diff options
-rw-r--r-- | winsup/cygwin/ChangeLog | 29 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver_process.cc | 68 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver_shm.cc | 68 | ||||
-rwxr-xr-x | winsup/cygwin/include/cygwin/cygserver_process.h | 21 |
4 files changed, 152 insertions, 34 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index d046421b1be..9ae7afc6d0a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,5 +1,34 @@ 2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com> + * include/cygwin/cygserver_process.h + (cleanup_routine::_key): New field. + (cleanup_routine::cleanup_routine): Initialise new field with new + argument. + (cleanup_routine::operator==): New method. + (cleanup_routine::cleanup): Make argument non-const. + (process::is_active): New method. + (process::remove): Ditto. + (process::check_exit_code): Rename method. + * cygserver_process.cc (process::add): Reorganize code. + (process::remove): New method. + (process::check_exit_code): Rename method. + (process::cleanup): Use new `process::is_active' method. + (process_cache::process): Ditto. + (process_cache::sync_wait_array): Ditto. + (process_cache::check_and_remove_process): Ditto. + * cygserver_shm.cc (server_shmmgr): Make `cleanup_t' a friend. + (segment_t::detach): Make argument non-const. Remove cleanup + object from client if appropriate. + (cleanup_t::_segptr): Remove field. + (cleanup_t::cleanup_t): Initialise parent explicitly. Remove + field. + (cleanup_t::segptr): New method. + (cleanup_t::cleanup): Add error checking and reporting. + (server_shmmgr::shmdt): Make argument non-const. + (server_shmmgr::find): New method. + +2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com> + * cygserver.cc (client_request_shutdown::client_request_shutdown): Comment out verbose tracing statement. * cygserver_client.cc diff --git a/winsup/cygwin/cygserver_process.cc b/winsup/cygwin/cygserver_process.cc index 679319f0c5c..99eb35acabb 100755 --- a/winsup/cygwin/cygserver_process.cc +++ b/winsup/cygwin/cygserver_process.cc @@ -85,7 +85,7 @@ process::~process () * client request. */ DWORD -process::exit_code () +process::check_exit_code () { if (_hProcess && _hProcess != INVALID_HANDLE_VALUE && _exit_status == STILL_ACTIVE @@ -99,26 +99,56 @@ process::exit_code () } bool -process::add (cleanup_routine *const new_cleanup) +process::add (cleanup_routine *const entry) { - assert (new_cleanup); + assert (entry); - if (_cleaning_up) - return false; + bool res = false; EnterCriticalSection (&_access); - /* Check that we didn't block with ::cleanup (). This rigmarole is - * to get around win9x's glaring missing TryEnterCriticalSection - * call which would be a whole lot easier. - */ - if (_cleaning_up) + + if (!_cleaning_up) { - LeaveCriticalSection (&_access); - return false; + entry->_next = _routines_head; + _routines_head = entry; + res = true; } - new_cleanup->_next = _routines_head; - _routines_head = new_cleanup; + + LeaveCriticalSection (&_access); + return res; +} + +bool +process::remove (const cleanup_routine *const entry) +{ + assert (entry); + + bool res = false; + EnterCriticalSection (&_access); + + 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; + + safe_delete (cleanup_routine, ptr); + res = true; + break; + } + } + } + LeaveCriticalSection (&_access); - return true; + return res; } /* This is single threaded. It's called after the process is removed @@ -129,7 +159,7 @@ void process::cleanup () { EnterCriticalSection (&_access); - assert (_exit_status != STILL_ACTIVE); + assert (!is_active ()); assert (!_cleaning_up); InterlockedExchange (&_cleaning_up, true); cleanup_routine *entry = _routines_head; @@ -222,7 +252,7 @@ process_cache::process (const pid_t cygpid, const DWORD winpid) } entry = safe_new (class process, cygpid, winpid); - if (entry->_exit_status != STILL_ACTIVE) + if (!entry->is_active ()) { LeaveCriticalSection (&_cache_write_access); safe_delete (process, entry); @@ -316,7 +346,7 @@ process_cache::sync_wait_array (const HANDLE interrupt_event) for (class process *ptr = _processes_head; ptr; ptr = ptr->_next) { assert (ptr->_hProcess && ptr->_hProcess != INVALID_HANDLE_VALUE); - assert (ptr->_exit_status == STILL_ACTIVE); + assert (ptr->is_active ()); _wait_array[index] = ptr->handle (); _process_array[index++] = ptr; @@ -353,7 +383,7 @@ process_cache::check_and_remove_process (const size_t index) assert (process); assert (process->handle () == _wait_array[index]); - if (process->exit_code () == STILL_ACTIVE) + if (process->check_exit_code () == STILL_ACTIVE) return; debug_printf ("process %d(%lu) has left the building ($? = %lu)", diff --git a/winsup/cygwin/cygserver_shm.cc b/winsup/cygwin/cygserver_shm.cc index 77a7baa36b1..3d0123e1ead 100755 --- a/winsup/cygwin/cygserver_shm.cc +++ b/winsup/cygwin/cygserver_shm.cc @@ -79,6 +79,9 @@ details. */ class server_shmmgr { + class cleanup_t; + friend class cleanup_t; + private: class attach_t { @@ -129,7 +132,7 @@ private: } int attach (class process *, HANDLE & hFileMap); - int detach (const class process *); + int detach (class process *); private: static long _sequence; @@ -145,20 +148,27 @@ private: { public: cleanup_t (segment_t *const segptr) - : _segptr (segptr) + : cleanup_routine (segptr) { - assert (_segptr); + assert (key ()); } - virtual void cleanup (const class process *const client) + segment_t *segptr () { return static_cast<segment_t *>(key ()); } + + virtual void cleanup (class process *const client) { - assert (_segptr); + assert (segptr ()); - shmmgr.shmdt (_segptr->_shmid, client); - } + if (!shmmgr.find (segptr ())) + debug_printf ("process cleanup called for non-existent segment"); + else + { + const int res = shmmgr.shmdt (segptr ()->_shmid, client); - private: - segment_t *const _segptr; + if (res != 0) + debug_printf ("process cleanup failed: %s", strerror (-res)); + } + } }; public: @@ -170,7 +180,7 @@ public: struct shminfo & out_shminfo, struct shm_info & out_shm_info, const int shmid, int cmd, const struct shmid_ds &, class process *); - int shmdt (int shmid, const class process *); + int shmdt (int shmid, class process *); int shmget (int & out_shmid, key_t, size_t, int shmflg, uid_t, gid_t, class process *); @@ -198,6 +208,8 @@ private: segment_t *find_by_key (key_t); segment_t *find (int intid, segment_t **previous = NULL); + const segment_t *find (const segment_t *) const; + int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t); segment_t *new_segment (key_t, size_t, HANDLE); @@ -316,7 +328,7 @@ server_shmmgr::segment_t::attach (class process *const client, *---------------------------------------------------------------------------*/ int -server_shmmgr::segment_t::detach (const class process *const client) +server_shmmgr::segment_t::detach (class process *const client) { attach_t *previous = NULL; attach_t *const attptr = find (client, &previous); @@ -324,6 +336,17 @@ server_shmmgr::segment_t::detach (const class process *const client) if (!attptr) return -EINVAL; + if (client->is_active ()) + { + const cleanup_t key (this); + + if (!client->remove (&key)) + syscall_printf (("failed to remove cleanup routine for %d(%lu) " + "[shmid = %d]"), + client->cygpid (), client->winpid (), + _shmid); + } + attptr->_refcnt -= 1; if (!attptr->_refcnt) @@ -540,7 +563,7 @@ server_shmmgr::shmctl (int & out_shmid, *---------------------------------------------------------------------------*/ int -server_shmmgr::shmdt (const int shmid, const class process *const client) +server_shmmgr::shmdt (const int shmid, class process *const client) { syscall_printf ("shmdt (shmid = %d) for %d(%lu)", shmid, client->cygpid (), client->winpid ()); @@ -714,6 +737,27 @@ server_shmmgr::find (const int intid, segment_t **previous) return NULL; } + +/*---------------------------------------------------------------------------* + * server_shmmgr::find () + * + * Used to check that a segptr is still valid. Since it may just be a + * random blob of memory, the routine doesn't try to access any of the + * "object's" fields. + *---------------------------------------------------------------------------*/ + +const server_shmmgr::segment_t * +server_shmmgr::find (const segment_t *segptr) const +{ + assert (segptr); + + for (segment_t *ptr = _segments_head; ptr; ptr = ptr->_next) + if (ptr == segptr) + return segptr; + + return NULL; +} + /*---------------------------------------------------------------------------* * server_shmmgr::new_segment () *---------------------------------------------------------------------------*/ diff --git a/winsup/cygwin/include/cygwin/cygserver_process.h b/winsup/cygwin/include/cygwin/cygserver_process.h index c3c2fa657e5..0706d501e11 100755 --- a/winsup/cygwin/include/cygwin/cygserver_process.h +++ b/winsup/cygwin/include/cygwin/cygserver_process.h @@ -41,13 +41,25 @@ class cleanup_routine friend class process; public: - cleanup_routine () : _next (NULL) {} + cleanup_routine (void *const key) + : _key (key), + _next (NULL) + {} + virtual ~cleanup_routine (); + bool operator== (const cleanup_routine &rhs) const + { + return _key == rhs._key; + } + + void *key () { return _key; } + /* MUST BE SYNCHRONOUS */ - virtual void cleanup (const class process *) = 0; + virtual void cleanup (class process *) = 0; private: + void *const _key; cleanup_routine *_next; }; @@ -66,10 +78,13 @@ public: DWORD winpid () const { return _winpid; } HANDLE handle () const { return _hProcess; } + bool is_active () const { return _exit_status == STILL_ACTIVE; } + void hold () { EnterCriticalSection (&_access); } void release () { LeaveCriticalSection (&_access); } bool add (cleanup_routine *); + bool remove (const cleanup_routine *); private: const pid_t _cygpid; @@ -82,7 +97,7 @@ private: CRITICAL_SECTION _access; class process *_next; - DWORD exit_code (); + DWORD check_exit_code (); void cleanup (); }; |