Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygserver/process.cc')
-rw-r--r--winsup/cygserver/process.cc500
1 files changed, 0 insertions, 500 deletions
diff --git a/winsup/cygserver/process.cc b/winsup/cygserver/process.cc
deleted file mode 100644
index cc665d88e..000000000
--- a/winsup/cygserver/process.cc
+++ /dev/null
@@ -1,500 +0,0 @@
-/* process.cc
-
- Copyright 2001, 2002, 2003, 2004, 2005 Red Hat Inc.
-
- Written by Robert Collins <rbtcollins@hotmail.com>
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#ifdef __OUTSIDE_CYGWIN__
-#include "woutsup.h"
-
-#include <sys/types.h>
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include "process.h"
-
-/*****************************************************************************/
-
-#define elements(ARRAY) (sizeof (ARRAY) / sizeof (*ARRAY))
-
-/*****************************************************************************/
-
-process_cleanup::~process_cleanup ()
-{
- delete _process;
-}
-
-void
-process_cleanup::process ()
-{
- _process->cleanup ();
-}
-
-/*****************************************************************************/
-
-process::process (const pid_t cygpid, const DWORD winpid, HANDLE signal_arrived)
- : _cygpid (cygpid),
- _winpid (winpid),
- _hProcess (NULL),
- _signal_arrived (INVALID_HANDLE_VALUE),
- _cleaning_up (false),
- _exit_status (STILL_ACTIVE),
- _routines_head (NULL),
- _next (NULL)
-{
- _hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, winpid);
- if (!_hProcess)
- {
- system_printf ("unable to obtain handle for new cache process %d(%lu)",
- _cygpid, _winpid);
- _hProcess = INVALID_HANDLE_VALUE;
- _exit_status = 0;
- }
- else
- debug_printf ("got handle %p for new cache process %d(%lu)",
- _hProcess, _cygpid, _winpid);
- if (!signal_arrived)
- system_printf ("signal_arrived NULL for process %d(%lu)",
- _cygpid, _winpid);
- else if (signal_arrived != INVALID_HANDLE_VALUE)
- {
- if (!DuplicateHandle (_hProcess, signal_arrived,
- GetCurrentProcess (), &_signal_arrived,
- 0, FALSE, DUPLICATE_SAME_ACCESS))
- {
- system_printf ("error getting signal_arrived to server (%lu)",
- GetLastError ());
- _signal_arrived = INVALID_HANDLE_VALUE;
- }
- }
- InitializeCriticalSection (&_access);
- debug ("initialized (%lu)", _cygpid);
-}
-
-process::~process ()
-{
- debug ("deleting (%lu)", _cygpid);
- DeleteCriticalSection (&_access);
- if (_signal_arrived && _signal_arrived != INVALID_HANDLE_VALUE)
- CloseHandle (_signal_arrived);
- CloseHandle (_hProcess);
-}
-
-/* No need to be thread-safe as this is only ever called by
- * process_cache::check_and_remove_process (). If it has to be made
- * thread-safe later on, it should not use the `access' critical section as
- * that is held by the client request handlers for an arbitrary length of time,
- * i.e. while they do whatever processing is required for a client request.
- */
-DWORD
-process::check_exit_code ()
-{
- if (_hProcess && _hProcess != INVALID_HANDLE_VALUE
- && _exit_status == STILL_ACTIVE
- && !GetExitCodeProcess (_hProcess, &_exit_status))
- {
- system_printf ("failed to retrieve exit code for %d(%lu), error = %lu",
- _cygpid, _winpid, GetLastError ());
- _hProcess = INVALID_HANDLE_VALUE;
- }
- return _exit_status;
-}
-
-bool
-process::add (cleanup_routine *const entry)
-{
- assert (entry);
-
- bool res = false;
- hold ();
-
- if (!_cleaning_up)
- {
- entry->_next = _routines_head;
- _routines_head = entry;
- res = true;
- }
-
- release ();
- return res;
-}
-
-bool
-process::remove (const cleanup_routine *const entry)
-{
- assert (entry);
-
- bool res = false;
- hold ();
-
- if (!_cleaning_up)
- {
- cleanup_routine *previous = NULL;
-
- for (cleanup_routine *ptr = _routines_head;
- ptr;
- previous = ptr, ptr = ptr->_next)
- {
- if (*ptr == *entry)
- {
- if (previous)
- previous->_next = ptr->_next;
- else
- _routines_head = ptr->_next;
-
- delete ptr;
- res = true;
- break;
- }
- }
- }
-
- release ();
- return res;
-}
-
-/* This is single threaded. It's called after the process is removed
- * from the cache, but inserts may be attemped by worker threads that
- * have a pointer to it.
- */
-void
-process::cleanup ()
-{
- hold ();
- assert (!is_active ());
- assert (!_cleaning_up);
- InterlockedExchange (&_cleaning_up, true);
- cleanup_routine *entry = _routines_head;
- _routines_head = NULL;
- release ();
-
- while (entry)
- {
- cleanup_routine *const ptr = entry;
- entry = entry->_next;
- ptr->cleanup (this);
- delete ptr;
- }
-}
-
-/*****************************************************************************/
-
-void
-process_cache::submission_loop::request_loop ()
-{
- assert (this);
- assert (_cache);
- assert (_interrupt_event);
-
- while (_running)
- _cache->wait_for_processes (_interrupt_event);
-}
-
-/*****************************************************************************/
-
-process_cache::process_cache (const size_t max_procs,
- const unsigned int initial_workers)
- : _queue (initial_workers),
- _submitter (this, &_queue), // true == interruptible
- _processes_count (0),
- _max_process_count (max_procs),
- _processes_head (NULL),
- _cache_add_trigger (NULL)
-{
- /* there can only be one */
- InitializeCriticalSection (&_cache_write_access);
-
- _cache_add_trigger = CreateEvent (NULL, // SECURITY_ATTRIBUTES
- TRUE, // Manual-reset
- FALSE, // Initially non-signalled
- NULL); // Anonymous
-
- if (!_cache_add_trigger)
- {
- system_printf ("failed to create cache add trigger, error = %lu",
- GetLastError ());
- abort ();
- }
-
- _queue.add_submission_loop (&_submitter);
-}
-
-process_cache::~process_cache ()
-{
- (void) CloseHandle (_cache_add_trigger);
- DeleteCriticalSection (&_cache_write_access);
-}
-
-/* This returns the process object to the caller already locked, that
- * is, with the object's `access' critical region entered. Thus the
- * caller must unlock the object when it's finished with it (via
- * process::release ()). It must then not try to access the object
- * afterwards, except by going through this routine again, as it may
- * have been deleted once it has been unlocked.
- */
-class process *
-process_cache::process (const pid_t cygpid, const DWORD winpid,
- HANDLE signal_arrived)
-{
- /* TODO: make this more granular, so a search doesn't involve the
- * write lock.
- */
- EnterCriticalSection (&_cache_write_access);
- class process *previous = NULL;
- class process *entry = find (winpid, &previous);
-
- if (!entry)
- {
- if (_processes_count >= _max_process_count)
- {
- LeaveCriticalSection (&_cache_write_access);
- system_printf (("process limit (%d processes) reached; "
- "new connection refused for %d(%lu)"),
- _max_process_count, cygpid, winpid);
- return NULL;
- }
-
- entry = new class process (cygpid, winpid, signal_arrived);
- if (!entry->is_active ())
- {
- LeaveCriticalSection (&_cache_write_access);
- delete entry;
- return NULL;
- }
-
- if (previous)
- {
- entry->_next = previous->_next;
- previous->_next = entry;
- }
- else
- {
- entry->_next = _processes_head;
- _processes_head = entry;
- }
-
- _processes_count += 1;
- SetEvent (_cache_add_trigger);
- }
-
- entry->hold (); // To be released by the caller.
- LeaveCriticalSection (&_cache_write_access);
- assert (entry);
- assert (entry->_winpid == winpid);
- return entry;
-}
-
-struct pcache_wait_t
-{
- size_t index;
- size_t count;
- HANDLE *hdls;
-};
-
-static DWORD WINAPI
-pcache_wait_thread (const LPVOID param)
-{
- pcache_wait_t *p = (pcache_wait_t *) param;
-
- DWORD rc = WaitForMultipleObjects (p->count, p->hdls, FALSE, INFINITE);
- ExitThread (rc == WAIT_FAILED ? rc : rc + p->index);
-}
-
-void
-process_cache::wait_for_processes (const HANDLE interrupt_event)
-{
- // Update `_wait_array' with handles of all current processes.
- size_t idx;
- const size_t count = sync_wait_array (interrupt_event);
-
- debug_printf ("waiting on %u objects in total (%u processes)",
- count, _processes_count);
-
- DWORD rc = WAIT_FAILED;
-
- if (count <= 64)
- {
- /* If count <= 64, a single WaitForMultipleObjects is sufficient and
- we can simply wait in the main thread. */
- rc = WaitForMultipleObjects (count, _wait_array, FALSE, INFINITE);
- if (rc == WAIT_FAILED)
- {
- system_printf ("could not wait on the process handles, error = %lu",
- GetLastError ());
- abort ();
- }
- }
- else
- {
- /* If count > 64 we have to create sub-threads which wait for the
- actual wait objects and the main thread waits for the termination
- of one of the threads. */
- HANDLE main_wait_array[5] = { NULL };
- DWORD mcount = 0;
-
- for (idx = 0; idx < count; idx += 64)
- {
- pcache_wait_t p = { idx, min (count - idx, 64), _wait_array + idx };
- main_wait_array[mcount++] = CreateThread (NULL, 0, pcache_wait_thread,
- &p, 0, NULL);
- }
-
- rc = WaitForMultipleObjects (mcount, main_wait_array, FALSE, INFINITE);
- if (rc == WAIT_FAILED)
- {
- system_printf ("could not wait on the process handles, error = %lu",
- GetLastError ());
- abort ();
- }
-
- /* Check for error condition on signalled sub-thread. */
- GetExitCodeThread (main_wait_array[rc], &rc);
- if (rc == WAIT_FAILED)
- {
- system_printf ("could not wait on the process handles, error = %lu",
- GetLastError ());
- abort ();
- }
-
- /* Wake up all waiting threads. _cache_add_trigger gets reset
- in sync_wait_array again. */
- SetEvent (_cache_add_trigger);
- WaitForMultipleObjects (mcount, main_wait_array, TRUE, INFINITE);
- for (idx = 0; idx < mcount; idx++)
- CloseHandle (main_wait_array[idx]);
- }
-
- /* Tell all processes the bad news. This one formerly only checked
- processes beginning with the index of the signalled process, but
- this can result in processes which are signalled but never removed
- under heavy load conditions. */
- for (idx = 0; idx < count; idx++)
- if (_process_array[idx])
- check_and_remove_process (idx);
-}
-
-/*
- * process_cache::sync_wait_array ()
- *
- * Fill-in the wait array with the handles that the cache needs to wait on.
- * These handles are:
- * - the process_process_param's interrupt event
- * - the process_cache's cache_add_trigger event
- * - the handle for each live process in the cache.
- *
- * Return value: the number of live handles in the array.
- */
-
-size_t
-process_cache::sync_wait_array (const HANDLE interrupt_event)
-{
- assert (this);
- assert (interrupt_event && interrupt_event != INVALID_HANDLE_VALUE);
-
- /* Always reset _cache_add_trigger before filling up the array again. */
- ResetEvent (_cache_add_trigger);
-
- EnterCriticalSection (&_cache_write_access);
-
- size_t index = 0;
-
- for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
- {
- assert (ptr->_hProcess && ptr->_hProcess != INVALID_HANDLE_VALUE);
- assert (ptr->is_active ());
-
- _wait_array[index] = ptr->handle ();
- _process_array[index++] = ptr;
-
- if (!ptr->_next || index % 64 == 62)
- {
- /* Added at the end of each thread's array part for efficiency. */
- _wait_array[index] = interrupt_event;
- _process_array[index++] = NULL;
- _wait_array[index] = _cache_add_trigger;
- _process_array[index++] = NULL;
- }
- }
-
- if (!index)
- {
- /* To get at least *something* to wait for. */
- _wait_array[index] = interrupt_event;
- _process_array[index++] = NULL;
- _wait_array[index] = _cache_add_trigger;
- _process_array[index++] = NULL;
- }
-
- assert (index <= elements (_wait_array));
-
- LeaveCriticalSection (&_cache_write_access);
-
- return index;
-}
-
-void
-process_cache::check_and_remove_process (const size_t index)
-{
- assert (this);
- assert (index < elements (_wait_array) - SPECIALS_COUNT);
-
- class process *const process = _process_array[index];
-
- assert (process);
- assert (process->handle () == _wait_array[index]);
-
- if (process->check_exit_code () == STILL_ACTIVE)
- return;
-
- debug_printf ("process %d(%lu) has left the building ($? = %lu)",
- process->_cygpid, process->_winpid, process->_exit_status);
-
- /* Unlink the process object from the process list. */
-
- EnterCriticalSection (&_cache_write_access);
-
- class process *previous = NULL;
-
- const class process *const tmp = find (process->_winpid, &previous);
-
- assert (tmp == process);
- assert (previous ? previous->_next == process : _processes_head == process);
-
- if (previous)
- previous->_next = process->_next;
- else
- _processes_head = process->_next;
-
- _processes_count -= 1;
- LeaveCriticalSection (&_cache_write_access);
-
- /* Schedule any cleanup tasks for this process. */
- _queue.add (new process_cleanup (process));
-}
-
-class process *
-process_cache::find (const DWORD winpid, class process **previous)
-{
- if (previous)
- *previous = NULL;
-
- for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
- if (ptr->_winpid == winpid)
- return ptr;
- else if (ptr->_winpid > winpid) // The list is sorted by winpid.
- return NULL;
- else if (previous)
- *previous = ptr;
-
- return NULL;
-}
-
-/*****************************************************************************/
-#endif /* __OUTSIDE_CYGWIN__ */