OSDN Git Service

Don't use safe_new but new throughout. Fix copyright dates
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygserver / process.cc
1 /* process.cc
2
3    Copyright 2001, 2002 Red Hat Inc.
4
5    Written by Robert Collins <rbtcollins@hotmail.com>
6
7 This file is part of Cygwin.
8
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
11 details. */
12
13 #include "woutsup.h"
14
15 #include <sys/types.h>
16
17 #include <assert.h>
18 #include <stdlib.h>
19
20 #include "cygerrno.h"
21
22 #include "process.h"
23
24 /*****************************************************************************/
25
26 #define elements(ARRAY) (sizeof (ARRAY) / sizeof (*ARRAY))
27
28 /*****************************************************************************/
29
30 process_cleanup::~process_cleanup ()
31 {
32   delete _process;
33 }
34
35 void
36 process_cleanup::process ()
37 {
38   _process->cleanup ();
39 }
40
41 /*****************************************************************************/
42
43 /* cleanup_routine */
44 cleanup_routine::~cleanup_routine ()
45 {
46 }
47
48 /*****************************************************************************/
49
50 process::process (const pid_t cygpid, const DWORD winpid)
51   : _cygpid (cygpid),
52     _winpid (winpid),
53     _hProcess (NULL),
54     _cleaning_up (false),
55     _exit_status (STILL_ACTIVE),
56     _routines_head (NULL),
57     _next (NULL)
58 {
59   _hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, winpid);
60   if (!_hProcess)
61     {
62       system_printf ("unable to obtain handle for new cache process %d(%lu)",
63                      _cygpid, _winpid);
64       _hProcess = INVALID_HANDLE_VALUE;
65       _exit_status = 0;
66     }
67   else
68     debug_printf ("got handle %p for new cache process %d(%lu)",
69                   _hProcess, _cygpid, _winpid);
70   InitializeCriticalSection (&_access);
71 }
72
73 process::~process ()
74 {
75   DeleteCriticalSection (&_access);
76   (void) CloseHandle (_hProcess);
77 }
78
79 /* No need to be thread-safe as this is only ever called by
80  * process_cache::remove_process ().  If it has to be made thread-safe
81  * later on, it should not use the `access' critical section as that
82  * is held by the client request handlers for an arbitrary length of
83  * time, i.e. while they do whatever processing is required for a
84  * client request.
85  */
86 DWORD
87 process::check_exit_code ()
88 {
89   if (_hProcess && _hProcess != INVALID_HANDLE_VALUE
90       && _exit_status == STILL_ACTIVE
91       && !GetExitCodeProcess (_hProcess, &_exit_status))
92     {
93       system_printf ("failed to retrieve exit code for %d(%lu), error = %lu",
94                      _cygpid, _winpid, GetLastError ());
95       _hProcess = INVALID_HANDLE_VALUE;
96     }
97   return _exit_status;
98 }
99
100 bool
101 process::add (cleanup_routine *const entry)
102 {
103   assert (entry);
104
105   bool res = false;
106   EnterCriticalSection (&_access);
107
108   if (!_cleaning_up)
109     {
110       entry->_next = _routines_head;
111       _routines_head = entry;
112       res = true;
113     }
114
115   LeaveCriticalSection (&_access);
116   return res;
117 }
118
119 bool
120 process::remove (const cleanup_routine *const entry)
121 {
122   assert (entry);
123
124   bool res = false;
125   EnterCriticalSection (&_access);
126
127   if (!_cleaning_up)
128     {
129       cleanup_routine *previous = NULL;
130
131       for (cleanup_routine *ptr = _routines_head;
132            ptr;
133            previous = ptr, ptr = ptr->_next)
134         {
135           if (*ptr == *entry)
136             {
137               if (previous)
138                 previous->_next = ptr->_next;
139               else
140                 _routines_head = ptr->_next;
141
142               delete ptr;
143               res = true;
144               break;
145             }
146         }
147     }
148
149   LeaveCriticalSection (&_access);
150   return res;
151 }
152
153 /* This is single threaded. It's called after the process is removed
154  * from the cache, but inserts may be attemped by worker threads that
155  * have a pointer to it.
156  */
157 void
158 process::cleanup ()
159 {
160   EnterCriticalSection (&_access);
161   assert (!is_active ());
162   assert (!_cleaning_up);
163   InterlockedExchange (&_cleaning_up, true);
164   cleanup_routine *entry = _routines_head;
165   _routines_head = NULL;
166   LeaveCriticalSection (&_access);
167
168   while (entry)
169     {
170       cleanup_routine *const ptr = entry;
171       entry = entry->_next;
172       ptr->cleanup (this);
173       delete ptr;
174     }
175 }
176
177 /*****************************************************************************/
178
179 void
180 process_cache::submission_loop::request_loop ()
181 {
182   assert (this);
183   assert (_cache);
184   assert (_interrupt_event);
185
186   while (_running)
187     _cache->wait_for_processes (_interrupt_event);
188 }
189
190 /*****************************************************************************/
191
192 process_cache::process_cache (const unsigned int initial_workers)
193   : _queue (initial_workers),
194     _submitter (this, &_queue), // true == interruptible
195     _processes_count (0),
196     _processes_head (NULL),
197     _cache_add_trigger (NULL)
198 {
199   /* there can only be one */
200   InitializeCriticalSection (&_cache_write_access);
201
202   _cache_add_trigger = CreateEvent (NULL,  // SECURITY_ATTRIBUTES
203                                     FALSE, // Auto-reset
204                                     FALSE, // Initially non-signalled
205                                     NULL); // Anonymous
206
207   if (!_cache_add_trigger)
208     {
209       system_printf ("failed to create cache add trigger, error = %lu",
210                      GetLastError ());
211       abort ();
212     }
213
214   _queue.add_submission_loop (&_submitter);
215 }
216
217 process_cache::~process_cache ()
218 {
219   (void) CloseHandle (_cache_add_trigger);
220   DeleteCriticalSection (&_cache_write_access);
221 }
222
223 /* This returns the process object to the caller already locked, that
224  * is, with the object's `access' critical region entered.  Thus the
225  * caller must unlock the object when it's finished with it (via
226  * process::release ()).  It must then not try to access the object
227  * afterwards, except by going through this routine again, as it may
228  * have been deleted once it has been unlocked.
229  */
230 class process *
231 process_cache::process (const pid_t cygpid, const DWORD winpid)
232 {
233   /* TODO: make this more granular, so a search doesn't involve the
234    * write lock.
235    */
236   EnterCriticalSection (&_cache_write_access);
237   class process *previous = NULL;
238   class process *entry = find (winpid, &previous);
239
240   if (!entry)
241     {
242       if (_processes_count + SPECIALS_COUNT >= MAXIMUM_WAIT_OBJECTS)
243         {
244           LeaveCriticalSection (&_cache_write_access);
245           system_printf (("process limit (%d processes) reached; "
246                           "new connection refused for %d(%lu)"),
247                          MAXIMUM_WAIT_OBJECTS - SPECIALS_COUNT,
248                          cygpid, winpid);
249           set_errno (EAGAIN);
250           return NULL;
251         }
252
253       entry = new class process (cygpid, winpid);
254       if (!entry->is_active ())
255         {
256           LeaveCriticalSection (&_cache_write_access);
257           delete entry;
258           set_errno (ESRCH);
259           return NULL;
260         }
261
262       if (previous)
263         {
264           entry->_next = previous->_next;
265           previous->_next = entry;
266         }
267       else
268         {
269           entry->_next = _processes_head;
270           _processes_head = entry;
271         }
272
273       _processes_count += 1;
274       SetEvent (_cache_add_trigger);
275     }
276
277   EnterCriticalSection (&entry->_access); // To be released by the caller.
278   LeaveCriticalSection (&_cache_write_access);
279   assert (entry);
280   assert (entry->_winpid == winpid);
281   return entry;
282 }
283
284 void
285 process_cache::wait_for_processes (const HANDLE interrupt_event)
286 {
287   // Update `_wait_array' with handles of all current processes.
288   const size_t count = sync_wait_array (interrupt_event);
289
290   debug_printf ("waiting on %u objects in total (%u processes)",
291                 count, _processes_count);
292
293   const DWORD rc = WaitForMultipleObjects (count, _wait_array,
294                                            FALSE, INFINITE);
295
296   if (rc == WAIT_FAILED)
297     {
298       system_printf ("could not wait on the process handles, error = %lu",
299                      GetLastError ());
300       abort ();
301     }
302
303   const size_t start = rc - WAIT_OBJECT_0;
304
305   if (rc < WAIT_OBJECT_0 || start > count)
306     {
307       system_printf (("unexpected return code %rc "
308                       "from WaitForMultipleObjects: "
309                       "expected [%u .. %u)"),
310                      rc, WAIT_OBJECT_0, WAIT_OBJECT_0 + count);
311       abort ();
312     }
313
314   // Tell all the processes, from the signalled point up, the bad news.
315   for (size_t index = start; index != count; index++)
316     if (_process_array[index])
317       check_and_remove_process (index);
318 }
319
320 /*
321  * process_cache::sync_wait_array ()
322  *
323  * Fill-in the wait array with the handles that the cache needs to wait on.
324  * These handles are:
325  *  - the process_process_param's interrupt event
326  *  - the process_cache's cache_add_trigger event
327  *  - the handle for each live process in the cache.
328  *
329  * Return value: the number of live handles in the array.
330  */
331
332 size_t
333 process_cache::sync_wait_array (const HANDLE interrupt_event)
334 {
335   assert (this);
336   assert (_cache_add_trigger && _cache_add_trigger != INVALID_HANDLE_VALUE);
337   assert (interrupt_event && interrupt_event != INVALID_HANDLE_VALUE);
338
339   EnterCriticalSection (&_cache_write_access);
340
341   assert (_processes_count + SPECIALS_COUNT <= elements (_wait_array));
342
343   size_t index = 0;
344
345   for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
346     {
347       assert (ptr->_hProcess && ptr->_hProcess != INVALID_HANDLE_VALUE);
348       assert (ptr->is_active ());
349
350       _wait_array[index] = ptr->handle ();
351       _process_array[index++] = ptr;
352
353       assert (index <= elements (_wait_array));
354     }
355
356   /* Sorry for shouting, but THESE MUST BE ADDED AT THE END! */
357   /* Well, not strictly `must', but it's more efficient if they are :-) */
358
359   _wait_array[index] = interrupt_event;
360   _process_array[index++] = NULL;
361
362   _wait_array[index] = _cache_add_trigger;
363   _process_array[index++] = NULL;
364
365   /* Phew, back to normal volume now. */
366
367   assert (index <= elements (_wait_array));
368
369   LeaveCriticalSection (&_cache_write_access);
370
371   return index;
372 }
373
374 void
375 process_cache::check_and_remove_process (const size_t index)
376 {
377   assert (this);
378   assert (index < elements (_wait_array) - SPECIALS_COUNT);
379
380   class process *const process = _process_array[index];
381
382   assert (process);
383   assert (process->handle () == _wait_array[index]);
384
385   if (process->check_exit_code () == STILL_ACTIVE)
386     return;
387
388   debug_printf ("process %d(%lu) has left the building ($? = %lu)",
389                 process->_cygpid, process->_winpid, process->_exit_status);
390
391   /* Unlink the process object from the process list. */
392
393   EnterCriticalSection (&_cache_write_access);
394
395   class process *previous = NULL;
396
397   const class process *const tmp = find (process->_winpid, &previous);
398
399   assert (tmp == process);
400   assert (previous ? previous->_next == process : _processes_head == process);
401
402   if (previous)
403     previous->_next = process->_next;
404   else
405     _processes_head = process->_next;
406
407   _processes_count -= 1;
408   LeaveCriticalSection (&_cache_write_access);
409
410   /* Schedule any cleanup tasks for this process. */
411   _queue.add (new process_cleanup (process));
412 }
413
414 class process *
415 process_cache::find (const DWORD winpid, class process **previous)
416 {
417   if (previous)
418     *previous = NULL;
419
420   for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
421     if (ptr->_winpid == winpid)
422       return ptr;
423     else if (ptr->_winpid > winpid) // The list is sorted by winpid.
424       return NULL;
425     else if (previous)
426       *previous = ptr;
427
428   return NULL;
429 }
430
431 /*****************************************************************************/