]>
sourceware.org Git - newlib-cygwin.git/blob - winsup/cygserver/process.cc
3 Copyright 2001, 2002, 2003, 2004, 2005 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(%lu)",
57 _hProcess
= INVALID_HANDLE_VALUE
;
61 debug_printf ("got handle %p for new cache process %d(%lu)",
62 _hProcess
, _cygpid
, _winpid
);
64 system_printf ("signal_arrived NULL for process %d(%lu)",
66 else if (signal_arrived
!= INVALID_HANDLE_VALUE
)
68 if (!DuplicateHandle (_hProcess
, signal_arrived
,
69 GetCurrentProcess (), &_signal_arrived
,
70 0, FALSE
, DUPLICATE_SAME_ACCESS
))
71 system_printf ("error getting signal_arrived to server (%lu)",
73 _signal_arrived
= INVALID_HANDLE_VALUE
;
75 InitializeCriticalSection (&_access
);
76 debug ("initialized (%lu)", _cygpid
);
81 debug ("deleting (%lu)", _cygpid
);
82 DeleteCriticalSection (&_access
);
83 CloseHandle (_signal_arrived
);
84 CloseHandle (_hProcess
);
87 /* No need to be thread-safe as this is only ever called by
88 * process_cache::remove_process (). If it has to be made thread-safe
89 * later on, it should not use the `access' critical section as that
90 * is held by the client request handlers for an arbitrary length of
91 * time, i.e. while they do whatever processing is required for a
95 process::check_exit_code ()
97 if (_hProcess
&& _hProcess
!= INVALID_HANDLE_VALUE
98 && _exit_status
== STILL_ACTIVE
99 && !GetExitCodeProcess (_hProcess
, &_exit_status
))
101 system_printf ("failed to retrieve exit code for %d(%lu), error = %lu",
102 _cygpid
, _winpid
, GetLastError ());
103 _hProcess
= INVALID_HANDLE_VALUE
;
109 process::add (cleanup_routine
*const entry
)
118 entry
->_next
= _routines_head
;
119 _routines_head
= entry
;
128 process::remove (const cleanup_routine
*const entry
)
137 cleanup_routine
*previous
= NULL
;
139 for (cleanup_routine
*ptr
= _routines_head
;
141 previous
= ptr
, ptr
= ptr
->_next
)
146 previous
->_next
= ptr
->_next
;
148 _routines_head
= ptr
->_next
;
161 /* This is single threaded. It's called after the process is removed
162 * from the cache, but inserts may be attemped by worker threads that
163 * have a pointer to it.
169 assert (!is_active ());
170 assert (!_cleaning_up
);
171 InterlockedExchange (&_cleaning_up
, true);
172 cleanup_routine
*entry
= _routines_head
;
173 _routines_head
= NULL
;
178 cleanup_routine
*const ptr
= entry
;
179 entry
= entry
->_next
;
185 /*****************************************************************************/
188 process_cache::submission_loop::request_loop ()
192 assert (_interrupt_event
);
195 _cache
->wait_for_processes (_interrupt_event
);
198 /*****************************************************************************/
200 process_cache::process_cache (const unsigned int initial_workers
)
201 : _queue (initial_workers
),
202 _submitter (this, &_queue
), // true == interruptible
203 _processes_count (0),
204 _processes_head (NULL
),
205 _cache_add_trigger (NULL
)
207 /* there can only be one */
208 InitializeCriticalSection (&_cache_write_access
);
210 _cache_add_trigger
= CreateEvent (NULL
, // SECURITY_ATTRIBUTES
212 FALSE
, // Initially non-signalled
215 if (!_cache_add_trigger
)
217 system_printf ("failed to create cache add trigger, error = %lu",
222 _queue
.add_submission_loop (&_submitter
);
225 process_cache::~process_cache ()
227 (void) CloseHandle (_cache_add_trigger
);
228 DeleteCriticalSection (&_cache_write_access
);
231 /* This returns the process object to the caller already locked, that
232 * is, with the object's `access' critical region entered. Thus the
233 * caller must unlock the object when it's finished with it (via
234 * process::release ()). It must then not try to access the object
235 * afterwards, except by going through this routine again, as it may
236 * have been deleted once it has been unlocked.
239 process_cache::process (const pid_t cygpid
, const DWORD winpid
,
240 HANDLE signal_arrived
)
242 /* TODO: make this more granular, so a search doesn't involve the
245 EnterCriticalSection (&_cache_write_access
);
246 class process
*previous
= NULL
;
247 class process
*entry
= find (winpid
, &previous
);
251 if (_processes_count
+ SPECIALS_COUNT
>= MAXIMUM_WAIT_OBJECTS
)
253 LeaveCriticalSection (&_cache_write_access
);
254 system_printf (("process limit (%d processes) reached; "
255 "new connection refused for %d(%lu)"),
256 MAXIMUM_WAIT_OBJECTS
- SPECIALS_COUNT
,
261 entry
= new class process (cygpid
, winpid
, signal_arrived
);
262 if (!entry
->is_active ())
264 LeaveCriticalSection (&_cache_write_access
);
271 entry
->_next
= previous
->_next
;
272 previous
->_next
= entry
;
276 entry
->_next
= _processes_head
;
277 _processes_head
= entry
;
280 _processes_count
+= 1;
281 SetEvent (_cache_add_trigger
);
284 entry
->hold (); // To be released by the caller.
285 LeaveCriticalSection (&_cache_write_access
);
287 assert (entry
->_winpid
== winpid
);
292 process_cache::wait_for_processes (const HANDLE interrupt_event
)
294 // Update `_wait_array' with handles of all current processes.
295 const size_t count
= sync_wait_array (interrupt_event
);
297 debug_printf ("waiting on %u objects in total (%u processes)",
298 count
, _processes_count
);
300 const DWORD rc
= WaitForMultipleObjects (count
, _wait_array
,
303 if (rc
== WAIT_FAILED
)
305 system_printf ("could not wait on the process handles, error = %lu",
310 const size_t start
= rc
- WAIT_OBJECT_0
;
312 if (rc
< WAIT_OBJECT_0
|| start
> count
)
314 system_printf (("unexpected return code %rc "
315 "from WaitForMultipleObjects: "
316 "expected [%u .. %u)"),
317 rc
, WAIT_OBJECT_0
, WAIT_OBJECT_0
+ count
);
321 // Tell all the processes, from the signalled point up, the bad news.
322 for (size_t index
= start
; index
!= count
; index
++)
323 if (_process_array
[index
])
324 check_and_remove_process (index
);
328 * process_cache::sync_wait_array ()
330 * Fill-in the wait array with the handles that the cache needs to wait on.
332 * - the process_process_param's interrupt event
333 * - the process_cache's cache_add_trigger event
334 * - the handle for each live process in the cache.
336 * Return value: the number of live handles in the array.
340 process_cache::sync_wait_array (const HANDLE interrupt_event
)
343 assert (_cache_add_trigger
&& _cache_add_trigger
!= INVALID_HANDLE_VALUE
);
344 assert (interrupt_event
&& interrupt_event
!= INVALID_HANDLE_VALUE
);
346 EnterCriticalSection (&_cache_write_access
);
348 assert (_processes_count
+ SPECIALS_COUNT
<= elements (_wait_array
));
352 for (class process
*ptr
= _processes_head
; ptr
; ptr
= ptr
->_next
)
354 assert (ptr
->_hProcess
&& ptr
->_hProcess
!= INVALID_HANDLE_VALUE
);
355 assert (ptr
->is_active ());
357 _wait_array
[index
] = ptr
->handle ();
358 _process_array
[index
++] = ptr
;
360 assert (index
<= elements (_wait_array
));
363 /* Sorry for shouting, but THESE MUST BE ADDED AT THE END! */
364 /* Well, not strictly `must', but it's more efficient if they are :-) */
366 _wait_array
[index
] = interrupt_event
;
367 _process_array
[index
++] = NULL
;
369 _wait_array
[index
] = _cache_add_trigger
;
370 _process_array
[index
++] = NULL
;
372 /* Phew, back to normal volume now. */
374 assert (index
<= elements (_wait_array
));
376 LeaveCriticalSection (&_cache_write_access
);
382 process_cache::check_and_remove_process (const size_t index
)
385 assert (index
< elements (_wait_array
) - SPECIALS_COUNT
);
387 class process
*const process
= _process_array
[index
];
390 assert (process
->handle () == _wait_array
[index
]);
392 if (process
->check_exit_code () == STILL_ACTIVE
)
395 debug_printf ("process %d(%lu) has left the building ($? = %lu)",
396 process
->_cygpid
, process
->_winpid
, process
->_exit_status
);
398 /* Unlink the process object from the process list. */
400 EnterCriticalSection (&_cache_write_access
);
402 class process
*previous
= NULL
;
404 const class process
*const tmp
= find (process
->_winpid
, &previous
);
406 assert (tmp
== process
);
407 assert (previous
? previous
->_next
== process
: _processes_head
== process
);
410 previous
->_next
= process
->_next
;
412 _processes_head
= process
->_next
;
414 _processes_count
-= 1;
415 LeaveCriticalSection (&_cache_write_access
);
417 /* Schedule any cleanup tasks for this process. */
418 _queue
.add (new process_cleanup (process
));
422 process_cache::find (const DWORD winpid
, class process
**previous
)
427 for (class process
*ptr
= _processes_head
; ptr
; ptr
= ptr
->_next
)
428 if (ptr
->_winpid
== winpid
)
430 else if (ptr
->_winpid
> winpid
) // The list is sorted by winpid.
438 /*****************************************************************************/
439 #endif /* __OUTSIDE_CYGWIN__ */
This page took 0.053138 seconds and 5 git commands to generate.