server: Simplify process creation.
Pass the socket for the new process from the parent through the
environment.
Perform initialisations during the new_process request.
diff --git a/server/process.c b/server/process.c
index 0c71540..231eb2f 100644
--- a/server/process.c
+++ b/server/process.c
@@ -94,17 +94,11 @@
struct startup_info
{
struct object obj; /* object header */
- struct list entry; /* entry in list of startup infos */
- int inherit_all; /* inherit all handles from parent */
- unsigned int create_flags; /* creation flags */
- int unix_pid; /* Unix pid of new process */
obj_handle_t hstdin; /* handle for stdin */
obj_handle_t hstdout; /* handle for stdout */
obj_handle_t hstderr; /* handle for stderr */
struct file *exe_file; /* file handle for main exe */
- struct thread *owner; /* owner thread (the one that created the new process) */
struct process *process; /* created process */
- struct thread *thread; /* created thread */
size_t data_size; /* size of startup data */
void *data; /* data for startup info */
};
@@ -130,8 +124,6 @@
};
-static struct list startup_info_list = LIST_INIT(startup_info_list);
-
struct ptid_entry
{
void *ptr; /* entry ptr */
@@ -226,13 +218,18 @@
}
/* create a new process and its main thread */
-struct thread *create_process( int fd )
+/* if the function fails the fd is closed */
+struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all )
{
struct process *process;
struct thread *thread = NULL;
int request_pipe[2];
- if (!(process = alloc_object( &process_ops ))) goto error;
+ if (!(process = alloc_object( &process_ops )))
+ {
+ close( fd );
+ goto error;
+ }
process->parent = NULL;
process->debugger = NULL;
process->handles = NULL;
@@ -261,9 +258,24 @@
gettimeofday( &process->start_time, NULL );
list_add_head( &process_list, &process->entry );
- if (!(process->id = process->group_id = alloc_ptid( process ))) goto error;
+ if (!(process->id = process->group_id = alloc_ptid( process )))
+ {
+ close( fd );
+ goto error;
+ }
if (!(process->msg_fd = create_anonymous_fd( &process_fd_ops, fd, &process->obj ))) goto error;
+ /* create the handle table */
+ if (!parent_thread) process->handles = alloc_handle_table( process, 0 );
+ else
+ {
+ struct process *parent = parent_thread->process;
+ process->parent = (struct process *)grab_object( parent );
+ process->handles = inherit_all ? copy_handle_table( process, parent )
+ : alloc_handle_table( process, 0 );
+ }
+ if (!process->handles) goto error;
+
/* create the main thread */
if (pipe( request_pipe ) == -1)
{
@@ -290,82 +302,13 @@
return NULL;
}
-/* find the startup info for a given Unix process */
-inline static struct startup_info *find_startup_info( int unix_pid )
-{
- struct list *ptr;
-
- LIST_FOR_EACH( ptr, &startup_info_list )
- {
- struct startup_info *info = LIST_ENTRY( ptr, struct startup_info, entry );
- if (info->unix_pid == unix_pid) return info;
- }
- return NULL;
-}
-
/* initialize the current process and fill in the request */
size_t init_process( struct thread *thread )
{
struct process *process = thread->process;
- struct thread *parent_thread = NULL;
- struct process *parent = NULL;
- struct startup_info *info;
-
- if (process->startup_info) return process->startup_info->data_size; /* already initialized */
-
- if ((info = find_startup_info( thread->unix_pid )))
- {
- if (info->thread) return info->data_size; /* already initialized */
-
- info->thread = (struct thread *)grab_object( thread );
- info->process = (struct process *)grab_object( process );
- process->startup_info = (struct startup_info *)grab_object( info );
-
- parent_thread = info->owner;
- parent = parent_thread->process;
- process->parent = (struct process *)grab_object( parent );
-
- /* set the process flags */
- process->create_flags = info->create_flags;
-
- if (info->inherit_all) process->handles = copy_handle_table( process, parent );
- }
-
- /* create the handle table */
- if (!process->handles) process->handles = alloc_handle_table( process, 0 );
- if (!process->handles)
- {
- set_error( STATUS_NO_MEMORY );
- return 0;
- }
-
- /* connect to the window station */
- connect_process_winstation( process, parent_thread );
+ struct startup_info *info = process->startup_info;
if (!info) return 0;
-
- /* thread will be actually suspended in init_done */
- if (info->create_flags & CREATE_SUSPENDED) thread->suspend++;
-
- /* set the process console */
- if (!(info->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
- {
- /* FIXME: some better error checking should be done...
- * like if hConOut and hConIn are console handles, then they should be on the same
- * physical console
- */
- inherit_console( parent_thread, process, info->inherit_all ? info->hstdin : 0 );
- }
-
- /* attach to the debugger if requested */
- if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
- set_process_debugger( process, parent_thread );
- else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
- set_process_debugger( process, parent->debugger );
-
- if (!(process->create_flags & CREATE_NEW_PROCESS_GROUP))
- process->group_id = parent->group_id;
-
return info->data_size;
}
@@ -426,12 +369,9 @@
{
struct startup_info *info = (struct startup_info *)obj;
assert( obj->ops == &startup_info_ops );
- list_remove( &info->entry );
if (info->data) free( info->data );
if (info->exe_file) release_object( info->exe_file );
if (info->process) release_object( info->process );
- if (info->thread) release_object( info->thread );
- if (info->owner) release_object( info->owner );
}
static void startup_info_dump( struct object *obj, int verbose )
@@ -439,8 +379,8 @@
struct startup_info *info = (struct startup_info *)obj;
assert( obj->ops == &startup_info_ops );
- fprintf( stderr, "Startup info flags=%x in=%p out=%p err=%p\n",
- info->create_flags, info->hstdin, info->hstdout, info->hstderr );
+ fprintf( stderr, "Startup info in=%p out=%p err=%p\n",
+ info->hstdin, info->hstdout, info->hstderr );
}
static int startup_info_signaled( struct object *obj, struct thread *thread )
@@ -792,20 +732,30 @@
DECL_HANDLER(new_process)
{
struct startup_info *info;
+ struct thread *thread;
+ struct process *process;
+ struct process *parent = current->process;
+ int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
+
+ if (socket_fd == -1)
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+ if (fcntl( socket_fd, F_SETFL, O_NONBLOCK ) == -1)
+ {
+ set_error( STATUS_INVALID_HANDLE );
+ close( socket_fd );
+ return;
+ }
/* build the startup info for a new process */
if (!(info = alloc_object( &startup_info_ops ))) return;
- list_add_head( &startup_info_list, &info->entry );
- info->inherit_all = req->inherit_all;
- info->create_flags = req->create_flags;
- info->unix_pid = req->unix_pid;
info->hstdin = req->hstdin;
info->hstdout = req->hstdout;
info->hstderr = req->hstderr;
info->exe_file = NULL;
- info->owner = (struct thread *)grab_object( current );
info->process = NULL;
- info->thread = NULL;
info->data_size = get_req_data_size();
info->data = NULL;
@@ -814,7 +764,56 @@
goto done;
if (!(info->data = memdup( get_req_data(), info->data_size ))) goto done;
+
+ if (!(thread = create_process( socket_fd, current, req->inherit_all ))) goto done;
+ process = thread->process;
+ process->create_flags = req->create_flags;
+ process->startup_info = (struct startup_info *)grab_object( info );
+
+ /* connect to the window station */
+ connect_process_winstation( process, current );
+
+ /* thread will be actually suspended in init_done */
+ if (req->create_flags & CREATE_SUSPENDED) thread->suspend++;
+
+ /* set the process console */
+ if (!(req->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
+ {
+ /* FIXME: some better error checking should be done...
+ * like if hConOut and hConIn are console handles, then they should be on the same
+ * physical console
+ */
+ inherit_console( current, process, req->inherit_all ? req->hstdin : 0 );
+ }
+
+ if (!req->inherit_all && !(req->create_flags & CREATE_NEW_CONSOLE))
+ {
+ info->hstdin = duplicate_handle( parent, req->hstdin, process,
+ 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
+ info->hstdout = duplicate_handle( parent, req->hstdout, process,
+ 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
+ info->hstderr = duplicate_handle( parent, req->hstderr, process,
+ 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
+ /* some handles above may have been invalid; this is not an error */
+ if (get_error() == STATUS_INVALID_HANDLE ||
+ get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error();
+ }
+
+ /* attach to the debugger if requested */
+ if (req->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
+ set_process_debugger( process, current );
+ else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
+ set_process_debugger( process, parent->debugger );
+
+ if (!(req->create_flags & CREATE_NEW_PROCESS_GROUP))
+ process->group_id = parent->group_id;
+
+ info->process = (struct process *)grab_object( process );
reply->info = alloc_handle( current->process, info, SYNCHRONIZE, 0 );
+ reply->pid = get_process_id( process );
+ reply->tid = get_thread_id( thread );
+ reply->phandle = alloc_handle( parent, process, req->process_access, req->process_attr );
+ reply->thandle = alloc_handle( parent, thread, req->thread_access, req->thread_attr );
done:
release_object( info );
@@ -828,23 +827,10 @@
if ((info = (struct startup_info *)get_handle_obj( current->process, req->info,
0, &startup_info_ops )))
{
- reply->pid = get_process_id( info->process );
- reply->tid = get_thread_id( info->thread );
- reply->phandle = alloc_handle( current->process, info->process,
- req->process_access, req->process_attr );
- reply->thandle = alloc_handle( current->process, info->thread,
- req->thread_access, req->thread_attr );
reply->success = is_process_init_done( info->process );
+ reply->exit_code = info->process->exit_code;
release_object( info );
}
- else
- {
- reply->pid = 0;
- reply->tid = 0;
- reply->phandle = 0;
- reply->thandle = 0;
- reply->success = 0;
- }
}
/* Retrieve the new process startup info */
@@ -859,25 +845,9 @@
if (info->exe_file &&
!(reply->exe_file = alloc_handle( process, info->exe_file, GENERIC_READ, 0 ))) return;
- if (!info->inherit_all && !(info->create_flags & CREATE_NEW_CONSOLE))
- {
- struct process *parent_process = info->owner->process;
- reply->hstdin = duplicate_handle( parent_process, info->hstdin, process,
- 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
- reply->hstdout = duplicate_handle( parent_process, info->hstdout, process,
- 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
- reply->hstderr = duplicate_handle( parent_process, info->hstderr, process,
- 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
- /* some handles above may have been invalid; this is not an error */
- if (get_error() == STATUS_INVALID_HANDLE ||
- get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error();
- }
- else
- {
- reply->hstdin = info->hstdin;
- reply->hstdout = info->hstdout;
- reply->hstderr = info->hstderr;
- }
+ reply->hstdin = info->hstdin;
+ reply->hstdout = info->hstdout;
+ reply->hstderr = info->hstderr;
/* we return the data directly without making a copy so this can only be called once */
size = info->data_size;