fork_team() is working now! It might not be 100% complete (signal handling),

but the kernel part seems to work good enough for now.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9296 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-10-12 04:03:52 +00:00
parent a8673f45bf
commit fdbd1b5d7b
+87 -36
View File
@@ -45,6 +45,15 @@ struct team_arg {
char **env; char **env;
}; };
struct fork_arg {
area_id user_stack_area;
addr_t user_stack_base;
size_t user_stack_size;
addr_t user_local_storage;
struct arch_fork_arg arch_info;
};
// team list // team list
static void *team_hash = NULL; static void *team_hash = NULL;
static team_id next_team_id = 1; static team_id next_team_id = 1;
@@ -541,7 +550,7 @@ create_team_arg(const char *path, int32 argc, char **args, int32 envCount, char
static int32 static int32
team_create_team2(void *args) team_create_thread_start(void *args)
{ {
int err; int err;
struct thread *t; struct thread *t;
@@ -712,7 +721,7 @@ team_create_team(const char *path, const char *name, char **args, int argc, char
threadName = name; threadName = name;
// create a kernel thread, but under the context of the new team // create a kernel thread, but under the context of the new team
tid = spawn_kernel_thread_etc(team_create_team2, threadName, B_NORMAL_PRIORITY, teamArgs, team->id); tid = spawn_kernel_thread_etc(team_create_thread_start, threadName, B_NORMAL_PRIORITY, teamArgs, team->id);
if (tid < 0) { if (tid < 0) {
err = tid; err = tid;
goto err4; goto err4;
@@ -773,6 +782,7 @@ exec_team(const char *path, int32 argCount, char **args, int32 envCount, char **
// ToDo: remove team resources if there are any left // ToDo: remove team resources if there are any left
// alarm, signals // alarm, signals
// thread_atkernel_exit() might not be called at all
vm_delete_areas(team->aspace); vm_delete_areas(team->aspace);
delete_owned_ports(team->id); delete_owned_ports(team->id);
@@ -780,7 +790,7 @@ exec_team(const char *path, int32 argCount, char **args, int32 envCount, char **
remove_images(team); remove_images(team);
vfs_exec_io_context(team->io_context); vfs_exec_io_context(team->io_context);
status = team_create_team2(teamArgs); status = team_create_thread_start(teamArgs);
// this one usually doesn't return... // 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) // sorry, we have to kill us, there is no way out anymore (without any areas left and all that)
@@ -791,44 +801,80 @@ exec_team(const char *path, int32 argCount, char **args, int32 envCount, char **
} }
/** This is the first function to be called from the newly created
* main child thread.
* It will fill in everything what's left to do from fork_arg, and
* return from the parent's fork() syscall to the child.
*/
static int32
fork_team_thread_start(void *_args)
{
struct thread *thread = thread_get_current_thread();
struct fork_arg *forkArgs = (struct fork_arg *)_args;
struct arch_fork_arg archArgs = forkArgs->arch_info;
// we need a local copy of the arch dependent part
thread->user_stack_region_id = forkArgs->user_stack_area;
thread->user_stack_base = forkArgs->user_stack_base;
thread->user_stack_size = forkArgs->user_stack_size;
thread->user_local_storage = forkArgs->user_local_storage;
arch_thread_init_tls(thread);
free(forkArgs);
// set frame of the parent thread to this one, too
arch_restore_fork_frame(&archArgs);
// This one won't return here
return 0;
}
static thread_id static thread_id
fork_team(void) fork_team(void)
{ {
struct team *forkedTeam = thread_get_current_thread()->team, *team; struct team *parentTeam = thread_get_current_thread()->team, *team;
struct thread *forkedThread = thread_get_current_thread(), *thread; struct thread *parentThread = thread_get_current_thread();
struct fork_arg *forkArgs;
struct area_info info; struct area_info info;
thread_id threadID;
cpu_status state; cpu_status state;
status_t status; status_t status;
int32 cookie; int32 cookie;
team_id pid;
TRACE(("fork_team()\n")); TRACE(("fork_team()\n"));
if (forkedTeam == team_get_kernel_team()) if (parentTeam == team_get_kernel_team())
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
dprintf("fork() is not yet implemented!\n");
// create a new team // create a new team
// ToDo: this is very similar to team_create_team() - maybe we can do something about it :) // ToDo: this is very similar to team_create_team() - maybe we can do something about it :)
team = create_team_struct(forkedTeam->name, false); team = create_team_struct(parentTeam->name, false);
if (team == NULL) if (team == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
pid = team->id;
state = disable_interrupts(); state = disable_interrupts();
GRAB_TEAM_LOCK(); GRAB_TEAM_LOCK();
hash_insert(team_hash, team); hash_insert(team_hash, team);
insert_team_into_parent(forkedTeam, team); insert_team_into_parent(parentTeam, team);
RELEASE_TEAM_LOCK(); RELEASE_TEAM_LOCK();
restore_interrupts(state); restore_interrupts(state);
forkArgs = (struct fork_arg *)malloc(sizeof(struct fork_arg));
if (forkArgs == NULL) {
status = B_NO_MEMORY;
goto err1;
}
// create a new io_context for this team // create a new io_context for this team
team->io_context = vfs_new_io_context(forkedTeam->io_context); team->io_context = vfs_new_io_context(parentTeam->io_context);
if (!team->io_context) { if (!team->io_context) {
status = B_NO_MEMORY; status = B_NO_MEMORY;
goto err2; goto err2;
@@ -846,46 +892,51 @@ fork_team(void)
cookie = 0; cookie = 0;
while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
void *address; void *address;
status = vm_copy_area(team->aspace->id, info.name, &address, B_CLONE_ADDRESS, area_id area = vm_copy_area(team->aspace->id, info.name, &address, B_CLONE_ADDRESS,
info.protection, info.area); info.protection, info.area);
if (status < B_OK) if (area < B_OK) {
status = area;
break; break;
}
if (info.area == parentThread->user_stack_region_id)
forkArgs->user_stack_area = area;
} }
if (status < B_OK) if (status < B_OK)
goto err4; goto err4;
/* forkArgs->user_stack_base = parentThread->user_stack_base;
// cut the path from the main thread name forkArgs->user_stack_size = parentThread->user_stack_size;
threadName = strrchr(name, '/'); forkArgs->user_local_storage = parentThread->user_local_storage;
if (threadName != NULL) arch_store_fork_frame(&forkArgs->arch_info);
threadName++;
else team->user_env_base = parentTeam->user_env_base;
threadName = name; // ToDo: copy image list
*/
/* // create a kernel thread under the context of the new team
// create a kernel thread, but under the context of the new team threadID = spawn_kernel_thread_etc(fork_team_thread_start, parentThread->name,
tid = spawn_kernel_thread_etc(team_create_team2, threadName, B_NORMAL_PRIORITY, teamArgs, team->id); parentThread->priority, forkArgs, team->id);
if (tid < 0) { if (threadID < 0) {
err = tid; status = threadID;
goto err4; goto err4;
} }
resume_thread(tid); resume_thread(threadID);
*/ return threadID;
return pid;
err4: err4:
vm_put_aspace(team->aspace); vm_delete_aspace(team->aspace);
err3: err3:
vfs_free_io_context(team->io_context); vfs_free_io_context(team->io_context);
err2: err2:
//free_team_arg(teamArgs); free(forkArgs);
err1:
// remove the team structure from the team hash table and delete the team structure // remove the team structure from the team hash table and delete the team structure
state = disable_interrupts(); state = disable_interrupts();
GRAB_TEAM_LOCK(); GRAB_TEAM_LOCK();
remove_team_from_parent(forkedTeam, team); remove_team_from_parent(parentTeam, team);
hash_remove(team_hash, team); hash_remove(team_hash, team);
RELEASE_TEAM_LOCK(); RELEASE_TEAM_LOCK();