]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygserver/process.cc
cygserver: Only print basename of source in debug output to raise readability
[newlib-cygwin.git] / winsup / cygserver / process.cc
CommitLineData
282113ba 1/* process.cc
f449bfef 2
f449bfef
RC
3 Written by Robert Collins <rbtcollins@hotmail.com>
4
1c001dd2 5This file is part of Cygwin.
f449bfef 6
1c001dd2
CS
7This software is a copyrighted work licensed under the terms of the
8Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9details. */
f449bfef 10
1dcd520b 11#ifdef __OUTSIDE_CYGWIN__
1c001dd2
CS
12#include "woutsup.h"
13
14#include <sys/types.h>
15
16#include <assert.h>
f449bfef 17#include <stdlib.h>
f449bfef 18
282113ba 19#include "process.h"
1c001dd2 20
8d8f4036
CV
21#include "cygserver_ipc.h"
22
1c001dd2
CS
23/*****************************************************************************/
24
25#define elements(ARRAY) (sizeof (ARRAY) / sizeof (*ARRAY))
26
27/*****************************************************************************/
28
29process_cleanup::~process_cleanup ()
f449bfef 30{
282113ba 31 delete _process;
f449bfef
RC
32}
33
1c001dd2
CS
34void
35process_cleanup::process ()
f449bfef 36{
1c001dd2 37 _process->cleanup ();
f449bfef
RC
38}
39
1c001dd2
CS
40/*****************************************************************************/
41
8d8f4036 42process::process (const pid_t cygpid, const DWORD winpid)
1c001dd2
CS
43 : _cygpid (cygpid),
44 _winpid (winpid),
45 _hProcess (NULL),
46 _cleaning_up (false),
47 _exit_status (STILL_ACTIVE),
48 _routines_head (NULL),
49 _next (NULL)
50{
51 _hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, winpid);
52 if (!_hProcess)
f449bfef 53 {
681bb2f7 54 system_printf ("unable to obtain handle for new cache process %d(%u)",
1c001dd2
CS
55 _cygpid, _winpid);
56 _hProcess = INVALID_HANDLE_VALUE;
57 _exit_status = 0;
f449bfef
RC
58 }
59 else
681bb2f7 60 debug_printf ("got handle %p for new cache process %d(%u)",
1c001dd2
CS
61 _hProcess, _cygpid, _winpid);
62 InitializeCriticalSection (&_access);
681bb2f7 63 debug ("initialized (%u)", _cygpid);
f449bfef
RC
64}
65
1c001dd2 66process::~process ()
f449bfef 67{
681bb2f7 68 debug ("deleting (%u)", _cygpid);
1c001dd2 69 DeleteCriticalSection (&_access);
373a036f 70 CloseHandle (_hProcess);
f449bfef
RC
71}
72
1c001dd2 73/* No need to be thread-safe as this is only ever called by
2d015bd6
CV
74 * process_cache::check_and_remove_process (). If it has to be made
75 * thread-safe later on, it should not use the `access' critical section as
76 * that is held by the client request handlers for an arbitrary length of time,
77 * i.e. while they do whatever processing is required for a client request.
1c001dd2
CS
78 */
79DWORD
80process::check_exit_code ()
f449bfef 81{
1c001dd2
CS
82 if (_hProcess && _hProcess != INVALID_HANDLE_VALUE
83 && _exit_status == STILL_ACTIVE
84 && !GetExitCodeProcess (_hProcess, &_exit_status))
85 {
681bb2f7 86 system_printf ("failed to retrieve exit code for %d(%u), error = %u",
1c001dd2
CS
87 _cygpid, _winpid, GetLastError ());
88 _hProcess = INVALID_HANDLE_VALUE;
89 }
90 return _exit_status;
f449bfef
RC
91}
92
1c001dd2
CS
93bool
94process::add (cleanup_routine *const entry)
f449bfef 95{
1c001dd2 96 assert (entry);
f449bfef 97
1c001dd2 98 bool res = false;
1f8b3049 99 hold ();
1c001dd2
CS
100
101 if (!_cleaning_up)
f449bfef 102 {
1c001dd2
CS
103 entry->_next = _routines_head;
104 _routines_head = entry;
105 res = true;
f449bfef 106 }
1c001dd2 107
1f8b3049 108 release ();
1c001dd2
CS
109 return res;
110}
111
112bool
113process::remove (const cleanup_routine *const entry)
114{
115 assert (entry);
116
117 bool res = false;
1f8b3049 118 hold ();
1c001dd2
CS
119
120 if (!_cleaning_up)
f449bfef 121 {
1c001dd2
CS
122 cleanup_routine *previous = NULL;
123
124 for (cleanup_routine *ptr = _routines_head;
125 ptr;
126 previous = ptr, ptr = ptr->_next)
f449bfef 127 {
1c001dd2
CS
128 if (*ptr == *entry)
129 {
130 if (previous)
131 previous->_next = ptr->_next;
132 else
133 _routines_head = ptr->_next;
134
282113ba 135 delete ptr;
1c001dd2
CS
136 res = true;
137 break;
138 }
f449bfef
RC
139 }
140 }
1c001dd2 141
1f8b3049 142 release ();
1c001dd2 143 return res;
f449bfef 144}
2402700d 145
1c001dd2
CS
146/* This is single threaded. It's called after the process is removed
147 * from the cache, but inserts may be attemped by worker threads that
148 * have a pointer to it.
f449bfef 149 */
1c001dd2
CS
150void
151process::cleanup ()
f449bfef 152{
1f8b3049 153 hold ();
1c001dd2
CS
154 assert (!is_active ());
155 assert (!_cleaning_up);
156 InterlockedExchange (&_cleaning_up, true);
157 cleanup_routine *entry = _routines_head;
158 _routines_head = NULL;
1f8b3049 159 release ();
1c001dd2
CS
160
161 while (entry)
f449bfef 162 {
1c001dd2
CS
163 cleanup_routine *const ptr = entry;
164 entry = entry->_next;
165 ptr->cleanup (this);
282113ba 166 delete ptr;
f449bfef 167 }
f449bfef
RC
168}
169
1c001dd2 170/*****************************************************************************/
f449bfef
RC
171
172void
1c001dd2 173process_cache::submission_loop::request_loop ()
f449bfef 174{
1c001dd2
CS
175 assert (this);
176 assert (_cache);
177 assert (_interrupt_event);
178
179 while (_running)
180 _cache->wait_for_processes (_interrupt_event);
f449bfef
RC
181}
182
1c001dd2
CS
183/*****************************************************************************/
184
2d015bd6
CV
185process_cache::process_cache (const size_t max_procs,
186 const unsigned int initial_workers)
1c001dd2
CS
187 : _queue (initial_workers),
188 _submitter (this, &_queue), // true == interruptible
189 _processes_count (0),
2d015bd6 190 _max_process_count (max_procs),
1c001dd2
CS
191 _processes_head (NULL),
192 _cache_add_trigger (NULL)
f449bfef 193{
1c001dd2
CS
194 /* there can only be one */
195 InitializeCriticalSection (&_cache_write_access);
196
197 _cache_add_trigger = CreateEvent (NULL, // SECURITY_ATTRIBUTES
2d015bd6 198 TRUE, // Manual-reset
1c001dd2
CS
199 FALSE, // Initially non-signalled
200 NULL); // Anonymous
201
202 if (!_cache_add_trigger)
f449bfef 203 {
681bb2f7 204 system_printf ("failed to create cache add trigger, error = %u",
1c001dd2
CS
205 GetLastError ());
206 abort ();
f449bfef 207 }
f449bfef 208
1c001dd2 209 _queue.add_submission_loop (&_submitter);
f449bfef
RC
210}
211
1c001dd2 212process_cache::~process_cache ()
f449bfef 213{
1c001dd2
CS
214 (void) CloseHandle (_cache_add_trigger);
215 DeleteCriticalSection (&_cache_write_access);
f449bfef
RC
216}
217
1c001dd2
CS
218/* This returns the process object to the caller already locked, that
219 * is, with the object's `access' critical region entered. Thus the
220 * caller must unlock the object when it's finished with it (via
221 * process::release ()). It must then not try to access the object
222 * afterwards, except by going through this routine again, as it may
223 * have been deleted once it has been unlocked.
224 */
225class process *
8d8f4036 226process_cache::process (const pid_t cygpid, const DWORD winpid)
f449bfef 227{
1c001dd2
CS
228 /* TODO: make this more granular, so a search doesn't involve the
229 * write lock.
230 */
231 EnterCriticalSection (&_cache_write_access);
232 class process *previous = NULL;
233 class process *entry = find (winpid, &previous);
234
235 if (!entry)
f449bfef 236 {
2d015bd6 237 if (_processes_count >= _max_process_count)
1c001dd2
CS
238 {
239 LeaveCriticalSection (&_cache_write_access);
240 system_printf (("process limit (%d processes) reached; "
681bb2f7 241 "new connection refused for %d(%u)"),
2d015bd6 242 _max_process_count, cygpid, winpid);
1c001dd2
CS
243 return NULL;
244 }
245
8d8f4036 246 entry = new class process (cygpid, winpid);
1c001dd2
CS
247 if (!entry->is_active ())
248 {
249 LeaveCriticalSection (&_cache_write_access);
282113ba 250 delete entry;
1c001dd2
CS
251 return NULL;
252 }
253
254 if (previous)
255 {
256 entry->_next = previous->_next;
257 previous->_next = entry;
258 }
259 else
260 {
261 entry->_next = _processes_head;
262 _processes_head = entry;
263 }
264
265 _processes_count += 1;
266 SetEvent (_cache_add_trigger);
f449bfef 267 }
1c001dd2 268
1f8b3049 269 entry->hold (); // To be released by the caller.
1c001dd2
CS
270 LeaveCriticalSection (&_cache_write_access);
271 assert (entry);
272 assert (entry->_winpid == winpid);
273 return entry;
f449bfef
RC
274}
275
2d015bd6
CV
276struct pcache_wait_t
277{
278 size_t index;
279 size_t count;
280 HANDLE *hdls;
281};
282
283static DWORD WINAPI
284pcache_wait_thread (const LPVOID param)
285{
286 pcache_wait_t *p = (pcache_wait_t *) param;
287
288 DWORD rc = WaitForMultipleObjects (p->count, p->hdls, FALSE, INFINITE);
289 ExitThread (rc == WAIT_FAILED ? rc : rc + p->index);
290}
291
f449bfef 292void
1c001dd2 293process_cache::wait_for_processes (const HANDLE interrupt_event)
f449bfef 294{
1c001dd2 295 // Update `_wait_array' with handles of all current processes.
2d015bd6 296 size_t idx;
1c001dd2
CS
297 const size_t count = sync_wait_array (interrupt_event);
298
299 debug_printf ("waiting on %u objects in total (%u processes)",
300 count, _processes_count);
301
2d015bd6 302 DWORD rc = WAIT_FAILED;
1c001dd2 303
2d015bd6 304 if (count <= 64)
1c001dd2 305 {
2d015bd6
CV
306 /* If count <= 64, a single WaitForMultipleObjects is sufficient and
307 we can simply wait in the main thread. */
308 rc = WaitForMultipleObjects (count, _wait_array, FALSE, INFINITE);
309 if (rc == WAIT_FAILED)
310 {
681bb2f7 311 system_printf ("could not wait on the process handles, error = %u",
2d015bd6
CV
312 GetLastError ());
313 abort ();
314 }
1c001dd2 315 }
2d015bd6
CV
316 else
317 {
318 /* If count > 64 we have to create sub-threads which wait for the
319 actual wait objects and the main thread waits for the termination
320 of one of the threads. */
321 HANDLE main_wait_array[5] = { NULL };
322 DWORD mcount = 0;
1c001dd2 323
2d015bd6
CV
324 for (idx = 0; idx < count; idx += 64)
325 {
326 pcache_wait_t p = { idx, min (count - idx, 64), _wait_array + idx };
327 main_wait_array[mcount++] = CreateThread (NULL, 0, pcache_wait_thread,
328 &p, 0, NULL);
329 }
1c001dd2 330
2d015bd6
CV
331 rc = WaitForMultipleObjects (mcount, main_wait_array, FALSE, INFINITE);
332 if (rc == WAIT_FAILED)
333 {
681bb2f7 334 system_printf ("could not wait on the process handles, error = %u",
2d015bd6
CV
335 GetLastError ());
336 abort ();
337 }
338
339 /* Check for error condition on signalled sub-thread. */
340 GetExitCodeThread (main_wait_array[rc], &rc);
341 if (rc == WAIT_FAILED)
342 {
681bb2f7 343 system_printf ("could not wait on the process handles, error = %u",
2d015bd6
CV
344 GetLastError ());
345 abort ();
346 }
347
348 /* Wake up all waiting threads. _cache_add_trigger gets reset
349 in sync_wait_array again. */
350 SetEvent (_cache_add_trigger);
351 WaitForMultipleObjects (mcount, main_wait_array, TRUE, INFINITE);
352 for (idx = 0; idx < mcount; idx++)
353 CloseHandle (main_wait_array[idx]);
f449bfef 354 }
1c001dd2 355
2d015bd6
CV
356 /* Tell all processes the bad news. This one formerly only checked
357 processes beginning with the index of the signalled process, but
358 this can result in processes which are signalled but never removed
359 under heavy load conditions. */
360 for (idx = 0; idx < count; idx++)
361 if (_process_array[idx])
362 check_and_remove_process (idx);
f449bfef
RC
363}
364
1c001dd2
CS
365/*
366 * process_cache::sync_wait_array ()
367 *
368 * Fill-in the wait array with the handles that the cache needs to wait on.
369 * These handles are:
370 * - the process_process_param's interrupt event
371 * - the process_cache's cache_add_trigger event
372 * - the handle for each live process in the cache.
373 *
374 * Return value: the number of live handles in the array.
375 */
376
377size_t
378process_cache::sync_wait_array (const HANDLE interrupt_event)
f449bfef 379{
1c001dd2 380 assert (this);
1c001dd2
CS
381 assert (interrupt_event && interrupt_event != INVALID_HANDLE_VALUE);
382
2d015bd6
CV
383 /* Always reset _cache_add_trigger before filling up the array again. */
384 ResetEvent (_cache_add_trigger);
1c001dd2 385
2d015bd6 386 EnterCriticalSection (&_cache_write_access);
1c001dd2
CS
387
388 size_t index = 0;
389
390 for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
f449bfef 391 {
1c001dd2
CS
392 assert (ptr->_hProcess && ptr->_hProcess != INVALID_HANDLE_VALUE);
393 assert (ptr->is_active ());
394
395 _wait_array[index] = ptr->handle ();
396 _process_array[index++] = ptr;
397
2d015bd6
CV
398 if (!ptr->_next || index % 64 == 62)
399 {
400 /* Added at the end of each thread's array part for efficiency. */
401 _wait_array[index] = interrupt_event;
402 _process_array[index++] = NULL;
403 _wait_array[index] = _cache_add_trigger;
404 _process_array[index++] = NULL;
405 }
f449bfef 406 }
1c001dd2 407
2d015bd6
CV
408 if (!index)
409 {
410 /* To get at least *something* to wait for. */
411 _wait_array[index] = interrupt_event;
412 _process_array[index++] = NULL;
413 _wait_array[index] = _cache_add_trigger;
414 _process_array[index++] = NULL;
415 }
1c001dd2
CS
416
417 assert (index <= elements (_wait_array));
418
419 LeaveCriticalSection (&_cache_write_access);
420
421 return index;
f449bfef
RC
422}
423
f449bfef 424void
1c001dd2 425process_cache::check_and_remove_process (const size_t index)
f449bfef 426{
1c001dd2
CS
427 assert (this);
428 assert (index < elements (_wait_array) - SPECIALS_COUNT);
429
430 class process *const process = _process_array[index];
431
432 assert (process);
433 assert (process->handle () == _wait_array[index]);
434
435 if (process->check_exit_code () == STILL_ACTIVE)
436 return;
437
681bb2f7 438 debug_printf ("process %d(%u) has left the building ($? = %u)",
1c001dd2
CS
439 process->_cygpid, process->_winpid, process->_exit_status);
440
441 /* Unlink the process object from the process list. */
442
443 EnterCriticalSection (&_cache_write_access);
444
445 class process *previous = NULL;
446
447 const class process *const tmp = find (process->_winpid, &previous);
448
449 assert (tmp == process);
450 assert (previous ? previous->_next == process : _processes_head == process);
451
452 if (previous)
453 previous->_next = process->_next;
454 else
455 _processes_head = process->_next;
456
457 _processes_count -= 1;
458 LeaveCriticalSection (&_cache_write_access);
459
460 /* Schedule any cleanup tasks for this process. */
282113ba 461 _queue.add (new process_cleanup (process));
f449bfef
RC
462}
463
1c001dd2
CS
464class process *
465process_cache::find (const DWORD winpid, class process **previous)
f449bfef 466{
1c001dd2
CS
467 if (previous)
468 *previous = NULL;
469
470 for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
471 if (ptr->_winpid == winpid)
472 return ptr;
473 else if (ptr->_winpid > winpid) // The list is sorted by winpid.
474 return NULL;
475 else if (previous)
476 *previous = ptr;
477
478 return NULL;
f449bfef 479}
1c001dd2 480
8d8f4036
CV
481void
482thread::dup_signal_arrived ()
483{
484 if (ipcblk && ipcblk->signal_arrived
485 && !DuplicateHandle (client->handle (), ipcblk->signal_arrived,
486 GetCurrentProcess (), &ipcblk->signal_arrived,
487 0, FALSE, DUPLICATE_SAME_ACCESS))
488 {
489 system_printf ("error duplicating thread's signal_arrived "
490 "to server (%u)", GetLastError ());
491 ipcblk->signal_arrived = NULL;
492 }
493}
494
495void
496thread::close_signal_arrived ()
497{
498 if (ipcblk && ipcblk->signal_arrived)
499 CloseHandle (ipcblk->signal_arrived);
500}
501
1c001dd2 502/*****************************************************************************/
1dcd520b 503#endif /* __OUTSIDE_CYGWIN__ */
This page took 0.268397 seconds and 5 git commands to generate.