Second round of changes. Splitted thread.c into thread.c, team.c and scheduler.c. First kernel-only get_team_info and get_next_team_info implementation.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@569 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
ebbcbbca01
commit
aded06e0aa
@ -345,6 +345,15 @@ thread_id find_thread(const char *);
|
||||
|
||||
status_t snooze(bigtime_t);
|
||||
|
||||
status_t _get_team_info(team_id id, team_info *info, size_t size);
|
||||
status_t _get_next_team_info(int32 *cookie, team_info *info, size_t size);
|
||||
|
||||
#define get_team_info(id, info) \
|
||||
_get_team_info((id), (info), sizeof(*(info)))
|
||||
|
||||
#define get_next_team_info(cookie, info) \
|
||||
_get_next_sem_info((cookie), (info), sizeof(*(info)))
|
||||
|
||||
/** @} */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -46,6 +46,14 @@ extern spinlock_t thread_spinlock;
|
||||
#define GRAB_THREAD_LOCK() acquire_spinlock(&thread_spinlock)
|
||||
#define RELEASE_THREAD_LOCK() release_spinlock(&thread_spinlock)
|
||||
|
||||
extern struct thread_queue dead_q;
|
||||
|
||||
extern spinlock_t team_spinlock;
|
||||
// NOTE: TEAM lock can be held over a THREAD lock acquisition,
|
||||
// but not the other way (to avoid deadlock)
|
||||
#define GRAB_TEAM_LOCK() acquire_spinlock(&team_spinlock)
|
||||
#define RELEASE_TEAM_LOCK() release_spinlock(&team_spinlock)
|
||||
|
||||
enum {
|
||||
THREAD_STATE_READY = 0, // ready to run
|
||||
THREAD_STATE_RUNNING, // running right now somewhere
|
||||
|
@ -12,6 +12,9 @@ extern "C" {
|
||||
#include <thread_types.h>
|
||||
#include <arch/thread.h>
|
||||
|
||||
void resched(void);
|
||||
void start_scheduler(void);
|
||||
|
||||
void thread_enqueue(struct thread *t, struct thread_queue *q);
|
||||
struct thread *thread_lookat_queue(struct thread_queue *q);
|
||||
struct thread *thread_dequeue(struct thread_queue *q);
|
||||
@ -25,9 +28,6 @@ void thread_atkernel_exit(void);
|
||||
int thread_suspend_thread(thread_id id);
|
||||
int thread_resume_thread(thread_id id);
|
||||
int thread_set_priority(thread_id id, int priority);
|
||||
void thread_resched(void);
|
||||
void thread_start_threading(void);
|
||||
void thread_snooze(bigtime_t time);
|
||||
int thread_init(kernel_args *ka);
|
||||
int thread_init_percpu(int cpu_num);
|
||||
void thread_exit(int retcode);
|
||||
@ -46,15 +46,19 @@ int thread_wait_on_thread(thread_id id, int *retcode);
|
||||
|
||||
thread_id thread_create_user_thread(char *name, team_id tid, addr entry, void *args);
|
||||
thread_id thread_create_kernel_thread(const char *name, int (*func)(void *args), void *args);
|
||||
thread_id thread_create_kernel_thread_etc(const char *name, int (*func)(void *), void *args, struct team *p);
|
||||
|
||||
int team_init(kernel_args *ka);
|
||||
struct team *team_get_kernel_team(void);
|
||||
team_id team_create_team(const char *path, const char *name, char **args, int argc, char **envp, int envc, int priority);
|
||||
int team_kill_team(team_id);
|
||||
int team_wait_on_team(team_id id, int *retcode);
|
||||
void team_remove_team_from_hash(struct team *team);
|
||||
team_id team_get_kernel_team_id(void);
|
||||
team_id team_get_current_team_id(void);
|
||||
char **user_team_get_arguments(void);
|
||||
int user_team_get_arg_count(void);
|
||||
struct team *team_get_team_struct_locked(team_id id);
|
||||
|
||||
// used in syscalls.c
|
||||
int user_thread_wait_on_thread(thread_id id, int *uretcode);
|
||||
@ -64,7 +68,10 @@ int user_team_wait_on_team(team_id id, int *uretcode);
|
||||
thread_id user_thread_create_user_thread(addr, team_id, const char*,
|
||||
int, void *);
|
||||
|
||||
int user_thread_snooze(bigtime_t time);
|
||||
status_t user_get_team_info(team_id id, team_info *info);
|
||||
status_t user_get_next_team_info(int32 *cookie, team_info *info);
|
||||
|
||||
|
||||
//int user_proc_get_table(struct proc_info *pi, size_t len);
|
||||
int user_getrlimit(int resource, struct rlimit * rlp);
|
||||
int user_setrlimit(int resource, const struct rlimit * rlp);
|
||||
|
@ -121,10 +121,12 @@ KernelLd kernel
|
||||
<$(SOURCE_GRIST)!core>pools.o
|
||||
<$(SOURCE_GRIST)!core>port.o
|
||||
<$(SOURCE_GRIST)!core>queue.o
|
||||
<$(SOURCE_GRIST)!core>scheduler.o
|
||||
<$(SOURCE_GRIST)!core>sem.o
|
||||
<$(SOURCE_GRIST)!core>smp.o
|
||||
<$(SOURCE_GRIST)!core>syscalls.o
|
||||
<$(SOURCE_GRIST)!core>sysctl.o
|
||||
<$(SOURCE_GRIST)!core>team.o
|
||||
<$(SOURCE_GRIST)!core>thread.o
|
||||
<$(SOURCE_GRIST)!core>timer.o
|
||||
|
||||
@ -165,10 +167,12 @@ KernelLd kernel.so
|
||||
<$(SOURCE_GRIST)!core>pools.o
|
||||
<$(SOURCE_GRIST)!core>port.o
|
||||
<$(SOURCE_GRIST)!core>queue.o
|
||||
<$(SOURCE_GRIST)!core>scheduler.o
|
||||
<$(SOURCE_GRIST)!core>sem.o
|
||||
<$(SOURCE_GRIST)!core>smp.o
|
||||
<$(SOURCE_GRIST)!core>syscalls.o
|
||||
<$(SOURCE_GRIST)!core>sysctl.o
|
||||
<$(SOURCE_GRIST)!core>team.o
|
||||
<$(SOURCE_GRIST)!core>thread.o
|
||||
<$(SOURCE_GRIST)!core>timer.o
|
||||
|
||||
|
@ -20,10 +20,12 @@ KernelObjects
|
||||
<$(SOURCE_GRIST)>pools.c
|
||||
<$(SOURCE_GRIST)>port.c
|
||||
<$(SOURCE_GRIST)>queue.c
|
||||
<$(SOURCE_GRIST)>scheduler.c
|
||||
<$(SOURCE_GRIST)>sem.c
|
||||
<$(SOURCE_GRIST)>smp.c
|
||||
<$(SOURCE_GRIST)>syscalls.c
|
||||
<$(SOURCE_GRIST)>sysctl.c
|
||||
<$(SOURCE_GRIST)>team.c
|
||||
<$(SOURCE_GRIST)>thread.c
|
||||
<$(SOURCE_GRIST)>timer.c
|
||||
:
|
||||
|
@ -245,7 +245,7 @@ void i386_handle_trap(struct int_frame frame)
|
||||
if (ret == B_INVOKE_SCHEDULER) {
|
||||
int state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
thread_resched();
|
||||
resched();
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
}
|
||||
|
@ -376,7 +376,7 @@ get_vnode(fs_id fsID, vnode_id vnodeID, struct vnode **_vnode, int reenter)
|
||||
if (vnode) {
|
||||
if (vnode->busy) {
|
||||
mutex_unlock(&vfs_vnode_mutex);
|
||||
thread_snooze(10000); // 10 ms
|
||||
snooze(10000); // 10 ms
|
||||
mutex_lock(&vfs_vnode_mutex);
|
||||
continue;
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ int _start(kernel_args *oldka, int cpu_num)
|
||||
vm_init_postsem(&ka);
|
||||
cbuf_init();
|
||||
vfs_init(&ka);
|
||||
team_init(&ka);
|
||||
thread_init(&ka);
|
||||
port_init(&ka);
|
||||
|
||||
@ -96,7 +97,7 @@ int _start(kernel_args *oldka, int cpu_num)
|
||||
|
||||
smp_wake_up_all_non_boot_cpus();
|
||||
smp_enable_ici(); // ici's were previously being ignored
|
||||
thread_start_threading();
|
||||
start_scheduler();
|
||||
} else {
|
||||
// this is run per cpu for each AP processor after they've been set loose
|
||||
thread_init_percpu(cpu_num);
|
||||
|
195
src/kernel/core/scheduler.c
Normal file
195
src/kernel/core/scheduler.c
Normal file
@ -0,0 +1,195 @@
|
||||
/* scheduler.c
|
||||
*
|
||||
* The scheduler code
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
#include <OS.h>
|
||||
#include <kernel.h>
|
||||
#include <thread.h>
|
||||
#include <thread_types.h>
|
||||
#include <timer.h>
|
||||
#include <int.h>
|
||||
#include <smp.h>
|
||||
#include <cpu.h>
|
||||
#include <khash.h>
|
||||
|
||||
static int _rand(void);
|
||||
|
||||
static int
|
||||
_rand(void)
|
||||
{
|
||||
static int next = 0;
|
||||
|
||||
if (next == 0)
|
||||
next = system_time();
|
||||
|
||||
next = next * 1103515245 + 12345;
|
||||
return((next >> 16) & 0x7FFF);
|
||||
}
|
||||
|
||||
|
||||
// this starts the scheduler. Must be run under the context of
|
||||
// the initial idle thread.
|
||||
void
|
||||
start_scheduler(void)
|
||||
{
|
||||
int state;
|
||||
|
||||
// XXX may not be the best place for this
|
||||
// invalidate all of the other processors' TLB caches
|
||||
state = disable_interrupts();
|
||||
arch_cpu_global_TLB_invalidate();
|
||||
smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVL_PAGE, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
|
||||
restore_interrupts(state);
|
||||
|
||||
// start the other processors
|
||||
smp_send_broadcast_ici(SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, SMP_MSG_FLAG_ASYNC);
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
resched();
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
context_switch(struct thread *t_from, struct thread *t_to)
|
||||
{
|
||||
bigtime_t now;
|
||||
|
||||
// track kernel time
|
||||
now = system_time();
|
||||
t_from->kernel_time += now - t_from->last_time;
|
||||
t_to->last_time = now;
|
||||
|
||||
t_to->cpu = t_from->cpu;
|
||||
arch_thread_set_current_thread(t_to);
|
||||
t_from->cpu = NULL;
|
||||
arch_thread_context_switch(t_from, t_to);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
reschedule_event(timer *unused)
|
||||
{
|
||||
// this function is called as a result of the timer event set by the scheduler
|
||||
// returning this causes a reschedule on the timer event
|
||||
thread_get_current_thread()->cpu->info.preempted= 1;
|
||||
return B_INVOKE_SCHEDULER;
|
||||
}
|
||||
|
||||
|
||||
// runs the scheduler.
|
||||
// NOTE: expects thread_spinlock to be held
|
||||
void
|
||||
resched(void)
|
||||
{
|
||||
struct thread *next_thread = NULL;
|
||||
int last_thread_pri = -1;
|
||||
struct thread *old_thread = thread_get_current_thread();
|
||||
int i;
|
||||
bigtime_t quantum;
|
||||
timer *quantum_timer;
|
||||
|
||||
// dprintf("top of thread_resched: cpu %d, cur_thread = 0x%x\n", smp_get_current_cpu(), thread_get_current_thread());
|
||||
|
||||
switch(old_thread->next_state) {
|
||||
case THREAD_STATE_RUNNING:
|
||||
case THREAD_STATE_READY:
|
||||
// dprintf("enqueueing thread 0x%x into run q. pri = %d\n", old_thread, old_thread->priority);
|
||||
thread_enqueue_run_q(old_thread);
|
||||
break;
|
||||
case THREAD_STATE_SUSPENDED:
|
||||
dprintf("suspending thread 0x%x\n", old_thread->id);
|
||||
break;
|
||||
case THREAD_STATE_FREE_ON_RESCHED:
|
||||
// This will hopefully be eliminated once the slab
|
||||
// allocator is done
|
||||
thread_enqueue(old_thread, &dead_q);
|
||||
break;
|
||||
default:
|
||||
// dprintf("not enqueueing thread 0x%x into run q. next_state = %d\n", old_thread, old_thread->next_state);
|
||||
;
|
||||
}
|
||||
old_thread->state = old_thread->next_state;
|
||||
|
||||
// search the real-time queue
|
||||
for(i = THREAD_MAX_RT_PRIORITY; i >= THREAD_MIN_RT_PRIORITY; i--) {
|
||||
next_thread = thread_dequeue_run_q(i);
|
||||
if(next_thread)
|
||||
goto found_thread;
|
||||
}
|
||||
|
||||
// search the regular queue
|
||||
for(i = THREAD_MAX_PRIORITY; i > THREAD_IDLE_PRIORITY; i--) {
|
||||
next_thread = thread_lookat_run_q(i);
|
||||
if(next_thread != NULL) {
|
||||
// skip it sometimes
|
||||
if(_rand() > 0x3000) {
|
||||
next_thread = thread_dequeue_run_q(i);
|
||||
goto found_thread;
|
||||
}
|
||||
last_thread_pri = i;
|
||||
next_thread = NULL;
|
||||
}
|
||||
}
|
||||
if(next_thread == NULL) {
|
||||
if(last_thread_pri != -1) {
|
||||
next_thread = thread_dequeue_run_q(last_thread_pri);
|
||||
if(next_thread == NULL)
|
||||
panic("next_thread == NULL! last_thread_pri = %d\n", last_thread_pri);
|
||||
} else {
|
||||
next_thread = thread_dequeue_run_q(THREAD_IDLE_PRIORITY);
|
||||
if(next_thread == NULL)
|
||||
panic("next_thread == NULL! no idle priorities!\n");
|
||||
}
|
||||
}
|
||||
|
||||
found_thread:
|
||||
next_thread->state = THREAD_STATE_RUNNING;
|
||||
next_thread->next_state = THREAD_STATE_READY;
|
||||
|
||||
if ((next_thread != old_thread) || (old_thread->cpu->info.preempted)) {
|
||||
// XXX calculate quantum
|
||||
quantum = 3000;
|
||||
quantum_timer = &old_thread->cpu->info.quantum_timer;
|
||||
if (!old_thread->cpu->info.preempted)
|
||||
_local_timer_cancel_event(old_thread->cpu->info.cpu_num, quantum_timer);
|
||||
old_thread->cpu->info.preempted = 0;
|
||||
add_timer(quantum_timer, &reschedule_event, quantum, B_ONE_SHOT_RELATIVE_TIMER);
|
||||
if (next_thread != old_thread)
|
||||
context_switch(old_thread, next_thread);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// XXX should only reset the quantum timer if we are switching to a new thread,
|
||||
// or we got here as a result of a quantum expire.
|
||||
|
||||
// XXX calculate quantum
|
||||
quantum = 10000;
|
||||
|
||||
// get the quantum timer for this cpu
|
||||
quantum_timer = &old_thread->cpu->info.quantum_timer;
|
||||
if(!old_thread->cpu->info.preempted) {
|
||||
_local_timer_cancel_event(old_thread->cpu->info.cpu_num, quantum_timer);
|
||||
}
|
||||
old_thread->cpu->info.preempted = 0;
|
||||
add_timer(quantum_timer, &reschedule_event, quantum, B_ONE_SHOT_RELATIVE_TIMER);
|
||||
|
||||
if(next_thread != old_thread) {
|
||||
// dprintf("thread_resched: cpu %d switching from thread %d to %d\n",
|
||||
// smp_get_current_cpu(), old_thread->id, next_thread->id);
|
||||
context_switch(old_thread, next_thread);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ int delete_sem_etc(sem_id id, int return_code)
|
||||
while ((t = thread_dequeue(&release_queue)) != NULL) {
|
||||
thread_enqueue_run_q(t);
|
||||
}
|
||||
thread_resched();
|
||||
resched();
|
||||
RELEASE_THREAD_LOCK();
|
||||
}
|
||||
|
||||
@ -415,7 +415,7 @@ int acquire_sem_etc(sem_id id, int count, int flags, bigtime_t timeout)
|
||||
}
|
||||
// fall through and reschedule since another thread with a higher priority may have been woken up
|
||||
}
|
||||
thread_resched();
|
||||
resched();
|
||||
RELEASE_THREAD_LOCK();
|
||||
|
||||
if ((flags & (B_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0) {
|
||||
@ -510,7 +510,7 @@ int release_sem_etc(sem_id id, int count, int flags)
|
||||
t->priority = priority;
|
||||
}
|
||||
if ((flags & B_DO_NOT_RESCHEDULE) == 0) {
|
||||
thread_resched();
|
||||
resched();
|
||||
}
|
||||
RELEASE_THREAD_LOCK();
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re
|
||||
*call_ret = system_time();
|
||||
break;
|
||||
case SYSCALL_SNOOZE:
|
||||
*call_ret = user_thread_snooze((bigtime_t)INT32TOINT64(arg0, arg1));
|
||||
*call_ret = snooze((bigtime_t)INT32TOINT64(arg0, arg1));
|
||||
break;
|
||||
case SYSCALL_SEM_CREATE:
|
||||
*call_ret = user_create_sem((int)arg0, (const char *)arg1);
|
||||
@ -283,9 +283,11 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re
|
||||
case SYSCALL_FDDUP2:
|
||||
*call_ret = user_dup2(arg0, arg1);
|
||||
break;
|
||||
/* obsolete; replaced by get_next_team_info
|
||||
case SYSCALL_GET_PROC_TABLE:
|
||||
*call_ret = user_team_get_table((struct team_info *)arg0, (size_t)arg1);
|
||||
break;
|
||||
*/
|
||||
case SYSCALL_GETRLIMIT:
|
||||
*call_ret = user_getrlimit((int)arg0, (struct rlimit *)arg1);
|
||||
break;
|
||||
|
929
src/kernel/core/team.c
Normal file
929
src/kernel/core/team.c
Normal file
@ -0,0 +1,929 @@
|
||||
/* team.c
|
||||
*
|
||||
* Team functions
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
#include <OS.h>
|
||||
#include <kernel.h>
|
||||
#include <thread.h>
|
||||
#include <thread_types.h>
|
||||
#include <int.h>
|
||||
#include <khash.h>
|
||||
#include <memheap.h>
|
||||
#include <user_runtime.h>
|
||||
#include <Errors.h>
|
||||
#include <kerrors.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <elf.h>
|
||||
#include <atomic.h>
|
||||
#include <syscalls.h>
|
||||
|
||||
|
||||
struct team_key {
|
||||
team_id id;
|
||||
};
|
||||
|
||||
struct team_arg {
|
||||
char *path;
|
||||
char **args;
|
||||
char **envp;
|
||||
unsigned int argc;
|
||||
unsigned int envc;
|
||||
};
|
||||
|
||||
// team list
|
||||
static void *team_hash = NULL;
|
||||
static team_id next_team_id = 0;
|
||||
static struct team *kernel_team = NULL;
|
||||
|
||||
spinlock_t team_spinlock = 0;
|
||||
|
||||
static struct team *create_team_struct(const char *name, bool kernel);
|
||||
static void delete_team_struct(struct team *p);
|
||||
static int team_struct_compare(void *_p, const void *_key);
|
||||
static unsigned int team_struct_hash(void *_p, const void *_key, unsigned int range);
|
||||
static void kfree_strings_array(char **strings, int strc);
|
||||
static int user_copy_strings_array(char **strings, int strc, char ***kstrings);
|
||||
static void _dump_team_info(struct team *p);
|
||||
static int dump_team_info(int argc, char **argv);
|
||||
|
||||
|
||||
static void _dump_team_info(struct team *p)
|
||||
{
|
||||
dprintf("TEAM: %p\n", p);
|
||||
dprintf("id: 0x%x\n", p->id);
|
||||
dprintf("name: '%s'\n", p->name);
|
||||
dprintf("next: %p\n", p->next);
|
||||
dprintf("num_threads: %d\n", p->num_threads);
|
||||
dprintf("state: %d\n", p->state);
|
||||
dprintf("pending_signals: 0x%x\n", p->pending_signals);
|
||||
dprintf("ioctx: %p\n", p->ioctx);
|
||||
dprintf("path: '%s'\n", p->path);
|
||||
dprintf("aspace_id: 0x%x\n", p->_aspace_id);
|
||||
dprintf("aspace: %p\n", p->aspace);
|
||||
dprintf("kaspace: %p\n", p->kaspace);
|
||||
dprintf("main_thread: %p\n", p->main_thread);
|
||||
dprintf("thread_list: %p\n", p->thread_list);
|
||||
}
|
||||
|
||||
static int dump_team_info(int argc, char **argv)
|
||||
{
|
||||
struct team *p;
|
||||
int id = -1;
|
||||
unsigned long num;
|
||||
struct hash_iterator i;
|
||||
|
||||
if(argc < 2) {
|
||||
dprintf("team: not enough arguments\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if the argument looks like a hex number, treat it as such
|
||||
if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') {
|
||||
num = atoul(argv[1]);
|
||||
if(num > vm_get_kernel_aspace()->virtual_map.base) {
|
||||
// XXX semi-hack
|
||||
_dump_team_info((struct team*)num);
|
||||
return 0;
|
||||
} else {
|
||||
id = num;
|
||||
}
|
||||
}
|
||||
|
||||
// walk through the thread list, trying to match name or id
|
||||
hash_open(team_hash, &i);
|
||||
while((p = hash_next(team_hash, &i)) != NULL) {
|
||||
if((p->name && strcmp(argv[1], p->name) == 0) || p->id == id) {
|
||||
_dump_team_info(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hash_close(team_hash, &i, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
team_init(kernel_args *ka)
|
||||
{
|
||||
// create the team hash table
|
||||
team_hash = hash_init(15, (addr)&kernel_team->next - (addr)kernel_team,
|
||||
&team_struct_compare, &team_struct_hash);
|
||||
|
||||
// create the kernel team
|
||||
kernel_team = create_team_struct("kernel_team", true);
|
||||
if(kernel_team == NULL)
|
||||
panic("could not create kernel team!\n");
|
||||
kernel_team->state = TEAM_STATE_NORMAL;
|
||||
|
||||
kernel_team->ioctx = vfs_new_io_context(NULL);
|
||||
if(kernel_team->ioctx == NULL)
|
||||
panic("could not create ioctx for kernel team!\n");
|
||||
|
||||
//XXX should initialize kernel_team->path here. Set it to "/"?
|
||||
|
||||
// stick it in the team hash
|
||||
hash_insert(team_hash, kernel_team);
|
||||
|
||||
add_debugger_command("team", &dump_team_info, "list info about a particular team");
|
||||
}
|
||||
|
||||
|
||||
// Frees an array of strings in kernel space
|
||||
// Parameters
|
||||
// strings strings array
|
||||
// strc number of strings in array
|
||||
static void kfree_strings_array(char **strings, int strc)
|
||||
{
|
||||
int cnt = strc;
|
||||
|
||||
if(strings != NULL) {
|
||||
for(cnt = 0; cnt < strc; cnt++){
|
||||
kfree(strings[cnt]);
|
||||
}
|
||||
kfree(strings);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy an array of strings from user space to kernel space
|
||||
// Parameters
|
||||
// strings userspace strings array
|
||||
// strc number of strings in array
|
||||
// kstrings pointer to the kernel copy
|
||||
// Returns < 0 on error and **kstrings = NULL
|
||||
static int user_copy_strings_array(char **strings, int strc, char ***kstrings)
|
||||
{
|
||||
char **lstrings;
|
||||
int err;
|
||||
int cnt;
|
||||
char *source;
|
||||
char buf[SYS_THREAD_STRING_LENGTH_MAX];
|
||||
|
||||
*kstrings = NULL;
|
||||
|
||||
if ((addr)strings >= KERNEL_BASE && (addr)strings <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
lstrings = (char **)kmalloc((strc + 1) * sizeof(char *));
|
||||
if (lstrings == NULL){
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
// scan all strings and copy to kernel space
|
||||
|
||||
for (cnt = 0; cnt < strc; cnt++) {
|
||||
err = user_memcpy(&source, &(strings[cnt]), sizeof(char *));
|
||||
if(err < 0)
|
||||
goto error;
|
||||
|
||||
if ((addr)source >= KERNEL_BASE && (addr)source <= KERNEL_TOP){
|
||||
err = ERR_VM_BAD_USER_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = user_strncpy(buf, source, SYS_THREAD_STRING_LENGTH_MAX - 1);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
buf[SYS_THREAD_STRING_LENGTH_MAX - 1] = 0;
|
||||
|
||||
lstrings[cnt] = (char *)kstrdup(buf);
|
||||
if (lstrings[cnt] == NULL){
|
||||
err = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
lstrings[strc] = NULL;
|
||||
|
||||
*kstrings = lstrings;
|
||||
return B_NO_ERROR;
|
||||
|
||||
error:
|
||||
kfree_strings_array(lstrings, cnt);
|
||||
dprintf("user_copy_strings_array failed %d \n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int user_team_wait_on_team(team_id id, int *uretcode)
|
||||
{
|
||||
int retcode;
|
||||
int rc, rc2;
|
||||
|
||||
if((addr)uretcode >= KERNEL_BASE && (addr)uretcode <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
rc = team_wait_on_team(id, &retcode);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
rc2 = user_memcpy(uretcode, &retcode, sizeof(int));
|
||||
if(rc2 < 0)
|
||||
return rc2;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int team_wait_on_team(team_id id, int *retcode)
|
||||
{
|
||||
struct team *p;
|
||||
thread_id tid;
|
||||
int state;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
p = team_get_team_struct_locked(id);
|
||||
if(p && p->main_thread) {
|
||||
tid = p->main_thread->id;
|
||||
} else {
|
||||
tid = ERR_INVALID_HANDLE;
|
||||
}
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
if(tid < 0)
|
||||
return tid;
|
||||
|
||||
return thread_wait_on_thread(tid, retcode);
|
||||
}
|
||||
|
||||
/*
|
||||
static struct team *team_get_team_struct(team_id id)
|
||||
{
|
||||
struct team *p;
|
||||
int state;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
|
||||
p = team_get_team_struct_locked(id);
|
||||
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
return p;
|
||||
}
|
||||
*/
|
||||
|
||||
struct team *team_get_team_struct_locked(team_id id)
|
||||
{
|
||||
struct team_key key;
|
||||
|
||||
key.id = id;
|
||||
|
||||
return hash_lookup(team_hash, &key);
|
||||
}
|
||||
|
||||
static int team_struct_compare(void *_p, const void *_key)
|
||||
{
|
||||
struct team *p = _p;
|
||||
const struct team_key *key = _key;
|
||||
|
||||
if(p->id == key->id) return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
static unsigned int team_struct_hash(void *_p, const void *_key, unsigned int range)
|
||||
{
|
||||
struct team *p = _p;
|
||||
const struct team_key *key = _key;
|
||||
|
||||
if(p != NULL)
|
||||
return (p->id % range);
|
||||
else
|
||||
return (key->id % range);
|
||||
}
|
||||
|
||||
void team_remove_team_from_hash(struct team *team)
|
||||
{
|
||||
hash_remove(team_hash, team);
|
||||
}
|
||||
|
||||
struct team *team_get_kernel_team(void)
|
||||
{
|
||||
return kernel_team;
|
||||
}
|
||||
|
||||
team_id team_get_kernel_team_id(void)
|
||||
{
|
||||
if(!kernel_team)
|
||||
return 0;
|
||||
else
|
||||
return kernel_team->id;
|
||||
}
|
||||
|
||||
team_id team_get_current_team_id(void)
|
||||
{
|
||||
return thread_get_current_thread()->team->id;
|
||||
}
|
||||
|
||||
static struct team *create_team_struct(const char *name, bool kernel)
|
||||
{
|
||||
struct team *p;
|
||||
|
||||
p = (struct team *)kmalloc(sizeof(struct team));
|
||||
if(p == NULL)
|
||||
goto error;
|
||||
p->id = atomic_add(&next_team_id, 1);
|
||||
strncpy(&p->name[0], name, SYS_MAX_OS_NAME_LEN-1);
|
||||
p->name[SYS_MAX_OS_NAME_LEN-1] = 0;
|
||||
p->num_threads = 0;
|
||||
p->ioctx = NULL;
|
||||
p->path[0] = 0;
|
||||
p->_aspace_id = -1;
|
||||
p->aspace = NULL;
|
||||
p->kaspace = vm_get_kernel_aspace();
|
||||
vm_put_aspace(p->kaspace);
|
||||
p->thread_list = NULL;
|
||||
p->main_thread = NULL;
|
||||
p->state = TEAM_STATE_BIRTH;
|
||||
p->pending_signals = SIG_NONE;
|
||||
p->death_sem = -1;
|
||||
p->user_env_base = NULL;
|
||||
|
||||
if(arch_team_init_team_struct(p, kernel) < 0)
|
||||
goto error1;
|
||||
|
||||
return p;
|
||||
|
||||
error1:
|
||||
kfree(p);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void delete_team_struct(struct team *p)
|
||||
{
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
|
||||
static int get_arguments_data_size(char **args,int argc)
|
||||
{
|
||||
int cnt;
|
||||
int tot_size = 0;
|
||||
|
||||
for(cnt = 0; cnt < argc; cnt++)
|
||||
tot_size += strlen(args[cnt]) + 1;
|
||||
tot_size += (argc + 1) * sizeof(char *);
|
||||
|
||||
return tot_size + sizeof(struct uspace_prog_args_t);
|
||||
}
|
||||
|
||||
static int team_create_team2(void *args)
|
||||
{
|
||||
int err;
|
||||
struct thread *t;
|
||||
struct team *p;
|
||||
struct team_arg *pargs = args;
|
||||
char *path;
|
||||
addr entry;
|
||||
char ustack_name[128];
|
||||
int tot_top_size;
|
||||
char **uargs;
|
||||
char **uenv;
|
||||
char *udest;
|
||||
struct uspace_prog_args_t *uspa;
|
||||
unsigned int arg_cnt;
|
||||
unsigned int env_cnt;
|
||||
|
||||
t = thread_get_current_thread();
|
||||
p = t->team;
|
||||
|
||||
dprintf("team_create_team2: entry thread %d\n", t->id);
|
||||
|
||||
// create an initial primary stack region
|
||||
|
||||
tot_top_size = STACK_SIZE + ENV_SIZE + PAGE_ALIGN(get_arguments_data_size(pargs->args, pargs->argc));
|
||||
t->user_stack_base = ((USER_STACK_REGION - tot_top_size) + USER_STACK_REGION_SIZE);
|
||||
sprintf(ustack_name, "%s_primary_stack", p->name);
|
||||
t->user_stack_region_id = vm_create_anonymous_region(p->_aspace_id, ustack_name, (void **)&t->user_stack_base,
|
||||
REGION_ADDR_EXACT_ADDRESS, tot_top_size, REGION_WIRING_LAZY, LOCK_RW);
|
||||
if(t->user_stack_region_id < 0) {
|
||||
panic("team_create_team2: could not create default user stack region\n");
|
||||
return t->user_stack_region_id;
|
||||
}
|
||||
|
||||
uspa = (struct uspace_prog_args_t *)(t->user_stack_base + STACK_SIZE + ENV_SIZE);
|
||||
uargs = (char **)(uspa + 1);
|
||||
udest = (char *)(uargs + pargs->argc + 1);
|
||||
// dprintf("addr: stack base=0x%x uargs = 0x%x udest=0x%x tot_top_size=%d \n\n",t->user_stack_base,uargs,udest,tot_top_size);
|
||||
|
||||
for(arg_cnt = 0; arg_cnt < pargs->argc; arg_cnt++) {
|
||||
uargs[arg_cnt] = udest;
|
||||
user_strcpy(udest, pargs->args[arg_cnt]);
|
||||
udest += (strlen(pargs->args[arg_cnt]) + 1);
|
||||
}
|
||||
uargs[arg_cnt] = NULL;
|
||||
|
||||
p->user_env_base = t->user_stack_base + STACK_SIZE;
|
||||
uenv = (char **)p->user_env_base;
|
||||
udest = (char *)p->user_env_base + ENV_SIZE - 1;
|
||||
// dprintf("team_create_team2: envc: %d, envp: 0x%p\n", pargs->envc, (void *)pargs->envp);
|
||||
for (env_cnt=0; env_cnt<pargs->envc; env_cnt++) {
|
||||
udest -= (strlen(pargs->envp[env_cnt]) + 1);
|
||||
uenv[env_cnt] = udest;
|
||||
user_strcpy(udest, pargs->envp[env_cnt]);
|
||||
}
|
||||
uenv[env_cnt] = NULL;
|
||||
|
||||
user_memcpy(uspa->prog_name, p->name, sizeof(uspa->prog_name));
|
||||
user_memcpy(uspa->prog_path, pargs->path, sizeof(uspa->prog_path));
|
||||
uspa->argc = arg_cnt;
|
||||
uspa->argv = uargs;
|
||||
uspa->envc = env_cnt;
|
||||
uspa->envp = uenv;
|
||||
|
||||
if (pargs->args != NULL)
|
||||
kfree_strings_array(pargs->args, pargs->argc);
|
||||
if (pargs->envp != NULL)
|
||||
kfree_strings_array(pargs->envp, pargs->envc);
|
||||
|
||||
path = pargs->path;
|
||||
dprintf("team_create_team2: loading elf binary '%s'\n", path);
|
||||
|
||||
err = elf_load_uspace("/boot/libexec/rld.so", p, 0, &entry);
|
||||
if(err < 0){
|
||||
// XXX clean up team
|
||||
return err;
|
||||
}
|
||||
|
||||
// free the args
|
||||
kfree(pargs->path);
|
||||
kfree(pargs);
|
||||
|
||||
dprintf("team_create_team2: loaded elf. entry = 0x%lx\n", entry);
|
||||
|
||||
p->state = TEAM_STATE_NORMAL;
|
||||
|
||||
// jump to the entry point in user space
|
||||
arch_thread_enter_uspace(entry, uspa, t->user_stack_base + STACK_SIZE);
|
||||
|
||||
// never gets here
|
||||
return 0;
|
||||
}
|
||||
|
||||
team_id team_create_team(const char *path, const char *name, char **args, int argc, char **envp, int envc, int priority)
|
||||
{
|
||||
struct team *p;
|
||||
thread_id tid;
|
||||
team_id pid;
|
||||
int err;
|
||||
unsigned int state;
|
||||
// int sem_retcode;
|
||||
struct team_arg *pargs;
|
||||
|
||||
dprintf("team_create_team: entry '%s', name '%s' args = %p argc = %d\n", path, name, args, argc);
|
||||
|
||||
p = create_team_struct(name, false);
|
||||
if(p == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
pid = p->id;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
hash_insert(team_hash, p);
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
// copy the args over
|
||||
pargs = (struct team_arg *)kmalloc(sizeof(struct team_arg));
|
||||
if(pargs == NULL){
|
||||
err = ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
pargs->path = (char *)kstrdup(path);
|
||||
if(pargs->path == NULL){
|
||||
err = ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
pargs->argc = argc;
|
||||
pargs->args = args;
|
||||
pargs->envp = envp;
|
||||
pargs->envc = envc;
|
||||
|
||||
// create a new ioctx for this team
|
||||
p->ioctx = vfs_new_io_context(thread_get_current_thread()->team->ioctx);
|
||||
if(!p->ioctx) {
|
||||
err = ENOMEM;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
//XXX should set p->path to path(?) here.
|
||||
|
||||
// create an address space for this team
|
||||
p->_aspace_id = vm_create_aspace(p->name, USER_BASE, USER_SIZE, false);
|
||||
if (p->_aspace_id < 0) {
|
||||
err = p->_aspace_id;
|
||||
goto err4;
|
||||
}
|
||||
p->aspace = vm_get_aspace_by_id(p->_aspace_id);
|
||||
|
||||
// create a kernel thread, but under the context of the new team
|
||||
tid = thread_create_kernel_thread_etc(name, team_create_team2, pargs, p);
|
||||
if (tid < 0) {
|
||||
err = tid;
|
||||
goto err5;
|
||||
}
|
||||
|
||||
thread_resume_thread(tid);
|
||||
|
||||
return pid;
|
||||
|
||||
err5:
|
||||
vm_put_aspace(p->aspace);
|
||||
vm_delete_aspace(p->_aspace_id);
|
||||
err4:
|
||||
vfs_free_io_context(p->ioctx);
|
||||
err3:
|
||||
kfree(pargs->path);
|
||||
err2:
|
||||
kfree(pargs);
|
||||
err1:
|
||||
// remove the team structure from the team hash table and delete the team structure
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
hash_remove(team_hash, p);
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
delete_team_struct(p);
|
||||
//err:
|
||||
return err;
|
||||
}
|
||||
|
||||
team_id user_team_create_team(const char *upath, const char *uname, char **args, int argc, char **envp, int envc, int priority)
|
||||
{
|
||||
char path[SYS_MAX_PATH_LEN];
|
||||
char name[SYS_MAX_OS_NAME_LEN];
|
||||
char **kargs;
|
||||
char **kenv;
|
||||
int rc;
|
||||
|
||||
dprintf("user_team_create_team : argc=%d \n",argc);
|
||||
|
||||
if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
if ((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
rc = user_copy_strings_array(args, argc, &kargs);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
|
||||
if (envp == NULL) {
|
||||
envp = (char **)thread_get_current_thread()->team->user_env_base;
|
||||
for (envc = 0; envp && (envp[envc]); envc++);
|
||||
}
|
||||
rc = user_copy_strings_array(envp, envc, &kenv);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
|
||||
rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
|
||||
path[SYS_MAX_PATH_LEN-1] = 0;
|
||||
|
||||
rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
|
||||
name[SYS_MAX_OS_NAME_LEN-1] = 0;
|
||||
|
||||
return team_create_team(path, name, kargs, argc, kenv, envc, priority);
|
||||
error:
|
||||
kfree_strings_array(kargs, argc);
|
||||
kfree_strings_array(kenv, envc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int team_kill_team(team_id id)
|
||||
{
|
||||
int state;
|
||||
struct team *p;
|
||||
// struct thread *t;
|
||||
thread_id tid = -1;
|
||||
int retval = 0;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
|
||||
p = team_get_team_struct_locked(id);
|
||||
if(p != NULL) {
|
||||
tid = p->main_thread->id;
|
||||
} else {
|
||||
retval = ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
if(retval < 0)
|
||||
return retval;
|
||||
|
||||
// just kill the main thread in the team. The cleanup code there will
|
||||
// take care of the team
|
||||
return thread_kill_thread(tid);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
user_get_team_info(team_id id, team_info *info)
|
||||
{
|
||||
team_info kinfo;
|
||||
status_t rc = B_OK;
|
||||
status_t rc2;
|
||||
|
||||
if ((addr)info >= KERNEL_BASE && (addr)info <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
rc = _get_team_info(id, &kinfo, sizeof(team_info));
|
||||
if (rc != B_OK)
|
||||
return rc;
|
||||
|
||||
rc2 = user_memcpy(info, &kinfo, sizeof(team_info));
|
||||
if (rc2 < 0)
|
||||
return rc2;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
_get_team_info(team_id id, team_info *info, size_t size)
|
||||
{
|
||||
int state;
|
||||
status_t rc = B_OK;
|
||||
struct team *team;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
|
||||
team = team_get_team_struct_locked(id);
|
||||
if (!team) {
|
||||
rc = B_BAD_TEAM_ID;
|
||||
goto err;
|
||||
}
|
||||
// XXX- Set more informations for team_info
|
||||
info->team = team->id;
|
||||
info->thread_count = team->num_threads;
|
||||
// XXX- make this to return real argc/argv
|
||||
strncpy(info->args, team->path, 64);
|
||||
info->args[63] = '\0';
|
||||
info->argc = 1;
|
||||
err:
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
user_get_next_team_info(int32 *cookie, team_info *info)
|
||||
{
|
||||
int32 kcookie;
|
||||
team_info kinfo;
|
||||
status_t rc = B_OK;
|
||||
status_t rc2;
|
||||
|
||||
if ((addr)cookie >= KERNEL_BASE && (addr)cookie <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
if ((addr)info >= KERNEL_BASE && (addr)info <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
rc2 = user_memcpy(&kcookie, cookie, sizeof(int32));
|
||||
if (rc2 < 0)
|
||||
return rc2;
|
||||
|
||||
rc = _get_next_team_info(&kcookie, &kinfo, sizeof(team_info));
|
||||
if (rc != B_OK)
|
||||
return rc;
|
||||
|
||||
rc2 = user_memcpy(cookie, &kcookie, sizeof(int32));
|
||||
if (rc2 < 0)
|
||||
return rc2;
|
||||
|
||||
rc2 = user_memcpy(info, &kinfo, sizeof(team_info));
|
||||
if (rc2 < 0)
|
||||
return rc2;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
_get_next_team_info(int32 *cookie, team_info *info, size_t size)
|
||||
{
|
||||
int state;
|
||||
int slot;
|
||||
status_t rc = B_BAD_TEAM_ID;
|
||||
struct team *team = NULL;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
|
||||
if (*cookie == 0)
|
||||
slot = 0;
|
||||
else {
|
||||
slot = *cookie;
|
||||
if (slot >= next_team_id)
|
||||
goto err;
|
||||
}
|
||||
while (!(team = team_get_team_struct_locked(slot)) && (slot < next_team_id))
|
||||
slot++;
|
||||
if (team) {
|
||||
// XXX- Set more informations for team_info
|
||||
info->team = team->id;
|
||||
info->thread_count = team->num_threads;
|
||||
// XXX- make this to return real argc/argv
|
||||
strncpy(info->args, team->path, 64);
|
||||
info->args[63] = '\0';
|
||||
info->argc = 1;
|
||||
slot++;
|
||||
*cookie = slot;
|
||||
rc = B_OK;
|
||||
}
|
||||
err:
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int user_setenv(const char *uname, const char *uvalue, int overwrite)
|
||||
{
|
||||
char name[SYS_THREAD_STRING_LENGTH_MAX];
|
||||
char value[SYS_THREAD_STRING_LENGTH_MAX];
|
||||
int rc;
|
||||
|
||||
if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
if((addr)uvalue >= KERNEL_BASE && (addr)uvalue <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
rc = user_strncpy(name, uname, SYS_THREAD_STRING_LENGTH_MAX-1);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
name[SYS_THREAD_STRING_LENGTH_MAX-1] = 0;
|
||||
|
||||
rc = user_strncpy(value, uvalue, SYS_THREAD_STRING_LENGTH_MAX-1);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
value[SYS_THREAD_STRING_LENGTH_MAX-1] = 0;
|
||||
|
||||
return sys_setenv(name, value, overwrite);
|
||||
}
|
||||
|
||||
int sys_setenv(const char *name, const char *value, int overwrite)
|
||||
{
|
||||
char var[SYS_THREAD_STRING_LENGTH_MAX];
|
||||
int state;
|
||||
addr env_space;
|
||||
char **envp;
|
||||
int envc;
|
||||
bool var_exists = false;
|
||||
int var_pos = 0;
|
||||
int name_size;
|
||||
int rc = 0;
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
dprintf("sys_setenv: entry (name=%s, value=%s)\n", name, value);
|
||||
|
||||
if (strlen(name) + strlen(value) + 1 >= SYS_THREAD_STRING_LENGTH_MAX)
|
||||
return -1;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
|
||||
strcpy(var, name);
|
||||
strncat(var, "=", SYS_THREAD_STRING_LENGTH_MAX-1);
|
||||
name_size = strlen(var);
|
||||
strncat(var, value, SYS_THREAD_STRING_LENGTH_MAX-1);
|
||||
|
||||
env_space = (addr)thread_get_current_thread()->team->user_env_base;
|
||||
envp = (char **)env_space;
|
||||
for (envc=0; envp[envc]; envc++) {
|
||||
if (!strncmp(envp[envc], var, name_size)) {
|
||||
var_exists = true;
|
||||
var_pos = envc;
|
||||
}
|
||||
}
|
||||
if (!var_exists)
|
||||
var_pos = envc;
|
||||
dprintf("sys_setenv: variable does%s exist\n", var_exists ? "" : " not");
|
||||
if ((!var_exists) || (var_exists && overwrite)) {
|
||||
|
||||
// XXX- make a better allocator
|
||||
if (var_exists) {
|
||||
if (strlen(var) <= strlen(envp[var_pos])) {
|
||||
strcpy(envp[var_pos], var);
|
||||
}
|
||||
else {
|
||||
for (p=(char *)env_space + ENV_SIZE - 1, i=0; envp[i]; i++)
|
||||
if (envp[i] < p)
|
||||
p = envp[i];
|
||||
p -= (strlen(var) + 1);
|
||||
if (p < (char *)env_space + (envc * sizeof(char *))) {
|
||||
rc = -1;
|
||||
}
|
||||
else {
|
||||
envp[var_pos] = p;
|
||||
strcpy(envp[var_pos], var);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (p=(char *)env_space + ENV_SIZE - 1, i=0; envp[i]; i++)
|
||||
if (envp[i] < p)
|
||||
p = envp[i];
|
||||
p -= (strlen(var) + 1);
|
||||
if (p < (char *)env_space + ((envc + 1) * sizeof(char *))) {
|
||||
rc = -1;
|
||||
}
|
||||
else {
|
||||
envp[envc] = p;
|
||||
strcpy(envp[envc], var);
|
||||
envp[envc + 1] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
dprintf("sys_setenv: variable set.\n");
|
||||
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int user_getenv(const char *uname, char **uvalue)
|
||||
{
|
||||
char name[SYS_THREAD_STRING_LENGTH_MAX];
|
||||
char *value;
|
||||
int rc;
|
||||
|
||||
if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
if((addr)uvalue >= KERNEL_BASE && (addr)uvalue <= KERNEL_TOP)
|
||||
return ERR_VM_BAD_USER_MEMORY;
|
||||
|
||||
rc = user_strncpy(name, uname, SYS_THREAD_STRING_LENGTH_MAX-1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
name[SYS_THREAD_STRING_LENGTH_MAX-1] = 0;
|
||||
|
||||
rc = sys_getenv(name, &value);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = user_memcpy(uvalue, &value, sizeof(char *));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_getenv(const char *name, char **value)
|
||||
{
|
||||
char **envp;
|
||||
char *p;
|
||||
int state;
|
||||
int i;
|
||||
int len = strlen(name);
|
||||
int rc = -1;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_TEAM_LOCK();
|
||||
|
||||
envp = (char **)thread_get_current_thread()->team->user_env_base;
|
||||
for (i=0; envp[i]; i++) {
|
||||
if (!strncmp(envp[i], name, len)) {
|
||||
p = envp[i] + len;
|
||||
if (*p == '=') {
|
||||
*value = (p + 1);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1633,7 +1633,7 @@ static int vm_thread_dump_max_commit(void *unused)
|
||||
(void)(unused);
|
||||
|
||||
for(;;) {
|
||||
thread_snooze(1000000);
|
||||
snooze(1000000);
|
||||
if(oldmax != max_commit)
|
||||
dprintf("max_commit 0x%x\n", max_commit);
|
||||
oldmax = max_commit;
|
||||
@ -1934,7 +1934,7 @@ static int vm_soft_fault(addr address, bool is_write, bool is_user)
|
||||
|
||||
// page must be busy
|
||||
mutex_unlock(&cache_ref->lock);
|
||||
thread_snooze(20000);
|
||||
snooze(20000);
|
||||
mutex_lock(&cache_ref->lock);
|
||||
}
|
||||
|
||||
@ -2040,7 +2040,7 @@ static int vm_soft_fault(addr address, bool is_write, bool is_user)
|
||||
// it couldn't map the second one, so sleep and retry
|
||||
// keeps an extremely rare deadlock from occuring
|
||||
(*aspace->translation_map.ops->put_physical_page)((addr)src);
|
||||
thread_snooze(5000);
|
||||
snooze(5000);
|
||||
}
|
||||
|
||||
memcpy(dest, src, PAGE_SIZE);
|
||||
|
@ -135,7 +135,7 @@ static int page_daemon()
|
||||
dprintf("page daemon starting\n");
|
||||
|
||||
for(;;) {
|
||||
thread_snooze(PAGE_DAEMON_INTERVAL);
|
||||
snooze(PAGE_DAEMON_INTERVAL);
|
||||
|
||||
// scan through all of the address spaces
|
||||
vm_aspace_walk_start(&i);
|
||||
|
@ -288,7 +288,7 @@ static int page_scrubber(void *unused)
|
||||
dprintf("page_scrubber starting...\n");
|
||||
|
||||
for(;;) {
|
||||
thread_snooze(100000); // 100ms
|
||||
snooze(100000); // 100ms
|
||||
|
||||
if(page_free_queue.count > 0) {
|
||||
state = disable_interrupts();
|
||||
|
Loading…
Reference in New Issue
Block a user