]>
sourceware.org Git - newlib-cygwin.git/blob - winsup/cygserver/process.cc
3 Copyright 2001, 2002, 2003, 2004, 2005, 2014 Red Hat Inc.
5 Written by Robert Collins <rbtcollins@hotmail.com>
7 This file is part of Cygwin.
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13 #ifdef __OUTSIDE_CYGWIN__
16 #include <sys/types.h>
23 /*****************************************************************************/
25 #define elements(ARRAY) (sizeof (ARRAY) / sizeof (*ARRAY))
27 /*****************************************************************************/
29 process_cleanup::~process_cleanup ()
35 process_cleanup::process ()
40 /*****************************************************************************/
42 process::process (const pid_t cygpid
, const DWORD winpid
, HANDLE signal_arrived
)
46 _signal_arrived (INVALID_HANDLE_VALUE
),
48 _exit_status (STILL_ACTIVE
),
49 _routines_head (NULL
),
52 _hProcess
= OpenProcess (PROCESS_ALL_ACCESS
, FALSE
, winpid
);
55 system_printf ("unable to obtain handle for new cache process %d(%u)",
57 _hProcess
= INVALID_HANDLE_VALUE
;
61 debug_printf ("got handle %p for new cache process %d(%u)",
62 _hProcess
, _cygpid
, _winpid
);
64 debug_printf ("signal_arrived NULL for process %d(%u)", _cygpid
, _winpid
);
65 else if (signal_arrived
!= INVALID_HANDLE_VALUE
)
67 if (!DuplicateHandle (_hProcess
, signal_arrived
,
68 GetCurrentProcess (), &_signal_arrived
,
69 0, FALSE
, DUPLICATE_SAME_ACCESS
))
71 system_printf ("error getting signal_arrived to server (%u)",
73 _signal_arrived
= INVALID_HANDLE_VALUE
;
76 InitializeCriticalSection (&_access
);
77 debug ("initialized (%u)", _cygpid
);
82 debug ("deleting (%u)", _cygpid
);
83 DeleteCriticalSection (&_access
);
84 if (_signal_arrived
&& _signal_arrived
!= INVALID_HANDLE_VALUE
)
85 CloseHandle (_signal_arrived
);
86 CloseHandle (_hProcess
);
89 /* No need to be thread-safe as this is only ever called by
90 * process_cache::check_and_remove_process (). If it has to be made
91 * thread-safe later on, it should not use the `access' critical section as
92 * that is held by the client request handlers for an arbitrary length of time,
93 * i.e. while they do whatever processing is required for a client request.
96 process::check_exit_code ()
98 if (_hProcess
&& _hProcess
!= INVALID_HANDLE_VALUE
99 && _exit_status
== STILL_ACTIVE
100 && !GetExitCodeProcess (_hProcess
, &_exit_status
))
102 system_printf ("failed to retrieve exit code for %d(%u), error = %u",
103 _cygpid
, _winpid
, GetLastError ());
104 _hProcess
= INVALID_HANDLE_VALUE
;
110 process::add (cleanup_routine
*const entry
)
119 entry
->_next
= _routines_head
;
120 _routines_head
= entry
;
129 process::remove (const cleanup_routine
*const entry
)
138 cleanup_routine
*previous
= NULL
;
140 for (cleanup_routine
*ptr
= _routines_head
;
142 previous
= ptr
, ptr
= ptr
->_next
)
147 previous
->_next
= ptr
->_next
;
149 _routines_head
= ptr
->_next
;
162 /* This is single threaded. It's called after the process is removed
163 * from the cache, but inserts may be attemped by worker threads that
164 * have a pointer to it.
170 assert (!is_active ());
171 assert (!_cleaning_up
);
172 InterlockedExchange (&_cleaning_up
, true);
173 cleanup_routine
*entry
= _routines_head
;
174 _routines_head
= NULL
;
179 cleanup_routine
*const ptr
= entry
;
180 entry
= entry
->_next
;
186 /*****************************************************************************/
189 process_cache::submission_loop::request_loop ()
193 assert (_interrupt_event
);
196 _cache
->wait_for_processes (_interrupt_event
);
199 /*****************************************************************************/
201 process_cache::process_cache (const size_t max_procs
,
202 const unsigned int initial_workers
)
203 : _queue (initial_workers
),
204 _submitter (this, &_queue
), // true == interruptible
205 _processes_count (0),
206 _max_process_count (max_procs
),
207 _processes_head (NULL
),
208 _cache_add_trigger (NULL
)
210 /* there can only be one */
211 InitializeCriticalSection (&_cache_write_access
);
213 _cache_add_trigger
= CreateEvent (NULL
, // SECURITY_ATTRIBUTES
214 TRUE
, // Manual-reset
215 FALSE
, // Initially non-signalled
218 if (!_cache_add_trigger
)
220 system_printf ("failed to create cache add trigger, error = %u",
225 _queue
.add_submission_loop (&_submitter
);
228 process_cache::~process_cache ()
230 (void) CloseHandle (_cache_add_trigger
);
231 DeleteCriticalSection (&_cache_write_access
);
234 /* This returns the process object to the caller already locked, that
235 * is, with the object's `access' critical region entered. Thus the
236 * caller must unlock the object when it's finished with it (via
237 * process::release ()). It must then not try to access the object
238 * afterwards, except by going through this routine again, as it may
239 * have been deleted once it has been unlocked.
242 process_cache::process (const pid_t cygpid
, const DWORD winpid
,
243 HANDLE signal_arrived
)
245 /* TODO: make this more granular, so a search doesn't involve the
248 EnterCriticalSection (&_cache_write_access
);
249 class process
*previous
= NULL
;
250 class process
*entry
= find (winpid
, &previous
);
254 if (_processes_count
>= _max_process_count
)
256 LeaveCriticalSection (&_cache_write_access
);
257 system_printf (("process limit (%d processes) reached; "
258 "new connection refused for %d(%u)"),
259 _max_process_count
, cygpid
, winpid
);
263 entry
= new class process (cygpid
, winpid
, signal_arrived
);
264 if (!entry
->is_active ())
266 LeaveCriticalSection (&_cache_write_access
);
273 entry
->_next
= previous
->_next
;
274 previous
->_next
= entry
;
278 entry
->_next
= _processes_head
;
279 _processes_head
= entry
;
282 _processes_count
+= 1;
283 SetEvent (_cache_add_trigger
);
286 entry
->hold (); // To be released by the caller.
287 LeaveCriticalSection (&_cache_write_access
);
289 assert (entry
->_winpid
== winpid
);
301 pcache_wait_thread (const LPVOID param
)
303 pcache_wait_t
*p
= (pcache_wait_t
*) param
;
305 DWORD rc
= WaitForMultipleObjects (p
->count
, p
->hdls
, FALSE
, INFINITE
);
306 ExitThread (rc
== WAIT_FAILED
? rc
: rc
+ p
->index
);
310 process_cache::wait_for_processes (const HANDLE interrupt_event
)
312 // Update `_wait_array' with handles of all current processes.
314 const size_t count
= sync_wait_array (interrupt_event
);
316 debug_printf ("waiting on %u objects in total (%u processes)",
317 count
, _processes_count
);
319 DWORD rc
= WAIT_FAILED
;
323 /* If count <= 64, a single WaitForMultipleObjects is sufficient and
324 we can simply wait in the main thread. */
325 rc
= WaitForMultipleObjects (count
, _wait_array
, FALSE
, INFINITE
);
326 if (rc
== WAIT_FAILED
)
328 system_printf ("could not wait on the process handles, error = %u",
335 /* If count > 64 we have to create sub-threads which wait for the
336 actual wait objects and the main thread waits for the termination
337 of one of the threads. */
338 HANDLE main_wait_array
[5] = { NULL
};
341 for (idx
= 0; idx
< count
; idx
+= 64)
343 pcache_wait_t p
= { idx
, min (count
- idx
, 64), _wait_array
+ idx
};
344 main_wait_array
[mcount
++] = CreateThread (NULL
, 0, pcache_wait_thread
,
348 rc
= WaitForMultipleObjects (mcount
, main_wait_array
, FALSE
, INFINITE
);
349 if (rc
== WAIT_FAILED
)
351 system_printf ("could not wait on the process handles, error = %u",
356 /* Check for error condition on signalled sub-thread. */
357 GetExitCodeThread (main_wait_array
[rc
], &rc
);
358 if (rc
== WAIT_FAILED
)
360 system_printf ("could not wait on the process handles, error = %u",
365 /* Wake up all waiting threads. _cache_add_trigger gets reset
366 in sync_wait_array again. */
367 SetEvent (_cache_add_trigger
);
368 WaitForMultipleObjects (mcount
, main_wait_array
, TRUE
, INFINITE
);
369 for (idx
= 0; idx
< mcount
; idx
++)
370 CloseHandle (main_wait_array
[idx
]);
373 /* Tell all processes the bad news. This one formerly only checked
374 processes beginning with the index of the signalled process, but
375 this can result in processes which are signalled but never removed
376 under heavy load conditions. */
377 for (idx
= 0; idx
< count
; idx
++)
378 if (_process_array
[idx
])
379 check_and_remove_process (idx
);
383 * process_cache::sync_wait_array ()
385 * Fill-in the wait array with the handles that the cache needs to wait on.
387 * - the process_process_param's interrupt event
388 * - the process_cache's cache_add_trigger event
389 * - the handle for each live process in the cache.
391 * Return value: the number of live handles in the array.
395 process_cache::sync_wait_array (const HANDLE interrupt_event
)
398 assert (interrupt_event
&& interrupt_event
!= INVALID_HANDLE_VALUE
);
400 /* Always reset _cache_add_trigger before filling up the array again. */
401 ResetEvent (_cache_add_trigger
);
403 EnterCriticalSection (&_cache_write_access
);
407 for (class process
*ptr
= _processes_head
; ptr
; ptr
= ptr
->_next
)
409 assert (ptr
->_hProcess
&& ptr
->_hProcess
!= INVALID_HANDLE_VALUE
);
410 assert (ptr
->is_active ());
412 _wait_array
[index
] = ptr
->handle ();
413 _process_array
[index
++] = ptr
;
415 if (!ptr
->_next
|| index
% 64 == 62)
417 /* Added at the end of each thread's array part for efficiency. */
418 _wait_array
[index
] = interrupt_event
;
419 _process_array
[index
++] = NULL
;
420 _wait_array
[index
] = _cache_add_trigger
;
421 _process_array
[index
++] = NULL
;
427 /* To get at least *something* to wait for. */
428 _wait_array
[index
] = interrupt_event
;
429 _process_array
[index
++] = NULL
;
430 _wait_array
[index
] = _cache_add_trigger
;
431 _process_array
[index
++] = NULL
;
434 assert (index
<= elements (_wait_array
));
436 LeaveCriticalSection (&_cache_write_access
);
442 process_cache::check_and_remove_process (const size_t index
)
445 assert (index
< elements (_wait_array
) - SPECIALS_COUNT
);
447 class process
*const process
= _process_array
[index
];
450 assert (process
->handle () == _wait_array
[index
]);
452 if (process
->check_exit_code () == STILL_ACTIVE
)
455 debug_printf ("process %d(%u) has left the building ($? = %u)",
456 process
->_cygpid
, process
->_winpid
, process
->_exit_status
);
458 /* Unlink the process object from the process list. */
460 EnterCriticalSection (&_cache_write_access
);
462 class process
*previous
= NULL
;
464 const class process
*const tmp
= find (process
->_winpid
, &previous
);
466 assert (tmp
== process
);
467 assert (previous
? previous
->_next
== process
: _processes_head
== process
);
470 previous
->_next
= process
->_next
;
472 _processes_head
= process
->_next
;
474 _processes_count
-= 1;
475 LeaveCriticalSection (&_cache_write_access
);
477 /* Schedule any cleanup tasks for this process. */
478 _queue
.add (new process_cleanup (process
));
482 process_cache::find (const DWORD winpid
, class process
**previous
)
487 for (class process
*ptr
= _processes_head
; ptr
; ptr
= ptr
->_next
)
488 if (ptr
->_winpid
== winpid
)
490 else if (ptr
->_winpid
> winpid
) // The list is sorted by winpid.
498 /*****************************************************************************/
499 #endif /* __OUTSIDE_CYGWIN__ */
This page took 0.056646 seconds and 5 git commands to generate.