2 * Server-side process management
4 * Copyright (C) 1998 Alexandre Julliard
25 /* process structure */
27 static struct process
*first_process
;
28 static int running_processes
;
30 /* process operations */
32 static void process_dump( struct object
*obj
, int verbose
);
33 static int process_signaled( struct object
*obj
, struct thread
*thread
);
34 static void process_destroy( struct object
*obj
);
36 static const struct object_ops process_ops
=
51 /* create a new process */
52 static struct process
*create_process( struct process
*parent
,
53 struct new_process_request
*req
, const char *cmd_line
)
55 struct process
*process
;
57 if (!(process
= alloc_object( sizeof(*process
), &process_ops
, NULL
))) return NULL
;
60 process
->thread_list
= NULL
;
61 process
->debug_next
= NULL
;
62 process
->debug_prev
= NULL
;
63 process
->debugger
= NULL
;
64 process
->handles
= NULL
;
65 process
->exit_code
= 0x103; /* STILL_ACTIVE */
66 process
->running_threads
= 0;
67 process
->priority
= NORMAL_PRIORITY_CLASS
;
68 process
->affinity
= 1;
70 process
->console_in
= NULL
;
71 process
->console_out
= NULL
;
73 gettimeofday( &process
->start_time
, NULL
);
76 process
->handles
= copy_handle_table( process
, parent
);
78 process
->handles
= alloc_handle_table( process
, 0 );
79 if (!process
->handles
) goto error
;
81 /* alloc a handle for the process itself */
82 alloc_handle( process
, process
, PROCESS_ALL_ACCESS
, 0 );
84 if (!(process
->info
= mem_alloc( sizeof(*process
->info
) + strlen(cmd_line
) + 1 ))) goto error
;
85 memcpy( process
->info
, req
, sizeof(*req
) );
86 strcpy( process
->info
->cmd_line
, cmd_line
);
88 /* set the process console */
89 if (req
->create_flags
& CREATE_NEW_CONSOLE
)
91 if (!alloc_console( process
)) goto error
;
93 else if (!(req
->create_flags
& DETACHED_PROCESS
))
95 if (parent
->console_in
) process
->console_in
= grab_object( parent
->console_in
);
96 if (parent
->console_out
) process
->console_out
= grab_object( parent
->console_out
);
99 if (!req
->inherit_all
&& !(req
->start_flags
& STARTF_USESTDHANDLES
))
101 process
->info
->hstdin
= duplicate_handle( parent
, req
->hstdin
, process
,
102 0, TRUE
, DUPLICATE_SAME_ACCESS
);
103 process
->info
->hstdout
= duplicate_handle( parent
, req
->hstdout
, process
,
104 0, TRUE
, DUPLICATE_SAME_ACCESS
);
105 process
->info
->hstderr
= duplicate_handle( parent
, req
->hstderr
, process
,
106 0, TRUE
, DUPLICATE_SAME_ACCESS
);
109 /* attach to the debugger if requested */
110 if (req
->create_flags
& DEBUG_PROCESS
)
111 debugger_attach( process
, current
);
112 else if (parent
&& parent
->debugger
&& !(req
->create_flags
& DEBUG_ONLY_THIS_PROCESS
))
113 debugger_attach( process
, parent
->debugger
);
115 if ((process
->next
= first_process
) != NULL
) process
->next
->prev
= process
;
116 first_process
= process
;
120 free_console( process
);
121 if (process
->info
) free( process
->info
);
122 if (process
->handles
) release_object( process
->handles
);
123 release_object( process
);
127 /* create the initial process */
128 struct process
*create_initial_process(void)
130 struct process
*process
;
131 struct new_process_request req
;
135 req
.create_flags
= CREATE_NEW_CONSOLE
;
136 req
.start_flags
= STARTF_USESTDHANDLES
;
142 if ((process
= create_process( NULL
, &req
, "" )))
144 process
->info
->hstdin
= alloc_handle( process
, process
->console_in
,
145 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
, 1 );
146 process
->info
->hstdout
= alloc_handle( process
, process
->console_out
,
147 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
, 1 );
148 process
->info
->hstderr
= alloc_handle( process
, process
->console_out
,
149 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
, 1 );
154 /* destroy a process when its refcount is 0 */
155 static void process_destroy( struct object
*obj
)
157 struct process
*process
= (struct process
*)obj
;
158 assert( obj
->ops
== &process_ops
);
160 /* we can't have a thread remaining */
161 assert( !process
->thread_list
);
162 if (process
->next
) process
->next
->prev
= process
->prev
;
163 if (process
->prev
) process
->prev
->next
= process
->next
;
164 else first_process
= process
->next
;
165 if (process
->info
) free( process
->info
);
166 if (debug_level
) memset( process
, 0xbb, sizeof(process
) ); /* catch errors */
170 /* dump a process on stdout for debugging purposes */
171 static void process_dump( struct object
*obj
, int verbose
)
173 struct process
*process
= (struct process
*)obj
;
174 assert( obj
->ops
== &process_ops
);
176 fprintf( stderr
, "Process next=%p prev=%p console=%p/%p handles=%p\n",
177 process
->next
, process
->prev
, process
->console_in
, process
->console_out
,
181 static int process_signaled( struct object
*obj
, struct thread
*thread
)
183 struct process
*process
= (struct process
*)obj
;
184 return !process
->running_threads
;
188 /* get a process from an id (and increment the refcount) */
189 struct process
*get_process_from_id( void *id
)
191 struct process
*p
= first_process
;
192 while (p
&& (p
!= id
)) p
= p
->next
;
193 if (p
) grab_object( p
);
194 else SET_ERROR( ERROR_INVALID_PARAMETER
);
198 /* get a process from a handle (and increment the refcount) */
199 struct process
*get_process_from_handle( int handle
, unsigned int access
)
201 return (struct process
*)get_handle_obj( current
->process
, handle
,
202 access
, &process_ops
);
205 /* a process has been killed (i.e. its last thread died) */
206 static void process_killed( struct process
*process
, int exit_code
)
208 assert( !process
->thread_list
);
209 process
->exit_code
= exit_code
;
210 gettimeofday( &process
->end_time
, NULL
);
211 release_object( process
->handles
);
212 process
->handles
= NULL
;
213 free_console( process
);
214 wake_up( &process
->obj
, 0 );
215 if (!--running_processes
)
217 /* last process died, close global handles */
218 close_global_handles();
222 /* add a thread to a process running threads list */
223 void add_process_thread( struct process
*process
, struct thread
*thread
)
225 thread
->proc_next
= process
->thread_list
;
226 thread
->proc_prev
= NULL
;
227 if (thread
->proc_next
) thread
->proc_next
->proc_prev
= thread
;
228 process
->thread_list
= thread
;
229 if (!process
->running_threads
++) running_processes
++;
230 grab_object( thread
);
233 /* remove a thread from a process running threads list */
234 void remove_process_thread( struct process
*process
, struct thread
*thread
)
236 assert( process
->running_threads
> 0 );
237 assert( process
->thread_list
);
239 if (thread
->proc_next
) thread
->proc_next
->proc_prev
= thread
->proc_prev
;
240 if (thread
->proc_prev
) thread
->proc_prev
->proc_next
= thread
->proc_next
;
241 else process
->thread_list
= thread
->proc_next
;
243 if (!--process
->running_threads
)
245 /* we have removed the last running thread, exit the process */
246 process_killed( process
, thread
->exit_code
);
248 release_object( thread
);
251 /* suspend all the threads of a process */
252 void suspend_process( struct process
*process
)
254 if (!process
->suspend
++)
256 struct thread
*thread
= process
->thread_list
;
257 for (; thread
; thread
= thread
->proc_next
)
259 if (!thread
->suspend
&& thread
->unix_pid
)
260 kill( thread
->unix_pid
, SIGSTOP
);
265 /* resume all the threads of a process */
266 void resume_process( struct process
*process
)
268 assert (process
->suspend
> 0);
269 if (!--process
->suspend
)
271 struct thread
*thread
= process
->thread_list
;
272 for (; thread
; thread
= thread
->proc_next
)
274 if (!thread
->suspend
&& thread
->unix_pid
)
275 kill( thread
->unix_pid
, SIGCONT
);
280 /* kill a process on the spot */
281 void kill_process( struct process
*process
, int exit_code
)
283 while (process
->thread_list
)
284 kill_thread( process
->thread_list
, exit_code
);
287 /* get all information about a process */
288 static void get_process_info( struct process
*process
,
289 struct get_process_info_reply
*reply
)
291 reply
->pid
= process
;
292 reply
->exit_code
= process
->exit_code
;
293 reply
->priority
= process
->priority
;
294 reply
->process_affinity
= process
->affinity
;
295 reply
->system_affinity
= 1;
298 /* set all information about a process */
299 static void set_process_info( struct process
*process
,
300 struct set_process_info_request
*req
)
302 if (req
->mask
& SET_PROCESS_INFO_PRIORITY
)
303 process
->priority
= req
->priority
;
304 if (req
->mask
& SET_PROCESS_INFO_AFFINITY
)
306 if (req
->affinity
!= 1) SET_ERROR( ERROR_INVALID_PARAMETER
);
307 else process
->affinity
= req
->affinity
;
311 /* allocate a console for this process */
312 int alloc_console( struct process
*process
)
314 struct object
*obj
[2];
315 if (process
->console_in
|| process
->console_out
)
317 SET_ERROR( ERROR_ACCESS_DENIED
);
320 if (!create_console( -1, obj
)) return 0;
321 process
->console_in
= obj
[0];
322 process
->console_out
= obj
[1];
326 /* free the console for this process */
327 int free_console( struct process
*process
)
329 if (process
->console_in
) release_object( process
->console_in
);
330 if (process
->console_out
) release_object( process
->console_out
);
331 process
->console_in
= process
->console_out
= NULL
;
335 /* get the process console */
336 struct object
*get_console( struct process
*process
, int output
)
339 if (!(obj
= output
? process
->console_out
: process
->console_in
))
341 return grab_object( obj
);
344 /* take a snapshot of currently running processes */
345 struct process_snapshot
*process_snap( int *count
)
347 struct process_snapshot
*snapshot
, *ptr
;
348 struct process
*process
;
349 if (!running_processes
) return NULL
;
350 if (!(snapshot
= mem_alloc( sizeof(*snapshot
) * running_processes
)))
353 for (process
= first_process
; process
; process
= process
->next
)
355 if (!process
->running_threads
) continue;
356 ptr
->process
= process
;
357 ptr
->threads
= process
->running_threads
;
358 ptr
->priority
= process
->priority
;
359 grab_object( process
);
362 *count
= running_processes
;
366 /* create a new process */
367 DECL_HANDLER(new_process
)
369 struct new_process_reply reply
;
370 struct process
*process
;
371 char *cmd_line
= (char *)data
;
373 CHECK_STRING( "new_process", cmd_line
, len
);
374 if ((process
= create_process( current
->process
, req
, cmd_line
)))
377 reply
.handle
= alloc_handle( current
->process
, process
,
378 PROCESS_ALL_ACCESS
, req
->inherit
);
379 release_object( process
);
386 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
389 /* initialize a new process */
390 DECL_HANDLER(init_process
)
392 struct init_process_reply reply
;
393 struct new_process_request
*info
;
395 if (current
->state
!= RUNNING
)
397 fatal_protocol_error( "init_process: init_thread not called yet\n" );
400 if (!(info
= current
->process
->info
))
402 fatal_protocol_error( "init_process: called twice\n" );
405 current
->process
->info
= NULL
;
406 reply
.start_flags
= info
->start_flags
;
407 reply
.hstdin
= info
->hstdin
;
408 reply
.hstdout
= info
->hstdout
;
409 reply
.hstderr
= info
->hstderr
;
410 reply
.cmd_show
= info
->cmd_show
;
411 reply
.env_ptr
= info
->env_ptr
;
412 send_reply( current
, -1, 2, &reply
, sizeof(reply
),
413 info
->cmd_line
, strlen(info
->cmd_line
) + 1 );
417 /* open a handle to a process */
418 DECL_HANDLER(open_process
)
420 struct open_process_reply reply
= { -1 };
421 struct process
*process
= get_process_from_id( req
->pid
);
424 reply
.handle
= alloc_handle( current
->process
, process
,
425 req
->access
, req
->inherit
);
426 release_object( process
);
428 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
431 /* terminate a process */
432 DECL_HANDLER(terminate_process
)
434 struct process
*process
;
436 if ((process
= get_process_from_handle( req
->handle
, PROCESS_TERMINATE
)))
438 kill_process( process
, req
->exit_code
);
439 release_object( process
);
441 if (current
) send_reply( current
, -1, 0 );
444 /* fetch information about a process */
445 DECL_HANDLER(get_process_info
)
447 struct process
*process
;
448 struct get_process_info_reply reply
= { 0, 0, 0 };
450 if ((process
= get_process_from_handle( req
->handle
, PROCESS_QUERY_INFORMATION
)))
452 get_process_info( process
, &reply
);
453 release_object( process
);
455 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
458 /* set information about a process */
459 DECL_HANDLER(set_process_info
)
461 struct process
*process
;
463 if ((process
= get_process_from_handle( req
->handle
, PROCESS_SET_INFORMATION
)))
465 set_process_info( process
, req
);
466 release_object( process
);
468 send_reply( current
, -1, 0 );