diff options
author | Robert Collins <rbtcollins@hotmail.com> | 2001-10-08 01:58:21 +0400 |
---|---|---|
committer | Robert Collins <rbtcollins@hotmail.com> | 2001-10-08 01:58:21 +0400 |
commit | 10caff1aadd69ebe7fbfba162dd23f6b2dc8b5a4 (patch) | |
tree | de0de67f94eae69042d5699059c3824df0bd0e9f /winsup/cygwin | |
parent | 02baf7ff76fe2853ff0e94dbea52164d60d67acf (diff) |
Mon Oct 8 7:41:00 2001 Robert Collins <rbtcollins@hotmail.com>
* cygserver.cc (server_request::process): Rename client_request_shm_get to
client_request_shm.
* cygserver_process.cc (process_cache::add): Rename to add_task.
Use process_cleanup instead of process_request.
(process_cache::remove_process): New method.
(process::process): Initialize new members.
(process::~process): New member.
(process::cleanup): New method.
(process::add_cleanup_routine): New method.
(process_request::process): Rename to process_cleanup.
Call the process object's cleanup method and then delete it.
(process_process_param::request_loop): Remove the signalling process.
* cygserver_shm.cc: Globally rename client_request_shm_get to client_request_shm.
(client_request_shm_get::serve): Handle attach request counting.
* cygserver_shm.h: Globally rename client_request_shm_get to client_request_shm.
(class shm_cleanup): New class.
* shm.cc: Globally rename client_request_shm_get to client_request_shm.
(client_request_shm::client_request_shm): New constructor for attach requests.
(shmat): Use it.
* include/cygwin/cygserver_process.h (class process_request): Rename to
process_cleanup.
(class cleanup_routine): New class.
(class process): New members and methods to allow calling back when the process
terminates.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r-- | winsup/cygwin/ChangeLog | 27 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver.cc | 2 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver_process.cc | 97 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver_shm.cc | 33 | ||||
-rw-r--r-- | winsup/cygwin/cygserver_shm.h | 18 | ||||
-rwxr-xr-x | winsup/cygwin/include/cygwin/cygserver_process.h | 27 | ||||
-rw-r--r-- | winsup/cygwin/shm.cc | 40 |
7 files changed, 214 insertions, 30 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 67ff204a7..59a42075d 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,30 @@ +Mon Oct 8 7:41:00 2001 Robert Collins <rbtcollins@hotmail.com> + + * cygserver.cc (server_request::process): Rename client_request_shm_get to + client_request_shm. + * cygserver_process.cc (process_cache::add): Rename to add_task. + Use process_cleanup instead of process_request. + (process_cache::remove_process): New method. + (process::process): Initialize new members. + (process::~process): New member. + (process::cleanup): New method. + (process::add_cleanup_routine): New method. + (process_request::process): Rename to process_cleanup. + Call the process object's cleanup method and then delete it. + (process_process_param::request_loop): Remove the signalling process. + * cygserver_shm.cc: Globally rename client_request_shm_get to client_request_shm. + (client_request_shm_get::serve): Handle attach request counting. + * cygserver_shm.h: Globally rename client_request_shm_get to client_request_shm. + (class shm_cleanup): New class. + * shm.cc: Globally rename client_request_shm_get to client_request_shm. + (client_request_shm::client_request_shm): New constructor for attach requests. + (shmat): Use it. + * include/cygwin/cygserver_process.h (class process_request): Rename to + process_cleanup. + (class cleanup_routine): New class. + (class process): New members and methods to allow calling back when the process + terminates. + Thu Oct 4 14:12:00 2001 Robert Collins <rbtcollins@hotmail.com> * cygserver.cc (request_loop): Make static. diff --git a/winsup/cygwin/cygserver.cc b/winsup/cygwin/cygserver.cc index b0b815beb..24a90dc20 100755 --- a/winsup/cygwin/cygserver.cc +++ b/winsup/cygwin/cygserver.cc @@ -370,7 +370,7 @@ server_request::process () case CYGSERVER_REQUEST_SHUTDOWN: req = new client_request_shutdown (); break; case CYGSERVER_REQUEST_SHM_GET: - req = new client_request_shm_get (); break; + req = new client_request_shm (); break; default: req = new client_request (CYGSERVER_REQUEST_INVALID, 0); req->header.error_code = ENOSYS; diff --git a/winsup/cygwin/cygserver_process.cc b/winsup/cygwin/cygserver_process.cc index fe5b5b80b..a5173afd3 100755 --- a/winsup/cygwin/cygserver_process.cc +++ b/winsup/cygwin/cygserver_process.cc @@ -95,18 +95,50 @@ process_cache::process_requests () } void -process_cache::add () +process_cache::add_task (class process * theprocess) { /* safe to not "Try" because workers don't hog this, they wait on the event */ /* every derived ::add must enter the section! */ EnterCriticalSection (&queuelock); - queue_request *listrequest = new process_request; + queue_request *listrequest = new process_cleanup (theprocess); threaded_queue::add (listrequest); LeaveCriticalSection (&queuelock); } - +/* NOT fully MT SAFE: must be called by only one thread in a program */ +void +process_cache::remove_process (class process *theprocess) +{ + class process *entry = head; + /* unlink */ + EnterCriticalSection (&cache_write_access); + if (entry == theprocess) + { + entry = (class process *) InterlockedExchangePointer (&head, theprocess->next); + if (entry != theprocess) + { + printf ("Bug encountered, process cache corrupted\n"); + exit (1); + } + } + else + { + while (entry->next && entry->next != theprocess) + entry = entry->next; + class process *temp = (class process *) InterlockedExchangePointer (&entry->next, theprocess->next); + if (temp != theprocess) + { + printf ("Bug encountered, process cache corrupted\n"); + exit (1); + } + } + LeaveCriticalSection (&cache_write_access); + /* Process any cleanup tasks */ + add_task (theprocess); +} + + /* copy <= max_copy HANDLEs to dest[], starting at an offset into _our list_ of * begin_at. (Ie begin_at = 5, the first copied handle is still written to dest[0] * NOTE: Thread safe, but not thread guaranteed - a newly added process may be missed. @@ -148,6 +180,7 @@ process_cache::handle_snapshot (HANDLE * hdest, class process ** edest, } /* process's */ +/* global process crit section */ static CRITICAL_SECTION process_access; static pthread_once_t process_init; @@ -159,7 +192,7 @@ do_process_init (void) } process::process (long pid): -winpid (pid), next (NULL), _exit_status (STILL_ACTIVE) +winpid (pid), next (NULL), cleaning_up (0), head (NULL), _exit_status (STILL_ACTIVE) { pthread_once (&process_init, do_process_init); EnterCriticalSection (&process_access); @@ -170,9 +203,15 @@ winpid (pid), next (NULL), _exit_status (STILL_ACTIVE) thehandle = INVALID_HANDLE_VALUE; } debug_printf ("Got handle %p for new cache process %ld\n", thehandle, pid); + InitializeCriticalSection (&access); LeaveCriticalSection (&process_access); } +process::~process () +{ + DeleteCriticalSection (&access); +} + HANDLE process::handle () { @@ -216,11 +255,53 @@ DWORD process::exit_code () return _exit_status; } -/* process_request */ +/* 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 () +{ + /* Serialize this */ + EnterCriticalSection (&access); + InterlockedIncrement (&(long)cleaning_up); + class cleanup_routine *entry = head; + while (entry) + { + class cleanup_routine *temp; + entry->cleanup (winpid); + temp = entry->next; + delete entry; + entry = temp; + } + LeaveCriticalSection (&access); +} + +bool +process::add_cleanup_routine (class cleanup_routine *new_cleanup) +{ + if (cleaning_up) + return 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) + { + LeaveCriticalSection (&access); + return false; + } + new_cleanup->next = head; + head = new_cleanup; + LeaveCriticalSection (&access); + return true; +} + +/* process_cleanup */ void -process_request::process () +process_cleanup::process () { - printf ("processing...\n"); + theprocess->cleanup (); + delete theprocess; } /* process_process_param */ @@ -290,7 +371,7 @@ process_process_param::request_loop () debug_printf ("Process %ld has left the building\n", Entries[objindex]->winpid); /* fire off the termination routines */ - + cache->remove_process (Entries[objindex]); } else if (objindex >= 0 && objindex < 2) { diff --git a/winsup/cygwin/cygserver_shm.cc b/winsup/cygwin/cygserver_shm.cc index 134f810e6..c29938bb9 100755 --- a/winsup/cygwin/cygserver_shm.cc +++ b/winsup/cygwin/cygserver_shm.cc @@ -44,9 +44,9 @@ #include <sys/shm.h> #endif //#include "perprocess.h" -#include "cygserver_shm.h" #include <threaded_queue.h> #include <cygwin/cygserver_process.h> +#include "cygserver_shm.h" // FIXME IS THIS CORRECT /* Implementation notes: We use two shared memory regions per key: @@ -70,7 +70,7 @@ getsystemallocgranularity () } -client_request_shm_get::client_request_shm_get ():client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) +client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) { buffer = (char *) ¶meters; } @@ -152,7 +152,7 @@ static long new_id = 0; static long new_private_key = 0; void -client_request_shm_get::serve (transport_layer_base * conn, +client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { // DWORD sd_size = 4096; @@ -208,6 +208,7 @@ client_request_shm_get::serve (transport_layer_base * conn, char *shmname = NULL, *shmaname = NULL; char stringbuf[29], stringbuf1[29]; + /* TODO: make this code block a function! */ if (parameters.in.type == SHM_REATTACH) { /* just find and fill out the existing shm_id */ @@ -245,6 +246,32 @@ client_request_shm_get::serve (transport_layer_base * conn, CloseHandle (token_handle); return; } + + /* someone attached */ + /* someone can send shm_id's they don't have and currently we will increment those + * attach counts. If someone wants to fix that, please go ahead. + * The problem is that shm_get has nothing to do with the ability to attach. Attach + * requires a permission check, which we get the OS to do in MapViewOfFile. + */ + if (parameters.in.type == SHM_ATTACH) + { + shmnode *tempnode = shm_head; + while (tempnode) + { + if (tempnode->shm_id == parameters.in.shm_id) + { + InterlockedIncrement (&tempnode->shmds->shm_nattch); + header.error_code = 0; + CloseHandle (token_handle); + return; + } + tempnode = tempnode->next; + } + header.error_code = EINVAL; + CloseHandle (token_handle); + return; + } + /* it's a original request from the users */ /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide diff --git a/winsup/cygwin/cygserver_shm.h b/winsup/cygwin/cygserver_shm.h index 20d5e5db9..32947f8ec 100644 --- a/winsup/cygwin/cygserver_shm.h +++ b/winsup/cygwin/cygserver_shm.h @@ -15,23 +15,33 @@ details. */ #define SHM_CREATE 0 #define SHM_REATTACH 1 +#define SHM_ATTACH 2 +#define SHM_DETACH 3 -class client_request_shm_get : public client_request +class client_request_shm : public client_request { public: #ifndef __INSIDE_CYGWIN__ virtual void serve (transport_layer_base *conn, process_cache *cache); #endif - client_request_shm_get::client_request_shm_get(key_t, size_t, int, char psdbuf[4096], pid_t); - client_request_shm_get::client_request_shm_get(); - client_request_shm_get::client_request_shm_get(int,pid_t); + client_request_shm (key_t, size_t, int, char psdbuf[4096], pid_t); + client_request_shm (); + client_request_shm (int, int, pid_t); + client_request_shm (int, int); union { struct {int type; pid_t pid; int shm_id; key_t key; size_t size; int shmflg; char sd_buf[4096];} in; struct {int shm_id; HANDLE filemap; HANDLE attachmap; key_t key;} out; } parameters; }; +#ifndef __INSIDE_CYGWIN__ +class shm_cleanup : cleanup_routine +{ +public: + virtual void cleanup (long winpid); +}; +#endif #if 0 class _shmattach { public: diff --git a/winsup/cygwin/include/cygwin/cygserver_process.h b/winsup/cygwin/include/cygwin/cygserver_process.h index 75cae51a7..4a49212b2 100755 --- a/winsup/cygwin/include/cygwin/cygserver_process.h +++ b/winsup/cygwin/include/cygwin/cygserver_process.h @@ -15,10 +15,13 @@ /* needs threaded_queue.h */ -class process_request:public queue_request +class process_cleanup:public queue_request { public: virtual void process (); + process_cleanup (class process *nprocess) : theprocess (nprocess) {}; +private: + class process * theprocess; }; class process_process_param:public queue_process_param @@ -29,15 +32,32 @@ public: process_process_param ():queue_process_param (true) {}; }; +class cleanup_routine +{ +public: + cleanup_routine () : next (NULL) {}; + class cleanup_routine * next; + /* MUST BE SYNCHRONOUS */ + virtual void cleanup (long winpid); +}; + class process { public: HANDLE handle (); long winpid; process (long); + ~process (); DWORD exit_code (); class process * next; + long refcount; + bool add_cleanup_routine (class cleanup_routine *); + void cleanup (); private: + /* used to prevent races-on-delete */ + CRITICAL_SECTION access; + volatile long cleaning_up; + class cleanup_routine *head; HANDLE thehandle; DWORD _exit_status; }; @@ -48,12 +68,15 @@ public: process_cache (unsigned int initial_workers); virtual ~ process_cache (); class process *process (long); + /* remove a process from the cache */ int handle_snapshot (HANDLE *, class process **, ssize_t, int); + void remove_process (class process *); /* threaded_queue methods */ void process_requests (); HANDLE cache_add_trigger; + private: - virtual void add (); + virtual void add_task (class process *); class process *head; CRITICAL_SECTION cache_write_access; }; diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc index 268ccbd2b..dbe9bb0e9 100644 --- a/winsup/cygwin/shm.cc +++ b/winsup/cygwin/shm.cc @@ -45,16 +45,25 @@ getsystemallocgranularity () return buffer_offset; } -client_request_shm_get::client_request_shm_get (int nshm_id, pid_t npid): +client_request_shm::client_request_shm (int ntype, int nshm_id): client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) { buffer = (char *) ¶meters; parameters.in.shm_id = nshm_id; parameters.in.type = SHM_REATTACH; + parameters.in.pid = GetCurrentProcessId (); +} + +client_request_shm::client_request_shm (int ntype, int nshm_id, pid_t npid): +client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) +{ + buffer = (char *) ¶meters; + parameters.in.shm_id = nshm_id; + parameters.in.type = ntype; parameters.in.pid = npid; } -client_request_shm_get::client_request_shm_get (key_t nkey, size_t nsize, +client_request_shm::client_request_shm (key_t nkey, size_t nsize, int nshmflg, char psdbuf[4096], pid_t npid): @@ -187,8 +196,8 @@ shmat (int shmid, const void *shmaddr, int shmflg) /* couldn't find a currently open shm control area for the key - probably because * shmget hasn't been called. * Allocate a new control block - this has to be handled by the daemon */ - client_request_shm_get *req = - new client_request_shm_get (shmid, GetCurrentProcessId ()); + client_request_shm *req = + new client_request_shm (SHM_REATTACH, shmid, GetCurrentProcessId ()); int rc; if ((rc = cygserver_request (req))) @@ -239,10 +248,17 @@ shmat (int shmid, const void *shmaddr, int shmflg) set_errno (EACCES); return (void *) -1; } + /* tell the daemon we have attached */ + client_request_shm *req = + new client_request_shm (SHM_ATTACH, shmid); + int rc; + if ((rc = cygserver_request (req))) + { + debug_printf ("failed to tell deaemon that we have attached\n"); + } + delete req; - InterlockedIncrement (&shm->shm_nattch); _shmattach *attachnode = new _shmattach; - attachnode->data = rv; attachnode->shmflg = shmflg; attachnode->next = @@ -276,8 +292,8 @@ shmctl (int shmid, int cmd, struct shmid_ds *buf) /* couldn't find a currently open shm control area for the key - probably because * shmget hasn't been called. * Allocate a new control block - this has to be handled by the daemon */ - client_request_shm_get *req = - new client_request_shm_get (shmid, GetCurrentProcessId ()); + client_request_shm *req = + new client_request_shm (SHM_REATTACH, shmid, GetCurrentProcessId ()); int rc; if ((rc = cygserver_request (req))) @@ -337,8 +353,8 @@ shmctl (int shmid, int cmd, struct shmid_ds *buf) */ #if 0 //waiting for the daemon to handle terminating process's - client_request_shm_get *req = - new client_request_shm_get (SHM_DEL, shmid, GetCurrentProcessId ()); + client_request_shm *req = + new client_request_shm (SHM_DEL, shmid, GetCurrentProcessId ()); int rc; if ((rc = cygserver_request (req))) { @@ -428,8 +444,8 @@ shmget (key_t key, size_t size, int shmflg) } /* couldn't find a currently open shm control area for the key. * Allocate a new control block - this has to be handled by the daemon */ - client_request_shm_get *req = - new client_request_shm_get (key, size, shmflg, sd_buf, + client_request_shm *req = + new client_request_shm (key, size, shmflg, sd_buf, GetCurrentProcessId ()); int rc; |