2002-10-30 02:07:06 +03:00
|
|
|
/* Team functions */
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
/*
|
2004-09-02 05:41:06 +04:00
|
|
|
** Copyright 2002-2004, The Haiku Team. All rights reserved.
|
|
|
|
** Distributed under the terms of the Haiku License.
|
2004-03-16 06:14:48 +03:00
|
|
|
**
|
2002-08-04 03:39:50 +04:00
|
|
|
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
|
|
|
** Distributed under the terms of the NewOS License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <OS.h>
|
2004-03-16 05:46:28 +03:00
|
|
|
|
|
|
|
#include <team.h>
|
2002-08-04 03:39:50 +04:00
|
|
|
#include <int.h>
|
|
|
|
#include <khash.h>
|
2004-03-16 05:46:28 +03:00
|
|
|
#include <port.h>
|
|
|
|
#include <sem.h>
|
2002-08-04 03:39:50 +04:00
|
|
|
#include <user_runtime.h>
|
2003-01-12 19:29:28 +03:00
|
|
|
#include <kimage.h>
|
2002-08-04 03:39:50 +04:00
|
|
|
#include <elf.h>
|
|
|
|
#include <syscalls.h>
|
2003-01-07 12:40:59 +03:00
|
|
|
#include <tls.h>
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-03-16 05:46:28 +03:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2004-03-16 06:14:48 +03:00
|
|
|
//#define TRACE_TEAM
|
|
|
|
#ifdef TRACE_TEAM
|
2003-11-12 18:37:44 +03:00
|
|
|
# define TRACE(x) dprintf x
|
|
|
|
#else
|
|
|
|
# define TRACE(x) ;
|
|
|
|
#endif
|
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
struct team_key {
|
|
|
|
team_id id;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct team_arg {
|
2004-10-07 19:34:17 +04:00
|
|
|
char *path;
|
|
|
|
uint32 arg_count;
|
|
|
|
char **args;
|
|
|
|
uint32 env_count;
|
|
|
|
char **env;
|
2002-08-04 03:39:50 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
// team list
|
|
|
|
static void *team_hash = NULL;
|
2002-08-05 00:10:06 +04:00
|
|
|
static team_id next_team_id = 1;
|
2002-08-04 03:39:50 +04:00
|
|
|
static struct team *kernel_team = NULL;
|
|
|
|
|
2002-10-26 20:13:36 +04:00
|
|
|
spinlock team_spinlock = 0;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
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);
|
2002-11-29 11:38:52 +03:00
|
|
|
static uint32 team_struct_hash(void *_p, const void *_key, uint32 range);
|
2004-10-07 19:34:17 +04:00
|
|
|
static void free_strings_array(char **strings, int32 count);
|
|
|
|
static status_t user_copy_strings_array(char * const *strings, int32 count, char ***_strings);
|
2002-08-04 03:39:50 +04:00
|
|
|
static void _dump_team_info(struct team *p);
|
|
|
|
static int dump_team_info(int argc, char **argv);
|
|
|
|
|
|
|
|
|
2002-09-24 03:24:12 +04:00
|
|
|
static void
|
|
|
|
_dump_team_info(struct team *p)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
dprintf("TEAM: %p\n", p);
|
2002-09-24 03:24:12 +04:00
|
|
|
dprintf("id: 0x%lx\n", p->id);
|
2002-08-04 03:39:50 +04:00
|
|
|
dprintf("name: '%s'\n", p->name);
|
|
|
|
dprintf("next: %p\n", p->next);
|
2004-03-16 05:46:28 +03:00
|
|
|
dprintf("parent: %p\n", p->parent);
|
|
|
|
dprintf("children: %p\n", p->children);
|
2002-08-04 03:39:50 +04:00
|
|
|
dprintf("num_threads: %d\n", p->num_threads);
|
|
|
|
dprintf("state: %d\n", p->state);
|
|
|
|
dprintf("pending_signals: 0x%x\n", p->pending_signals);
|
2002-12-03 17:17:53 +03:00
|
|
|
dprintf("io_context: %p\n", p->io_context);
|
|
|
|
// dprintf("path: '%s'\n", p->path);
|
2002-09-24 03:24:12 +04:00
|
|
|
dprintf("aspace_id: 0x%lx\n", p->_aspace_id);
|
2002-08-04 03:39:50 +04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2002-09-24 03:24:12 +04:00
|
|
|
|
|
|
|
static int
|
|
|
|
dump_team_info(int argc, char **argv)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
struct team *p;
|
|
|
|
int id = -1;
|
|
|
|
unsigned long num;
|
|
|
|
struct hash_iterator i;
|
|
|
|
|
2002-09-24 03:24:12 +04:00
|
|
|
if (argc < 2) {
|
2002-08-04 03:39:50 +04:00
|
|
|
dprintf("team: not enough arguments\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the argument looks like a hex number, treat it as such
|
2002-09-24 03:24:12 +04:00
|
|
|
if (strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') {
|
2004-05-21 14:17:08 +04:00
|
|
|
num = strtoul(argv[1], NULL, 16);
|
2002-09-24 03:24:12 +04:00
|
|
|
if (num > vm_get_kernel_aspace()->virtual_map.base) {
|
2002-08-04 03:39:50 +04:00
|
|
|
// 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);
|
2002-09-24 03:24:12 +04:00
|
|
|
while ((p = hash_next(team_hash, &i)) != NULL) {
|
|
|
|
if ((p->name && strcmp(argv[1], p->name) == 0) || p->id == id) {
|
2002-08-04 03:39:50 +04:00
|
|
|
_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);
|
2002-08-05 09:26:52 +04:00
|
|
|
if (kernel_team == NULL)
|
2002-08-04 03:39:50 +04:00
|
|
|
panic("could not create kernel team!\n");
|
|
|
|
kernel_team->state = TEAM_STATE_NORMAL;
|
|
|
|
|
2002-12-03 17:17:53 +03:00
|
|
|
kernel_team->io_context = vfs_new_io_context(NULL);
|
|
|
|
if (kernel_team->io_context == NULL)
|
|
|
|
panic("could not create io_context for kernel team!\n");
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
//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");
|
2002-08-05 09:26:52 +04:00
|
|
|
return 0;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
/** Frees an array of strings in kernel space.
|
|
|
|
*
|
|
|
|
* \param strings strings array
|
|
|
|
* \param count number of strings in array
|
2002-08-05 09:26:52 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
2004-10-07 19:34:17 +04:00
|
|
|
free_strings_array(char **strings, int32 count)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2004-10-07 19:34:17 +04:00
|
|
|
int32 i;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
if (strings == NULL)
|
|
|
|
return;
|
2004-05-11 23:52:38 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
free(strings[i]);
|
|
|
|
|
|
|
|
free(strings);
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
/** Copy an array of strings from user space to kernel space
|
2004-10-07 19:34:17 +04:00
|
|
|
*
|
|
|
|
* \param strings userspace strings array
|
|
|
|
* \param count number of strings in array
|
|
|
|
* \param kstrings pointer to the kernel copy
|
|
|
|
* \return \c B_OK on success, or an appropriate error code on
|
|
|
|
* failure.
|
2002-08-05 09:26:52 +04:00
|
|
|
*/
|
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
static status_t
|
|
|
|
user_copy_strings_array(char * const *userStrings, int32 count, char ***_strings)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2004-02-23 07:08:09 +03:00
|
|
|
char buffer[SYS_THREAD_STRING_LENGTH_MAX];
|
2004-10-07 19:34:17 +04:00
|
|
|
char **strings;
|
|
|
|
status_t err;
|
|
|
|
int32 i = 0;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-02-23 07:08:09 +03:00
|
|
|
if (!IS_USER_ADDRESS(userStrings))
|
|
|
|
return B_BAD_ADDRESS;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
strings = (char **)malloc((count + 1) * sizeof(char *));
|
|
|
|
if (strings == NULL)
|
2002-12-03 17:17:53 +03:00
|
|
|
return B_NO_MEMORY;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
if ((err = user_memcpy(strings, userStrings, count * sizeof(char *))) < B_OK)
|
|
|
|
goto error;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
// scan all strings and copy to kernel space
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
for (; i < count; i++) {
|
|
|
|
err = user_strlcpy(buffer, strings[i], SYS_THREAD_STRING_LENGTH_MAX);
|
|
|
|
if (err < B_OK)
|
2002-08-04 03:39:50 +04:00
|
|
|
goto error;
|
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
strings[i] = strdup(buffer);
|
|
|
|
if (strings[i] == NULL) {
|
|
|
|
err = B_NO_MEMORY;
|
2002-08-04 03:39:50 +04:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
strings[count] = NULL;
|
|
|
|
*_strings = strings;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
return B_OK;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
error:
|
2004-10-07 19:34:17 +04:00
|
|
|
free_strings_array(strings, i);
|
|
|
|
|
|
|
|
TRACE(("user_copy_strings_array failed %d \n", err));
|
2002-08-04 03:39:50 +04:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
2004-02-23 07:08:09 +03:00
|
|
|
/** Quick check to see if we have a valid team ID.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool
|
|
|
|
team_is_valid(team_id id)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2004-02-23 07:08:09 +03:00
|
|
|
struct team *team;
|
2002-08-04 03:39:50 +04:00
|
|
|
int state;
|
|
|
|
|
2004-02-23 07:08:09 +03:00
|
|
|
if (id <= 0)
|
|
|
|
return false;
|
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
|
|
|
|
2004-02-23 07:08:09 +03:00
|
|
|
team = team_get_team_struct_locked(id);
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
|
|
|
|
2004-02-23 07:08:09 +03:00
|
|
|
return team != NULL;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
2002-08-04 06:04:37 +04:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
struct team *
|
|
|
|
team_get_team_struct_locked(team_id id)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
struct team_key key;
|
|
|
|
|
|
|
|
key.id = id;
|
|
|
|
|
|
|
|
return hash_lookup(team_hash, &key);
|
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
static int
|
|
|
|
team_struct_compare(void *_p, const void *_key)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
struct team *p = _p;
|
|
|
|
const struct team_key *key = _key;
|
|
|
|
|
2002-11-29 11:38:52 +03:00
|
|
|
if (p->id == key->id)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
2002-11-29 11:38:52 +03:00
|
|
|
static uint32
|
|
|
|
team_struct_hash(void *_p, const void *_key, uint32 range)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
struct team *p = _p;
|
|
|
|
const struct team_key *key = _key;
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
if (p != NULL)
|
2002-11-29 11:38:52 +03:00
|
|
|
return p->id % range;
|
2002-08-05 09:26:52 +04:00
|
|
|
|
2002-11-29 11:38:52 +03:00
|
|
|
return key->id % range;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
2004-03-16 05:46:28 +03:00
|
|
|
static void
|
|
|
|
insert_team_into_parent(struct team *parent, struct team *team)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2004-03-16 05:46:28 +03:00
|
|
|
ASSERT(parent != NULL);
|
|
|
|
|
|
|
|
team->siblings_next = parent->children;
|
|
|
|
parent->children = team;
|
|
|
|
team->parent = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Note: must have TEAM lock held
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
remove_team_from_parent(struct team *parent, struct team *team)
|
|
|
|
{
|
|
|
|
struct team *child, *last = NULL;
|
|
|
|
|
|
|
|
for (child = parent->children; child != NULL; child = child->siblings_next) {
|
|
|
|
if (child == team) {
|
|
|
|
if (last == NULL)
|
|
|
|
parent->children = child->siblings_next;
|
|
|
|
else
|
|
|
|
last->siblings_next = child->siblings_next;
|
|
|
|
|
|
|
|
team->parent = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
last = child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Reparent each of our children
|
|
|
|
* Note: must have TEAM lock held
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
reparent_children(struct team *team)
|
|
|
|
{
|
|
|
|
struct team *child = team->children;
|
|
|
|
|
|
|
|
while (child != NULL) {
|
|
|
|
// remove the child from the current proc and add to the parent
|
|
|
|
remove_team_from_parent(team, child);
|
|
|
|
insert_team_into_parent(team->parent, child);
|
|
|
|
|
|
|
|
child = team->children;
|
|
|
|
}
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
struct team *
|
|
|
|
team_get_kernel_team(void)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
return kernel_team;
|
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
team_id
|
|
|
|
team_get_kernel_team_id(void)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2002-08-05 09:26:52 +04:00
|
|
|
if (!kernel_team)
|
2002-08-04 03:39:50 +04:00
|
|
|
return 0;
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
return kernel_team->id;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
team_id
|
|
|
|
team_get_current_team_id(void)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
return thread_get_current_thread()->team->id;
|
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
static struct team *
|
|
|
|
create_team_struct(const char *name, bool kernel)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2004-02-23 07:08:09 +03:00
|
|
|
struct team *team = (struct team *)malloc(sizeof(struct team));
|
2003-01-06 11:10:54 +03:00
|
|
|
if (team == NULL)
|
2004-02-23 07:08:09 +03:00
|
|
|
return NULL;
|
2002-08-05 09:26:52 +04:00
|
|
|
|
2004-02-23 07:08:09 +03:00
|
|
|
team->next = team->siblings_next = team->children = team->parent = NULL;
|
2003-01-06 11:10:54 +03:00
|
|
|
team->id = atomic_add(&next_team_id, 1);
|
2004-02-23 07:08:09 +03:00
|
|
|
strlcpy(team->name, name, B_OS_NAME_LENGTH);
|
2003-01-06 11:10:54 +03:00
|
|
|
team->num_threads = 0;
|
|
|
|
team->io_context = NULL;
|
|
|
|
team->_aspace_id = -1;
|
|
|
|
team->aspace = NULL;
|
|
|
|
team->kaspace = vm_get_kernel_aspace();
|
|
|
|
vm_put_aspace(team->kaspace);
|
|
|
|
team->thread_list = NULL;
|
|
|
|
team->main_thread = NULL;
|
|
|
|
team->state = TEAM_STATE_BIRTH;
|
|
|
|
team->pending_signals = 0;
|
|
|
|
team->death_sem = -1;
|
|
|
|
team->user_env_base = 0;
|
2003-01-27 02:31:38 +03:00
|
|
|
list_init(&team->image_list);
|
2003-01-06 11:10:54 +03:00
|
|
|
|
|
|
|
if (arch_team_init_team_struct(team, kernel) < 0)
|
2004-02-23 07:08:09 +03:00
|
|
|
goto error;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2003-01-06 11:10:54 +03:00
|
|
|
return team;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
error:
|
2004-02-23 07:08:09 +03:00
|
|
|
free(team);
|
2002-08-04 03:39:50 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
static void
|
2003-01-06 11:10:54 +03:00
|
|
|
delete_team_struct(struct team *team)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2003-01-06 11:10:54 +03:00
|
|
|
free(team);
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-16 05:46:28 +03:00
|
|
|
void
|
|
|
|
team_remove_team(struct team *team)
|
|
|
|
{
|
|
|
|
hash_remove(team_hash, team);
|
|
|
|
team->state = TEAM_STATE_DEATH;
|
|
|
|
|
|
|
|
// reparent each of the team's children
|
|
|
|
reparent_children(team);
|
|
|
|
|
|
|
|
// remove us from our parent
|
|
|
|
remove_team_from_parent(team->parent, team);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
team_delete_team(struct team *team)
|
|
|
|
{
|
|
|
|
if (team->num_threads > 0) {
|
|
|
|
// there are other threads still in this team,
|
|
|
|
// cycle through and signal kill on each of the threads
|
|
|
|
// XXX this can be optimized. There's got to be a better solution.
|
|
|
|
cpu_status state;
|
|
|
|
struct thread *temp_thread;
|
|
|
|
char death_sem_name[B_OS_NAME_LENGTH];
|
|
|
|
|
|
|
|
sprintf(death_sem_name, "team %ld death sem", team->id);
|
|
|
|
team->death_sem = create_sem(0, death_sem_name);
|
|
|
|
if (team->death_sem < 0)
|
|
|
|
panic("thread_exit: cannot init death sem for team %ld\n", team->id);
|
|
|
|
|
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
|
|
|
// we can safely walk the list because of the lock. no new threads can be created
|
|
|
|
// because of the TEAM_STATE_DEATH flag on the team
|
|
|
|
temp_thread = team->thread_list;
|
|
|
|
while (temp_thread) {
|
|
|
|
struct thread *next = temp_thread->team_next;
|
2004-03-17 18:25:43 +03:00
|
|
|
|
|
|
|
send_signal_etc(temp_thread->id, SIGKILLTHR, B_DO_NOT_RESCHEDULE);
|
2004-03-16 05:46:28 +03:00
|
|
|
temp_thread = next;
|
|
|
|
}
|
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
|
|
|
|
|
|
|
// wait until all threads in team are dead.
|
|
|
|
acquire_sem_etc(team->death_sem, team->num_threads, 0, 0);
|
|
|
|
delete_sem(team->death_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
// free team resources
|
|
|
|
vm_put_aspace(team->aspace);
|
|
|
|
vm_delete_aspace(team->_aspace_id);
|
|
|
|
delete_owned_ports(team->id);
|
|
|
|
sem_delete_owned_sems(team->id);
|
|
|
|
remove_images(team);
|
|
|
|
vfs_free_io_context(team->io_context);
|
|
|
|
|
|
|
|
free(team);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
static int
|
2003-01-12 19:29:28 +03:00
|
|
|
get_arguments_data_size(char **args, int argc)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2003-09-09 06:36:52 +04:00
|
|
|
uint32 size = 0;
|
|
|
|
int count;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2003-01-12 19:29:28 +03:00
|
|
|
for (count = 0; count < argc; count++)
|
|
|
|
size += strlen(args[count]) + 1;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2003-01-12 19:29:28 +03:00
|
|
|
return size + (argc + 1) * sizeof(char *) + sizeof(struct uspace_program_args);
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
static void
|
|
|
|
free_team_arg(struct team_arg *teamArg)
|
|
|
|
{
|
|
|
|
free(teamArg->path);
|
|
|
|
free(teamArg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct team_arg *
|
|
|
|
create_team_arg(const char *path, int32 argc, char **args, int32 envCount, char **env)
|
|
|
|
{
|
|
|
|
struct team_arg *teamArg = (struct team_arg *)malloc(sizeof(struct team_arg));
|
|
|
|
if (teamArg == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
teamArg->path = strdup(path);
|
|
|
|
if (teamArg->path == NULL) {
|
|
|
|
free(teamArg);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
teamArg->arg_count = argc;
|
|
|
|
teamArg->args = args;
|
|
|
|
teamArg->env_count = envCount;
|
|
|
|
teamArg->env = env;
|
|
|
|
|
|
|
|
return teamArg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-27 06:09:33 +03:00
|
|
|
static int32
|
2002-08-05 09:26:52 +04:00
|
|
|
team_create_team2(void *args)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct thread *t;
|
2003-01-07 12:40:59 +03:00
|
|
|
struct team *team;
|
2003-01-12 19:29:28 +03:00
|
|
|
struct team_arg *teamArgs = args;
|
2002-08-04 03:39:50 +04:00
|
|
|
char *path;
|
|
|
|
addr entry;
|
|
|
|
char ustack_name[128];
|
2004-10-07 19:34:17 +04:00
|
|
|
uint32 sizeLeft;
|
2002-08-04 03:39:50 +04:00
|
|
|
char **uargs;
|
|
|
|
char **uenv;
|
|
|
|
char *udest;
|
2003-01-12 19:29:28 +03:00
|
|
|
struct uspace_program_args *uspa;
|
2004-10-07 19:34:17 +04:00
|
|
|
uint32 argCount, envCount, i;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
t = thread_get_current_thread();
|
2003-01-07 12:40:59 +03:00
|
|
|
team = t->team;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-03-16 06:14:48 +03:00
|
|
|
TRACE(("team_create_team2: entry thread %ld\n", t->id));
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
// create an initial primary stack region
|
|
|
|
|
2004-10-05 02:41:34 +04:00
|
|
|
// ToDo: make ENV_SIZE variable and put it on the heap?
|
2004-06-10 05:43:16 +04:00
|
|
|
// ToDo: we could reserve the whole USER_STACK_REGION upfront...
|
2003-01-07 12:40:59 +03:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
sizeLeft = PAGE_ALIGN(MAIN_THREAD_STACK_SIZE + TLS_SIZE + ENV_SIZE +
|
|
|
|
get_arguments_data_size(teamArgs->args, teamArgs->arg_count));
|
|
|
|
t->user_stack_base = USER_STACK_REGION + USER_STACK_REGION_SIZE - sizeLeft;
|
2004-10-05 02:41:34 +04:00
|
|
|
t->user_stack_size = MAIN_THREAD_STACK_SIZE;
|
2003-01-07 12:40:59 +03:00
|
|
|
// the exact location at the end of the user stack region
|
|
|
|
|
2004-06-09 01:35:14 +04:00
|
|
|
sprintf(ustack_name, "%s_main_stack", team->name);
|
2003-08-19 21:38:13 +04:00
|
|
|
t->user_stack_region_id = create_area_etc(team, ustack_name, (void **)&t->user_stack_base,
|
2004-10-07 19:34:17 +04:00
|
|
|
B_EXACT_ADDRESS, sizeLeft, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
2002-09-24 03:24:12 +04:00
|
|
|
if (t->user_stack_region_id < 0) {
|
2004-06-10 05:43:16 +04:00
|
|
|
dprintf("team_create_team2: could not create default user stack region\n");
|
2002-08-04 03:39:50 +04:00
|
|
|
return t->user_stack_region_id;
|
|
|
|
}
|
|
|
|
|
2003-01-07 12:40:59 +03:00
|
|
|
// now that the TLS area is allocated, initialize TLS
|
|
|
|
arch_thread_init_tls(t);
|
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
argCount = teamArgs->arg_count;
|
|
|
|
envCount = teamArgs->env_count;
|
|
|
|
|
2003-01-12 19:29:28 +03:00
|
|
|
uspa = (struct uspace_program_args *)(t->user_stack_base + STACK_SIZE + TLS_SIZE + ENV_SIZE);
|
2002-08-04 03:39:50 +04:00
|
|
|
uargs = (char **)(uspa + 1);
|
2004-10-07 19:34:17 +04:00
|
|
|
udest = (char *)(uargs + argCount + 1);
|
2004-03-16 06:14:48 +03:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
TRACE(("addr: stack base = 0x%lx, uargs = %p, udest = %p, sizeLeft = %lu\n",
|
|
|
|
t->user_stack_base, uargs, udest, sizeLeft));
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
for (i = 0; i < argCount; i++) {
|
|
|
|
ssize_t length = user_strlcpy(udest, teamArgs->args[i], sizeLeft) + 1;
|
|
|
|
|
|
|
|
uargs[i] = udest;
|
|
|
|
udest += length;
|
|
|
|
sizeLeft -= length;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
2004-10-07 19:34:17 +04:00
|
|
|
uargs[argCount] = NULL;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-10-05 02:41:34 +04:00
|
|
|
team->user_env_base = t->user_stack_base + t->user_stack_size + TLS_SIZE;
|
2004-05-11 23:52:38 +04:00
|
|
|
uenv = (char **)team->user_env_base;
|
2003-01-07 12:40:59 +03:00
|
|
|
udest = (char *)team->user_env_base + ENV_SIZE - 1;
|
2004-03-16 06:14:48 +03:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
TRACE(("team_create_team2: envc: %d, envp: 0x%p\n", teamArgs->env_count, (void *)teamArgs->env));
|
|
|
|
|
|
|
|
for (i = 0; i < envCount; i++) {
|
|
|
|
ssize_t length = user_strlcpy(udest, teamArgs->env[i], sizeLeft) + 1;
|
2004-03-16 06:14:48 +03:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
uenv[i] = udest;
|
|
|
|
udest += length;
|
|
|
|
sizeLeft -= length;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
2004-10-07 19:34:17 +04:00
|
|
|
uenv[envCount] = NULL;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2003-01-12 19:29:28 +03:00
|
|
|
user_memcpy(uspa->program_name, team->name, sizeof(uspa->program_name));
|
|
|
|
user_memcpy(uspa->program_path, teamArgs->path, sizeof(uspa->program_path));
|
2004-10-07 19:34:17 +04:00
|
|
|
uspa->argc = argCount;
|
2002-08-04 03:39:50 +04:00
|
|
|
uspa->argv = uargs;
|
2004-10-07 19:34:17 +04:00
|
|
|
uspa->envc = envCount;
|
2002-08-04 03:39:50 +04:00
|
|
|
uspa->envp = uenv;
|
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
free_strings_array(teamArgs->args, teamArgs->arg_count);
|
|
|
|
free_strings_array(teamArgs->env, teamArgs->env_count);
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2003-01-12 19:29:28 +03:00
|
|
|
path = teamArgs->path;
|
2004-03-16 06:14:48 +03:00
|
|
|
TRACE(("team_create_team2: loading elf binary '%s'\n", path));
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-06-10 05:43:16 +04:00
|
|
|
// ToDo: don't use fixed paths!
|
2004-06-09 01:35:14 +04:00
|
|
|
err = elf_load_user_image("/boot/beos/system/lib/rld.so", team, 0, &entry);
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
// free the args
|
2004-10-07 19:34:17 +04:00
|
|
|
free_team_arg(teamArgs);
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-06-10 05:43:16 +04:00
|
|
|
if (err < 0) {
|
|
|
|
// Luckily, we don't have to clean up the mess we created - that's
|
|
|
|
// done for us by the normal team deletion process
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2004-03-16 06:14:48 +03:00
|
|
|
TRACE(("team_create_team2: loaded elf. entry = 0x%lx\n", entry));
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2003-01-07 12:40:59 +03:00
|
|
|
team->state = TEAM_STATE_NORMAL;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
// jump to the entry point in user space
|
2003-04-18 13:38:28 +04:00
|
|
|
arch_thread_enter_uspace(t, entry, uspa, NULL);
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
// never gets here
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
team_id
|
2004-10-07 19:34:17 +04:00
|
|
|
team_create_team(const char *path, const char *name, char **args, int argc, char **env, int envCount, int priority)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2004-03-16 05:46:28 +03:00
|
|
|
struct team *team, *parent;
|
2004-06-11 05:36:29 +04:00
|
|
|
const char *threadName;
|
2002-08-04 03:39:50 +04:00
|
|
|
thread_id tid;
|
|
|
|
team_id pid;
|
|
|
|
int err;
|
2004-06-11 05:36:29 +04:00
|
|
|
cpu_status state;
|
2003-01-12 19:29:28 +03:00
|
|
|
struct team_arg *teamArgs;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-03-16 06:14:48 +03:00
|
|
|
TRACE(("team_create_team: entry '%s', name '%s' args = %p argc = %d\n",
|
|
|
|
path, name, args, argc));
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2003-01-07 12:40:59 +03:00
|
|
|
team = create_team_struct(name, false);
|
|
|
|
if (team == NULL)
|
2004-03-16 05:46:28 +03:00
|
|
|
return B_NO_MEMORY;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2003-01-07 12:40:59 +03:00
|
|
|
pid = team->id;
|
2004-03-16 05:46:28 +03:00
|
|
|
parent = thread_get_current_thread()->team;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
2004-03-16 05:46:28 +03:00
|
|
|
|
2003-01-07 12:40:59 +03:00
|
|
|
hash_insert(team_hash, team);
|
2004-03-16 05:46:28 +03:00
|
|
|
insert_team_into_parent(parent, team);
|
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
|
|
|
|
|
|
|
// copy the args over
|
2004-10-07 19:34:17 +04:00
|
|
|
teamArgs = create_team_arg(path, argc, args, envCount, env);
|
|
|
|
if (teamArgs == NULL) {
|
2004-03-16 05:46:28 +03:00
|
|
|
err = B_NO_MEMORY;
|
2002-08-04 03:39:50 +04:00
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
2002-12-03 17:17:53 +03:00
|
|
|
// create a new io_context for this team
|
2003-01-07 12:40:59 +03:00
|
|
|
team->io_context = vfs_new_io_context(thread_get_current_thread()->team->io_context);
|
|
|
|
if (!team->io_context) {
|
2004-06-11 05:36:29 +04:00
|
|
|
err = B_NO_MEMORY;
|
2004-10-07 19:34:17 +04:00
|
|
|
goto err2;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// create an address space for this team
|
2003-01-07 12:40:59 +03:00
|
|
|
team->_aspace_id = vm_create_aspace(team->name, USER_BASE, USER_SIZE, false);
|
|
|
|
if (team->_aspace_id < 0) {
|
|
|
|
err = team->_aspace_id;
|
2004-10-07 19:34:17 +04:00
|
|
|
goto err3;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
2003-01-07 12:40:59 +03:00
|
|
|
team->aspace = vm_get_aspace_by_id(team->_aspace_id);
|
2002-08-04 03:39:50 +04:00
|
|
|
|
2004-06-11 05:36:29 +04:00
|
|
|
// cut the path from the main thread name
|
|
|
|
threadName = strrchr(name, '/');
|
|
|
|
if (threadName != NULL)
|
|
|
|
threadName++;
|
|
|
|
else
|
|
|
|
threadName = name;
|
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
// create a kernel thread, but under the context of the new team
|
2004-06-11 05:36:29 +04:00
|
|
|
tid = spawn_kernel_thread_etc(team_create_team2, threadName, B_NORMAL_PRIORITY, teamArgs, team->id);
|
2002-08-04 03:39:50 +04:00
|
|
|
if (tid < 0) {
|
|
|
|
err = tid;
|
2004-10-07 19:34:17 +04:00
|
|
|
goto err4;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
2003-01-27 06:09:33 +03:00
|
|
|
resume_thread(tid);
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
return pid;
|
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
err4:
|
2003-01-07 12:40:59 +03:00
|
|
|
vm_put_aspace(team->aspace);
|
|
|
|
vm_delete_aspace(team->_aspace_id);
|
2002-08-04 03:39:50 +04:00
|
|
|
err3:
|
2004-10-07 19:34:17 +04:00
|
|
|
vfs_free_io_context(team->io_context);
|
2002-08-04 03:39:50 +04:00
|
|
|
err2:
|
2004-10-07 19:34:17 +04:00
|
|
|
free_team_arg(teamArgs);
|
2002-08-04 03:39:50 +04:00
|
|
|
err1:
|
|
|
|
// remove the team structure from the team hash table and delete the team structure
|
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
2004-03-16 05:46:28 +03:00
|
|
|
|
|
|
|
remove_team_from_parent(parent, team);
|
2003-01-07 12:40:59 +03:00
|
|
|
hash_remove(team_hash, team);
|
2004-03-16 05:46:28 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
2003-01-07 12:40:59 +03:00
|
|
|
delete_team_struct(team);
|
2004-10-07 19:34:17 +04:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
static status_t
|
|
|
|
exec_team(const char *path, int32 argCount, char **args, int32 envCount, char **env)
|
|
|
|
{
|
|
|
|
struct team *team = thread_get_current_thread()->team;
|
|
|
|
struct team_arg *teamArgs;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld\n", path, argCount, envCount));
|
|
|
|
|
|
|
|
// switching the kernel at run time is probably not a good idea :)
|
|
|
|
if (team == team_get_kernel_team())
|
|
|
|
return B_NOT_ALLOWED;
|
|
|
|
|
|
|
|
// we currently need to be single threaded here
|
|
|
|
// ToDo: maybe we should just kill all other threads and
|
|
|
|
// make the current thread the team's main thread?
|
|
|
|
if (team->main_thread != thread_get_current_thread()
|
|
|
|
|| team->main_thread != team->thread_list
|
|
|
|
|| team->main_thread->team_next != NULL)
|
|
|
|
return B_NOT_ALLOWED;
|
|
|
|
|
|
|
|
// ToDo: maybe we should make sure upfront that the target path is an app?
|
|
|
|
|
|
|
|
teamArgs = create_team_arg(path, argCount, args, envCount, env);
|
|
|
|
if (teamArgs == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
// ToDo: remove team resources if there are any left
|
|
|
|
|
|
|
|
vm_delete_areas(team->aspace);
|
|
|
|
delete_owned_ports(team->id);
|
|
|
|
sem_delete_owned_sems(team->id);
|
|
|
|
remove_images(team);
|
|
|
|
vfs_exec_io_context(team->io_context);
|
|
|
|
|
|
|
|
status = team_create_team2(teamArgs);
|
|
|
|
// this one usually doesn't return...
|
|
|
|
|
|
|
|
// sorry, we have to kill us, there is no way out anymore (without any areas left and all that)
|
|
|
|
exit_thread(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-09-02 05:41:06 +04:00
|
|
|
/** This is the kernel backend for waitpid(). It is a bit more powerful when it comes
|
|
|
|
* to the reason why a thread has died than waitpid() can be.
|
|
|
|
*/
|
|
|
|
|
2004-09-15 19:45:37 +04:00
|
|
|
|
|
|
|
static thread_id
|
|
|
|
wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnCode)
|
2004-09-02 05:41:06 +04:00
|
|
|
{
|
|
|
|
// ToDo: implement me! We need to store the death of children in the team structure!
|
|
|
|
|
2004-09-15 19:45:37 +04:00
|
|
|
dprintf("wait_for_child(child = %ld, flags = %lu) is not yet implemented\n", child, flags);
|
|
|
|
|
2004-09-02 05:41:06 +04:00
|
|
|
if (child > 0) {
|
|
|
|
// wait for the specified child
|
|
|
|
} else if (child == -1) {
|
|
|
|
// wait for any children of this team to die
|
|
|
|
} else if (child == 0) {
|
|
|
|
// wait for any children of this process group to die
|
|
|
|
} else {
|
|
|
|
// wait for any children with progress group of the absolute value of "child"
|
|
|
|
}
|
|
|
|
|
|
|
|
return B_ERROR;
|
|
|
|
}
|
2004-09-15 19:45:37 +04:00
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
// public team API
|
2004-09-02 05:41:06 +04:00
|
|
|
|
|
|
|
|
2004-03-03 03:57:00 +03:00
|
|
|
status_t
|
|
|
|
wait_for_team(team_id id, status_t *_returnCode)
|
|
|
|
{
|
|
|
|
struct team *team;
|
|
|
|
thread_id thread;
|
|
|
|
cpu_status state;
|
|
|
|
|
|
|
|
// find main thread and wait for that
|
|
|
|
|
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
|
|
|
|
|
|
|
team = team_get_team_struct_locked(id);
|
|
|
|
if (team && team->main_thread)
|
|
|
|
thread = team->main_thread->id;
|
|
|
|
else
|
|
|
|
thread = B_BAD_THREAD_ID;
|
|
|
|
|
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
|
|
|
|
|
|
|
if (thread < 0)
|
|
|
|
return thread;
|
|
|
|
|
|
|
|
return wait_for_thread(thread, _returnCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
kill_team(team_id id)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
int state;
|
2003-01-07 12:40:59 +03:00
|
|
|
struct team *team;
|
2002-08-04 03:39:50 +04:00
|
|
|
// struct thread *t;
|
|
|
|
thread_id tid = -1;
|
|
|
|
int retval = 0;
|
|
|
|
|
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
|
|
|
|
2003-01-07 12:40:59 +03:00
|
|
|
team = team_get_team_struct_locked(id);
|
|
|
|
if (team != NULL)
|
|
|
|
tid = team->main_thread->id;
|
|
|
|
else
|
2004-02-23 07:12:34 +03:00
|
|
|
retval = B_BAD_THREAD_ID;
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
2003-01-07 12:40:59 +03:00
|
|
|
|
|
|
|
if (retval < 0)
|
2002-08-04 03:39:50 +04:00
|
|
|
return retval;
|
|
|
|
|
|
|
|
// just kill the main thread in the team. The cleanup code there will
|
|
|
|
// take care of the team
|
2004-03-03 03:57:00 +03:00
|
|
|
return kill_thread(tid);
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-12 19:29:28 +03:00
|
|
|
/** Fills the team_info structure with information from the specified
|
|
|
|
* team.
|
2004-02-23 07:08:09 +03:00
|
|
|
* The team lock must be held when called.
|
2003-01-12 19:29:28 +03:00
|
|
|
*/
|
|
|
|
|
2002-12-03 17:17:53 +03:00
|
|
|
static status_t
|
|
|
|
fill_team_info(struct team *team, team_info *info, size_t size)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
2002-12-03 17:17:53 +03:00
|
|
|
if (size != sizeof(team_info))
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
// ToDo: Set more informations for team_info
|
|
|
|
memset(info, 0, size);
|
|
|
|
|
|
|
|
info->team = team->id;
|
|
|
|
info->thread_count = team->num_threads;
|
2003-01-12 19:29:28 +03:00
|
|
|
info->image_count = count_images(team);
|
2002-12-03 17:17:53 +03:00
|
|
|
//info->area_count =
|
|
|
|
//info->debugger_nub_thread =
|
|
|
|
//info->debugger_nub_port =
|
|
|
|
//info->argc =
|
|
|
|
//info->args[64] =
|
|
|
|
//info->uid =
|
|
|
|
//info->gid =
|
|
|
|
|
|
|
|
// ToDo: make this to return real argc/argv
|
|
|
|
strlcpy(info->args, team->name, sizeof(info->args));
|
|
|
|
info->argc = 1;
|
|
|
|
|
|
|
|
return B_OK;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
_get_team_info(team_id id, team_info *info, size_t size)
|
|
|
|
{
|
|
|
|
int state;
|
|
|
|
status_t rc = B_OK;
|
|
|
|
struct team *team;
|
2004-02-23 07:08:09 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
2004-02-23 07:08:09 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
team = team_get_team_struct_locked(id);
|
|
|
|
if (!team) {
|
|
|
|
rc = B_BAD_TEAM_ID;
|
|
|
|
goto err;
|
|
|
|
}
|
2002-12-03 17:17:53 +03:00
|
|
|
|
|
|
|
rc = fill_team_info(team, info, size);
|
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
err:
|
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
_get_next_team_info(int32 *cookie, team_info *info, size_t size)
|
|
|
|
{
|
2002-12-03 17:17:53 +03:00
|
|
|
status_t status = B_BAD_TEAM_ID;
|
2002-08-04 03:39:50 +04:00
|
|
|
struct team *team = NULL;
|
2002-12-03 17:17:53 +03:00
|
|
|
int32 slot = *cookie;
|
|
|
|
|
|
|
|
int state = disable_interrupts();
|
2002-08-04 03:39:50 +04:00
|
|
|
GRAB_TEAM_LOCK();
|
2002-12-03 17:17:53 +03:00
|
|
|
|
|
|
|
if (slot >= next_team_id)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
// get next valid team
|
2002-08-05 00:10:06 +04:00
|
|
|
while ((slot < next_team_id) && !(team = team_get_team_struct_locked(slot)))
|
2002-08-04 03:39:50 +04:00
|
|
|
slot++;
|
2002-12-03 17:17:53 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
if (team) {
|
2002-12-03 17:17:53 +03:00
|
|
|
status = fill_team_info(team, info, size);
|
|
|
|
*cookie = ++slot;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
2002-12-03 17:17:53 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
err:
|
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
|
|
|
|
2002-12-03 17:17:53 +03:00
|
|
|
return status;
|
2002-08-04 03:39:50 +04:00
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
int
|
|
|
|
sys_setenv(const char *name, const char *value, int overwrite)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
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;
|
2003-01-27 06:09:33 +03:00
|
|
|
|
|
|
|
// ToDo: please put me out of the kernel into libroot.so!
|
|
|
|
|
2004-03-16 06:14:48 +03:00
|
|
|
TRACE(("sys_setenv: entry (name=%s, value=%s)\n", name, value));
|
2003-01-27 06:09:33 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
if (strlen(name) + strlen(value) + 1 >= SYS_THREAD_STRING_LENGTH_MAX)
|
|
|
|
return -1;
|
2003-01-27 06:09:33 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
2003-01-27 06:09:33 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
strcpy(var, name);
|
|
|
|
strncat(var, "=", SYS_THREAD_STRING_LENGTH_MAX-1);
|
|
|
|
name_size = strlen(var);
|
|
|
|
strncat(var, value, SYS_THREAD_STRING_LENGTH_MAX-1);
|
2003-01-27 06:09:33 +03:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
env_space = (addr)thread_get_current_thread()->team->user_env_base;
|
|
|
|
envp = (char **)env_space;
|
2003-01-27 06:09:33 +03:00
|
|
|
for (envc = 0; envp[envc]; envc++) {
|
2002-08-04 03:39:50 +04:00
|
|
|
if (!strncmp(envp[envc], var, name_size)) {
|
|
|
|
var_exists = true;
|
|
|
|
var_pos = envc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!var_exists)
|
|
|
|
var_pos = envc;
|
2003-01-27 06:09:33 +03:00
|
|
|
|
2004-03-16 06:14:48 +03:00
|
|
|
TRACE(("sys_setenv: variable does%s exist\n", var_exists ? "" : " not"));
|
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
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);
|
2003-01-27 06:09:33 +03:00
|
|
|
} else {
|
|
|
|
for (p = (char *)env_space + ENV_SIZE - 1, i = 0; envp[i]; i++)
|
2002-08-04 03:39:50 +04:00
|
|
|
if (envp[i] < p)
|
|
|
|
p = envp[i];
|
|
|
|
p -= (strlen(var) + 1);
|
|
|
|
if (p < (char *)env_space + (envc * sizeof(char *))) {
|
|
|
|
rc = -1;
|
2003-01-27 06:09:33 +03:00
|
|
|
} else {
|
2002-08-04 03:39:50 +04:00
|
|
|
envp[var_pos] = p;
|
|
|
|
strcpy(envp[var_pos], var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2003-01-27 06:09:33 +03:00
|
|
|
for (p = (char *)env_space + ENV_SIZE - 1, i=0; envp[i]; i++)
|
2002-08-04 03:39:50 +04:00
|
|
|
if (envp[i] < p)
|
|
|
|
p = envp[i];
|
|
|
|
p -= (strlen(var) + 1);
|
|
|
|
if (p < (char *)env_space + ((envc + 1) * sizeof(char *))) {
|
|
|
|
rc = -1;
|
2003-01-27 06:09:33 +03:00
|
|
|
} else {
|
2002-08-04 03:39:50 +04:00
|
|
|
envp[envc] = p;
|
|
|
|
strcpy(envp[envc], var);
|
|
|
|
envp[envc + 1] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-03-16 06:14:48 +03:00
|
|
|
TRACE(("sys_setenv: variable set.\n"));
|
2002-08-04 03:39:50 +04:00
|
|
|
|
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
2004-10-05 02:41:34 +04:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2002-08-05 09:26:52 +04:00
|
|
|
|
|
|
|
int
|
|
|
|
sys_getenv(const char *name, char **value)
|
2002-08-04 03:39:50 +04:00
|
|
|
{
|
|
|
|
char **envp;
|
|
|
|
char *p;
|
|
|
|
int state;
|
|
|
|
int i;
|
|
|
|
int len = strlen(name);
|
|
|
|
int rc = -1;
|
2003-01-27 06:09:33 +03:00
|
|
|
|
|
|
|
// ToDo: please put me out of the kernel into libroot.so!
|
2004-10-05 02:41:34 +04:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
|
|
|
|
|
|
|
envp = (char **)thread_get_current_thread()->team->user_env_base;
|
2003-01-27 06:09:33 +03:00
|
|
|
for (i = 0; envp[i]; i++) {
|
2002-08-04 03:39:50 +04:00
|
|
|
if (!strncmp(envp[i], name, len)) {
|
|
|
|
p = envp[i] + len;
|
|
|
|
if (*p == '=') {
|
|
|
|
*value = (p + 1);
|
|
|
|
rc = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-10-05 02:41:34 +04:00
|
|
|
|
2002-08-04 03:39:50 +04:00
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-03 17:17:53 +03:00
|
|
|
// #pragma mark -
|
2004-03-03 03:57:00 +03:00
|
|
|
// User syscalls
|
2002-12-03 17:17:53 +03:00
|
|
|
|
|
|
|
|
2004-09-15 19:45:37 +04:00
|
|
|
status_t
|
2004-10-07 19:34:17 +04:00
|
|
|
_user_exec(const char *userPath, int32 argCount, char * const *userArgs,
|
|
|
|
int32 envCount, char * const *userEnvironment)
|
2004-09-15 19:45:37 +04:00
|
|
|
{
|
2004-10-07 19:34:17 +04:00
|
|
|
char path[B_PATH_NAME_LENGTH];
|
|
|
|
status_t status;
|
|
|
|
char **args;
|
|
|
|
char **env;
|
2004-09-15 19:45:37 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userArgs) || !IS_USER_ADDRESS(userEnvironment)
|
|
|
|
|| user_strlcpy(path, userPath, sizeof(path)) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
2004-09-15 19:45:37 +04:00
|
|
|
|
2004-10-07 19:34:17 +04:00
|
|
|
status = user_copy_strings_array(userArgs, argCount, &args);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = user_copy_strings_array(userEnvironment, envCount, &env);
|
|
|
|
if (status < B_OK) {
|
|
|
|
free_strings_array(args, argCount);
|
|
|
|
return status;
|
2004-09-15 19:45:37 +04:00
|
|
|
}
|
2004-10-07 19:34:17 +04:00
|
|
|
|
|
|
|
status = exec_team(path, argCount, args, envCount, env);
|
|
|
|
// this one only returns in case of error
|
|
|
|
|
|
|
|
free_strings_array(args, argCount);
|
|
|
|
free_strings_array(env, envCount);
|
|
|
|
|
|
|
|
return status;
|
2004-09-15 19:45:37 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
thread_id
|
|
|
|
_user_fork(void)
|
|
|
|
{
|
|
|
|
dprintf("fork() is not yet implemented!\n");
|
|
|
|
return B_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
thread_id
|
|
|
|
_user_wait_for_child(thread_id child, uint32 flags, int32 *_userReason, status_t *_userReturnCode)
|
|
|
|
{
|
|
|
|
status_t returnCode;
|
|
|
|
int32 reason;
|
|
|
|
thread_id deadChild;
|
|
|
|
|
|
|
|
if ((_userReason != NULL && !IS_USER_ADDRESS(_userReason))
|
|
|
|
|| (_userReturnCode != NULL && !IS_USER_ADDRESS(_userReturnCode)))
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
deadChild = wait_for_child(child, flags, &reason, &returnCode);
|
|
|
|
|
|
|
|
if (deadChild >= B_OK) {
|
|
|
|
// copy result data on successful completion
|
|
|
|
if ((_userReason != NULL && user_memcpy(_userReason, &reason, sizeof(int32)) < B_OK)
|
|
|
|
|| (_userReturnCode != NULL && user_memcpy(_userReturnCode, &returnCode, sizeof(status_t)) < B_OK))
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return deadChild;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-27 06:09:33 +03:00
|
|
|
status_t
|
2004-03-03 03:57:00 +03:00
|
|
|
_user_wait_for_team(team_id id, status_t *_userReturnCode)
|
2002-12-03 17:17:53 +03:00
|
|
|
{
|
2003-01-27 06:09:33 +03:00
|
|
|
status_t returnCode;
|
|
|
|
status_t status;
|
2002-12-03 17:17:53 +03:00
|
|
|
|
2004-09-15 19:45:37 +04:00
|
|
|
if (_userReturnCode != NULL && !IS_USER_ADDRESS(_userReturnCode))
|
2002-12-03 17:17:53 +03:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
2003-01-27 06:09:33 +03:00
|
|
|
status = wait_for_team(id, &returnCode);
|
2004-08-13 23:08:35 +04:00
|
|
|
if (status >= B_OK && _userReturnCode != NULL) {
|
2003-01-27 06:09:33 +03:00
|
|
|
if (user_memcpy(_userReturnCode, &returnCode, sizeof(returnCode)) < B_OK)
|
2002-12-03 17:17:53 +03:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
team_id
|
2004-03-03 03:57:00 +03:00
|
|
|
_user_create_team(const char *userPath, const char *userName, char **userArgs,
|
|
|
|
int argCount, char **userEnv, int envCount, int priority)
|
2002-12-03 17:17:53 +03:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
2004-02-23 07:08:09 +03:00
|
|
|
char name[B_OS_NAME_LENGTH];
|
2003-11-12 18:37:44 +03:00
|
|
|
char **args = NULL;
|
|
|
|
char **env = NULL;
|
2002-12-03 17:17:53 +03:00
|
|
|
int rc;
|
|
|
|
|
2003-11-12 18:37:44 +03:00
|
|
|
TRACE(("user_team_create_team: argc = %d\n", argCount));
|
2002-12-03 17:17:53 +03:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath)
|
|
|
|
|| !IS_USER_ADDRESS(userName))
|
2003-11-12 18:37:44 +03:00
|
|
|
return B_BAD_ADDRESS;
|
2002-12-03 17:17:53 +03:00
|
|
|
|
2003-11-12 18:37:44 +03:00
|
|
|
rc = user_copy_strings_array(userArgs, argCount, &args);
|
2002-12-03 17:17:53 +03:00
|
|
|
if (rc < 0)
|
|
|
|
goto error;
|
|
|
|
|
2003-11-12 18:37:44 +03:00
|
|
|
if (userEnv == NULL) {
|
|
|
|
// ToDo: this doesn't look particularly safe to me - where
|
|
|
|
// is user_env_base?
|
|
|
|
userEnv = (char **)thread_get_current_thread()->team->user_env_base;
|
|
|
|
for (envCount = 0; userEnv && (userEnv[envCount]); envCount++);
|
|
|
|
}
|
|
|
|
if (user_copy_strings_array(userEnv, envCount, &env) < B_OK
|
|
|
|
|| user_strlcpy(path, userPath, SYS_MAX_PATH_LEN) < B_OK
|
2004-02-23 07:08:09 +03:00
|
|
|
|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) {
|
2003-11-12 18:37:44 +03:00
|
|
|
rc = B_BAD_ADDRESS;
|
2002-12-03 17:17:53 +03:00
|
|
|
goto error;
|
2003-11-12 18:37:44 +03:00
|
|
|
}
|
2002-12-03 17:17:53 +03:00
|
|
|
|
2003-11-12 18:37:44 +03:00
|
|
|
return team_create_team(path, name, args, argCount, env, envCount, priority);
|
2002-12-03 17:17:53 +03:00
|
|
|
|
|
|
|
error:
|
2004-10-07 19:34:17 +04:00
|
|
|
free_strings_array(args, argCount);
|
|
|
|
free_strings_array(env, envCount);
|
2002-12-03 17:17:53 +03:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2004-03-03 03:57:00 +03:00
|
|
|
_user_kill_team(team_id team)
|
|
|
|
{
|
|
|
|
return kill_team(team);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
_user_get_team_info(team_id id, team_info *userInfo)
|
2002-12-03 17:17:53 +03:00
|
|
|
{
|
2003-11-12 18:37:44 +03:00
|
|
|
status_t status;
|
|
|
|
team_info info;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userInfo))
|
2003-11-12 18:37:44 +03:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
status = _get_team_info(id, &info, sizeof(team_info));
|
|
|
|
if (status == B_OK) {
|
|
|
|
if (user_memcpy(userInfo, &info, sizeof(team_info)) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
2002-12-03 17:17:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2004-03-03 03:57:00 +03:00
|
|
|
_user_get_next_team_info(int32 *userCookie, team_info *userInfo)
|
2002-12-03 17:17:53 +03:00
|
|
|
{
|
2003-11-12 18:37:44 +03:00
|
|
|
status_t status;
|
|
|
|
team_info info;
|
|
|
|
int32 cookie;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userCookie)
|
|
|
|
|| !IS_USER_ADDRESS(userInfo)
|
2003-11-12 18:37:44 +03:00
|
|
|
|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
status = _get_next_team_info(&cookie, &info, sizeof(team_info));
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
|
|
|
|
|| user_memcpy(userInfo, &info, sizeof(team_info)) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return status;
|
2002-12-03 17:17:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-03 03:57:00 +03:00
|
|
|
team_id
|
|
|
|
_user_get_current_team(void)
|
|
|
|
{
|
|
|
|
return team_get_current_team_id();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-03 17:17:53 +03:00
|
|
|
int
|
2004-08-29 00:51:47 +04:00
|
|
|
_user_getenv(const char *userName, char **_userValue)
|
2002-12-03 17:17:53 +03:00
|
|
|
{
|
|
|
|
char name[SYS_THREAD_STRING_LENGTH_MAX];
|
|
|
|
char *value;
|
|
|
|
int rc;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName)
|
|
|
|
|| !IS_USER_ADDRESS(_userValue)
|
2002-12-03 17:17:53 +03:00
|
|
|
|| user_strlcpy(name, userName, SYS_THREAD_STRING_LENGTH_MAX) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
rc = sys_getenv(name, &value);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (user_memcpy(_userValue, &value, sizeof(char *)) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-08-29 00:51:47 +04:00
|
|
|
_user_setenv(const char *userName, const char *userValue, int overwrite)
|
2002-12-03 17:17:53 +03:00
|
|
|
{
|
|
|
|
char name[SYS_THREAD_STRING_LENGTH_MAX];
|
|
|
|
char value[SYS_THREAD_STRING_LENGTH_MAX];
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName)
|
|
|
|
|| !IS_USER_ADDRESS(userValue)
|
2002-12-03 17:17:53 +03:00
|
|
|
|| user_strlcpy(name, userName, SYS_THREAD_STRING_LENGTH_MAX) < B_OK
|
|
|
|
|| user_strlcpy(value, userValue, SYS_THREAD_STRING_LENGTH_MAX) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return sys_setenv(name, value, overwrite);
|
|
|
|
}
|
|
|
|
|