diff options
author | scottc <scottc> | 2002-06-28 18:04:00 +0000 |
---|---|---|
committer | scottc <scottc> | 2002-06-28 18:04:00 +0000 |
commit | f4f60dbb9b3aa02e57851a3d928911c8fbb4903a (patch) | |
tree | 486fb8a9cc62020bb2010cd81b0d06019a2a5975 /winsup/cygwin/shm.cc | |
parent | ddeba35b3fc6fa7ed6c7ab68a0ba4e1ef15187bf (diff) | |
download | gdb-f4f60dbb9b3aa02e57851a3d928911c8fbb4903a.tar.gz |
* cygserver_ipc.h: New file.
* cygserver_shm.h: Re-written from scratch.
* cygserver_shm.cc: Ditto.
* shm.cc: Ditto.
Diffstat (limited to 'winsup/cygwin/shm.cc')
-rw-r--r-- | winsup/cygwin/shm.cc | 915 |
1 files changed, 465 insertions, 450 deletions
diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc index 80a47318bdf..75fd04aa998 100644 --- a/winsup/cygwin/shm.cc +++ b/winsup/cygwin/shm.cc @@ -1,8 +1,9 @@ -/* shm.cc: Single unix specification IPC interface for Cygwin +/* shm.cc: Single unix specification IPC interface for Cygwin. - Copyright 2001, 2002 Red Hat, Inc. + Copyright 2002 Red Hat, Inc. - Originally written by Robert Collins <robert.collins@hotmail.com> + Written by Conrad Scott <conrad.scott@dsl.pipex.com>. + Based on code by Robert Collins <robert.collins@hotmail.com>. This file is part of Cygwin. @@ -11,545 +12,559 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <sys/stat.h> -#include <assert.h> + +#include <sys/types.h> + #include <errno.h> -#include "cygerrno.h" -#include <limits.h> +#include <stdio.h> #include <unistd.h> -#include "security.h" -#include "fhandler.h" -#include "path.h" -#include "dtable.h" -#include "cygheap.h" -#include "thread.h" -#include "cygwin_shm.h" -#include "cygserver_shm.h" -/* - * FIXME: These must be defined somewhere? i.e. get the high and low - * double words of a quad word? They are required here to allow keys - * to be printed out via XXX_printf (i.e. small_printf()). Note that - * even if the key is only 32 bits (the old default), these routine - * should still give sensible results, i.e. hi_ulong() => 0. - */ +#include "cygerrno.h" -inline long int hi_ulong (const key_t key) -{ - return (unsigned long) - (((unsigned long long) key >> 32) & ULONG_MAX); -} +#include "cygserver_ipc.h" +#include "cygserver_shm.h" -inline long int lo_ulong (const key_t key) +/*---------------------------------------------------------------------------* + * with_strerr () + *---------------------------------------------------------------------------*/ + +#define with_strerr(MSG, ACTION) \ + do \ + { \ + const DWORD lasterr = GetLastError (); \ + char *MSG = NULL; \ + if (!FormatMessage ((FORMAT_MESSAGE_ALLOCATE_BUFFER \ + | FORMAT_MESSAGE_FROM_SYSTEM \ + | FORMAT_MESSAGE_IGNORE_INSERTS), \ + NULL, \ + lasterr, \ + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), \ + reinterpret_cast<char *>(&MSG), \ + 0, \ + NULL)) \ + { \ + MSG = static_cast<char *> \ + (LocalAlloc (LMEM_FIXED, 24)); /* Big enough. */ \ + if (!MSG) \ + { \ + system_printf (("failure in LocalAlloc(LMEM_FIXED, 16): " \ + "error = %lu"), \ + GetLastError ()); \ + } \ + else \ + { \ + snprintf (MSG, 24, "error = %lu", lasterr); \ + } \ + } \ + SetLastError (lasterr); \ + { ACTION; } \ + if (MSG && !LocalFree (MSG)) \ + { \ + system_printf ("failed to free memory at %p, error = %lu", \ + MSG, GetLastError ()); \ + } \ + SetLastError (lasterr); \ + } while (false) + +/*---------------------------------------------------------------------------* + * class client_shmmgr + * + * A singleton class. + *---------------------------------------------------------------------------*/ + +#define shmmgr (client_shmmgr::instance ()) + +class client_shmmgr { - return (unsigned long) - ((unsigned long long) key & ULONG_MAX); -} +private: + class segment_t + { + public: + const int shmid; + const void *const shmaddr; + const int shmflg; + HANDLE hFileMap; // Updated by fixup_shms_after_fork (). -// FIXME IS THIS CORRECT -/* Implementation notes: We use two shared memory regions per key: - * One for the control structure, and one for the shared memory. - * While this has a higher overhead tham a single shared area, - * It allows more flexability. As the entire code is transparent to the user - * We can merge these in the future should it be needed. - */ -extern "C" size_t -getsystemallocgranularity () -{ - SYSTEM_INFO sysinfo; - static size_t buffer_offset = 0; - if (buffer_offset) - return buffer_offset; - GetSystemInfo (&sysinfo); - buffer_offset = sysinfo.dwAllocationGranularity; - return buffer_offset; -} + segment_t *next; -/* - * Used for: SHM_ATTACH, SHM_DETACH, SHM_REATTACH, and SHM_DEL. - */ -client_request_shm::client_request_shm (int ntype, int nshmid) - : client_request (CYGSERVER_REQUEST_SHM, ¶meters, sizeof (parameters)) -{ - assert (ntype == SHM_REATTACH \ - || ntype == SHM_ATTACH \ - || ntype == SHM_DETACH \ - || ntype == SHM_DEL); + segment_t (const int shmid, const void *const shmaddr, const int shmflg, + const HANDLE hFileMap) + : shmid (shmid), shmaddr (shmaddr), shmflg (shmflg), hFileMap (hFileMap), + next (NULL) + {} + }; - parameters.in.type = ntype; - parameters.in.cygpid = getpid (); - parameters.in.winpid = GetCurrentProcessId (); - parameters.in.shm_id = nshmid; +public: + static client_shmmgr & instance (); - assert (parameters.in.cygpid > 0); - assert (parameters.in.winpid != 0); + void *shmat (int shmid, const void *, int shmflg); + int shmctl (int shmid, int cmd, struct shmid_ds *); + int shmdt (const void *); + int shmget (key_t, size_t, int shmflg); - msglen (sizeof (parameters.in) - sizeof (parameters.in.sd_buf)); + int fixup_shms_after_fork (); - syscall_printf ("created: type = %d, shmid = %d", - parameters.in.type, parameters.in.shm_id); -} +private: + CRITICAL_SECTION _segments_lock; + static segment_t *_segments_head; // A list sorted by shmaddr. -/* - * Used for: SHM_CREATE. - */ -client_request_shm::client_request_shm (key_t nkey, size_t nsize, int nshmflg) - : client_request (CYGSERVER_REQUEST_SHM, ¶meters, sizeof (parameters)) -{ - assert (nkey != (key_t) -1); - assert (nsize >= 0); + client_shmmgr (); + ~client_shmmgr (); - parameters.in.type = SHM_CREATE; - parameters.in.cygpid = getpid (); - parameters.in.winpid = GetCurrentProcessId (); - parameters.in.key = nkey; - parameters.in.size = nsize; - parameters.in.shmflg = nshmflg; + // Undefined (as this class is a singleton): + client_shmmgr (const client_shmmgr &); + client_shmmgr & operator= (const client_shmmgr &); - assert (parameters.in.cygpid > 0); - assert (parameters.in.winpid != 0); + segment_t *find (const void *, segment_t **previous = NULL); - DWORD sd_buf_size = 0; + void *attach (int shmid, const void *, int shmflg, HANDLE & hFileMap); - if (wincap.has_security ()) - { - SECURITY_ATTRIBUTES sa = sec_none; - sd_buf_size = sizeof (parameters.in.sd_buf); + segment_t *new_segment (int shmid, const void *, int shmflg, HANDLE); +}; - PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) parameters.in.sd_buf; +client_shmmgr::segment_t *client_shmmgr::_segments_head; - InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION); +/*---------------------------------------------------------------------------* + * client_shmmgr::instance () + *---------------------------------------------------------------------------*/ - alloc_sd (geteuid32 (), getegid32 (), parameters.in.shmflg & 0777, - psd, &sd_buf_size); - } +client_shmmgr & +client_shmmgr::instance () +{ + static NO_COPY client_shmmgr instance; + + return instance; +} - msglen (sizeof (parameters.in) - sizeof (parameters.in.sd_buf) - + sd_buf_size); +/*---------------------------------------------------------------------------* + * client_shmmgr::shmat () + *---------------------------------------------------------------------------*/ - syscall_printf (("created: type = %d, " - "key = 0x%x%08x, size = %ld, shmflg = %o"), - parameters.in.type, - hi_ulong(parameters.in.key), lo_ulong(parameters.in.key), - parameters.in.size, parameters.in.shmflg); +void * +client_shmmgr::shmat (const int shmid, + const void *const shmaddr, + const int shmflg) +{ + HANDLE hFileMap = NULL; + + void *const ptr = attach (shmid, shmaddr, shmflg, hFileMap); + + if (ptr) + new_segment (shmid, ptr, shmflg, hFileMap); + + return (ptr ? ptr : (void *) -1); } -static shmnode *shm_head = NULL; +/*---------------------------------------------------------------------------* + * client_shmmgr::shmctl () + *---------------------------------------------------------------------------*/ -static shmnode * -build_inprocess_shmds (HANDLE hfilemap, HANDLE hattachmap, key_t key, - int shm_id) +int +client_shmmgr::shmctl (const int shmid, + const int cmd, + struct shmid_ds *const buf) { - HANDLE filemap = hfilemap; - void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0); + client_request_shm request (shmid, cmd, buf); - if (!mapptr) + if (request.make_request () == -1 || request.error_code ()) { - CloseHandle (hfilemap); - CloseHandle (hattachmap); - //FIXME: close filemap and free the mutex - /* we couldn't access the mapped area with the requested permissions */ - set_errno (EACCES); - return NULL; + set_errno (request.error_code ()); + return -1; } - /* Now get the user data */ - HANDLE attachmap = hattachmap; - int_shmid_ds *shmtemp = new int_shmid_ds; - if (!shmtemp) + // Some commands require special processing, e.g. for out parameters. + + switch (cmd) { - system_printf ("failed to malloc shm node"); - set_errno (ENOMEM); - UnmapViewOfFile (mapptr); - CloseHandle (filemap); - CloseHandle (attachmap); - /* exit mutex */ - return NULL; + case IPC_STAT: + *buf = request.ds (); + break; + } + + return 0; +} + +/*---------------------------------------------------------------------------* + * client_shmmgr::shmdt () + * + * According to Posix, the only error condition for this system call + * is EINVAL if shmaddr is not the address of the start of an attached + * shared memory segment. Given that, all other errors just generate + * tracing noise. + *---------------------------------------------------------------------------*/ + +int +client_shmmgr::shmdt (const void *const shmaddr) +{ + segment_t *previous = NULL; + + segment_t *const segptr = find (shmaddr, &previous); + + if (!segptr) + { + set_errno (EINVAL); + return -1; } - /* get the system node data */ - shmtemp->ds = *(shmid_ds *) mapptr; + assert (previous ? previous->next == segptr : _segments_head == segptr); + + if (previous) + previous->next = segptr->next; + else + _segments_head = segptr->next; + + if (!UnmapViewOfFile ((void *) shmaddr)) + with_strerr (msg, + syscall_printf (("failed to unmap view " + "[shmid = %d, handle = %p, shmaddr = %p]:" + "%s"), + segptr->shmid, segptr->hFileMap, shmaddr, + msg)); + + assert (segptr->hFileMap); - /* process local data */ - shmnode *tempnode = new shmnode; + if (!CloseHandle (segptr->hFileMap)) + with_strerr (msg, + syscall_printf (("failed to close file map handle " + "[shmid = %d, handle = %p]:" + "%s"), + segptr->shmid, segptr->hFileMap, + msg)); - tempnode->filemap = filemap; - tempnode->attachmap = attachmap; - shmtemp->mapptr = mapptr; + client_request_shm request (segptr->shmid); - /* no need for InterlockedExchange here, we're serialised by the global mutex */ - tempnode->shmds = shmtemp; - tempnode->shm_id = shm_id; - tempnode->key = key; - tempnode->next = shm_head; - tempnode->attachhead = NULL; - shm_head = tempnode; + if (request.make_request () == -1 || request.error_code ()) + syscall_printf ("shmdt request failed [shmid = %d, handle = %p]: %s", + segptr->shmid, segptr->hFileMap, + strerror (request.error_code ())); - /* FIXME: leave the system wide shm mutex */ + delete segptr; - return tempnode; + return 0; } -static void -delete_inprocess_shmds (shmnode **nodeptr) +/*---------------------------------------------------------------------------* + * client_shmmgr::shmget () + *---------------------------------------------------------------------------*/ + +int +client_shmmgr::shmget (const key_t key, const size_t size, const int shmflg) { - shmnode *node = *nodeptr; + client_request_shm request (key, size, shmflg); - // remove from the list - if (node == shm_head) - shm_head = shm_head->next; - else + if (request.make_request () == -1 || request.error_code ()) { - shmnode *tempnode = shm_head; - while (tempnode && tempnode->next != node) - tempnode = tempnode->next; - if (tempnode) - tempnode->next = node->next; - // else log the unexpected ! + set_errno (request.error_code ()); + return -1; } - // release the shared data view - UnmapViewOfFile (node->shmds); - CloseHandle (node->filemap); - CloseHandle (node->attachmap); - - // free the memory - delete node; - nodeptr = NULL; + return request.shmid (); } -int __stdcall -fixup_shms_after_fork () +/*---------------------------------------------------------------------------* + * client_shmmgr::fixup_shms_after_fork () + * + * The hFileMap handles are non-inheritable: so the + *---------------------------------------------------------------------------*/ + +int +client_shmmgr::fixup_shms_after_fork () { - shmnode *tempnode = shm_head; - while (tempnode) - { - void *newshmds = - MapViewOfFile (tempnode->filemap, FILE_MAP_WRITE, 0, 0, 0); - if (!newshmds) - { - /* don't worry about handle cleanup, we're dying! */ - system_printf ("failed to reattach to shm control file view %x", - tempnode); - return 1; - } - tempnode->shmds->ds = *(shmid_ds *) newshmds; - tempnode->shmds->mapptr = newshmds; - _shmattach *attachnode = tempnode->attachhead; - while (attachnode) - { - void *newdata = MapViewOfFileEx (tempnode->attachmap, - (attachnode->shmflg & SHM_RDONLY) ? - FILE_MAP_READ : FILE_MAP_WRITE, 0, - 0, 0, attachnode->data); - if (newdata != attachnode->data) - { - /* don't worry about handle cleanup, we're dying! */ - system_printf ("failed to reattach to mapped file view %x", - attachnode->data); - return 1; - } - attachnode = attachnode->next; - } - tempnode = tempnode->next; - } + for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next) + if (!attach (segptr->shmid, + segptr->shmaddr, + segptr->shmflg & ~SHM_RND, + segptr->hFileMap)) + { + system_printf ("fatal error re-attaching to shared memory segments"); + return 1; + } + return 0; } -/* this is ugly. Yes, I know that. - * FIXME: abstract the lookup functionality, - * So that it can be an array, list, whatever without us being worried - */ +/*---------------------------------------------------------------------------* + * client_shmmgr::client_shmmgr () + *---------------------------------------------------------------------------*/ -/* FIXME: after fork, every memory area needs to have the attach count - * incremented. This should be done in the server? - */ +client_shmmgr::client_shmmgr () +{ + InitializeCriticalSection (&_segments_lock); +} -/* FIXME: tell the daemon when we attach, so at process close it can clean up - * the attach count - */ -extern "C" void * -shmat (int shmid, const void *shmaddr, int shmflg) +/*---------------------------------------------------------------------------* + * client_shmmgr::~client_shmmgr () + *---------------------------------------------------------------------------*/ + +client_shmmgr::~client_shmmgr () { - shmnode *tempnode = shm_head; - while (tempnode && tempnode->shm_id != shmid) - tempnode = tempnode->next; + DeleteCriticalSection (&_segments_lock); +} - if (!tempnode) - { - /* 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 req (SHM_REATTACH, shmid); - - if (req.make_request () == -1) - { - set_errno (ENOSYS); /* daemon communication failed */ - return (void *) -1; - } - - if (req.error_code ()) /* shm_get failed in the daemon */ - { - set_errno (req.error_code ()); - return (void *) -1; - } - - /* we've got the id, now we open the memory area ourselves. - * This tests security automagically - * FIXME: make this a method of shmnode ? - */ - tempnode = - build_inprocess_shmds (req.parameters.out.filemap, - req.parameters.out.attachmap, - req.parameters.out.key, - req.parameters.out.shm_id); - if (!tempnode) - return (void *) -1; +/*---------------------------------------------------------------------------* + * client_shmmgr::find () + *---------------------------------------------------------------------------*/ - } +client_shmmgr::segment_t * +client_shmmgr::find (const void *const shmaddr, segment_t **previous) +{ + if (previous) + *previous = NULL; - // class shmid_ds *shm = tempnode->shmds; + for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next) + if (segptr->shmaddr == shmaddr) + return segptr; + else if (segptr->shmaddr > shmaddr) // The list is sorted by shmaddr. + return NULL; + else if (previous) + *previous = segptr; - if (shmaddr) + return NULL; +} + +/*---------------------------------------------------------------------------* + * client_shmmgr::attach () + * + * The body of shmat (), also used by fixup_shms_after_fork (). + *---------------------------------------------------------------------------*/ + +void * +client_shmmgr::attach (const int shmid, + const void *shmaddr, + const int shmflg, + HANDLE & hFileMap) +{ + client_request_shm request (shmid, shmflg); + + if (request.make_request () == -1 || request.error_code ()) { - //FIXME: requested base address ?! (Don't forget to fix the fixup_after_fork too) - set_errno (EINVAL); - return (void *) -1; + set_errno (request.error_code ()); + return NULL; } - void *rv = MapViewOfFile (tempnode->attachmap, - (shmflg & SHM_RDONLY) ? FILE_MAP_READ : - FILE_MAP_WRITE, 0, 0, 0); + int result = 0; + + const DWORD access = (shmflg & SHM_RDONLY) ? FILE_MAP_READ : FILE_MAP_WRITE; + + if (shmaddr && (shmflg & SHM_RND)) + shmaddr = (char *) shmaddr - ((ssize_t) shmaddr % SHMLBA); + + void *const ptr = + MapViewOfFileEx (request.hFileMap (), access, 0, 0, 0, (void *) shmaddr); - if (!rv) + if (!ptr) { - //FIXME: translate GetLastError() - set_errno (EACCES); - return (void *) -1; + with_strerr (msg, + syscall_printf (("failed to map view " + "[shmid = %d, handle = %p, shmaddr = %p]:" + "%s"), + shmid, request.hFileMap (), shmaddr, + msg)); + result = EINVAL; // FIXME } - /* tell the daemon we have attached */ - client_request_shm req (SHM_ATTACH, shmid); - - if (req.make_request () == -1) + else if (shmaddr && ptr != shmaddr) { - debug_printf ("failed to tell daemon that we have attached"); + syscall_printf (("failed to map view at requested address " + "[shmid = %d, handle = %p]: " + "requested address = %p, mapped address = %p"), + shmid, request.hFileMap (), + shmaddr, ptr); + result = EINVAL; // FIXME } - _shmattach *attachnode = new _shmattach; - attachnode->data = rv; - attachnode->shmflg = shmflg; - attachnode->next = - (_shmattach *) InterlockedExchangePointer (&tempnode->attachhead, - attachnode); - + if (result != 0) + { + if (!CloseHandle (request.hFileMap ())) + with_strerr (msg, + syscall_printf (("failed to close file map handle " + "[shmid = %d, handle = %p]:" + "%s"), + shmid, request.hFileMap (), + msg)); + + client_request_shm dt_req (shmid); + + if (dt_req.make_request () == -1 || dt_req.error_code ()) + syscall_printf ("shmdt request failed [shmid = %d, handle = %p]: %s", + shmid, request.hFileMap (), + strerror (dt_req.error_code ())); + + set_errno (result); + return NULL; + } - return rv; + hFileMap = request.hFileMap (); + return ptr; } -/* FIXME: tell the daemon when we detach so it doesn't cleanup incorrectly. - */ -extern "C" int -shmdt (const void *shmaddr) +/*---------------------------------------------------------------------------* + * client_shmmgr::new_segment () + * + * Allocate a new segment for the given shmid, file map and address + * and insert into the segment map. + *---------------------------------------------------------------------------*/ + +client_shmmgr::segment_t * +client_shmmgr::new_segment (const int shmid, + const void *const shmaddr, + const int shmflg, + const HANDLE hFileMap) { - /* this should be "rare" so a hefty search is ok. If this is common, then we - * should alter the data structs to allow more optimisation - */ - shmnode *tempnode = shm_head; - _shmattach *attachnode; - while (tempnode) + assert (ipc_ext2int_subsys (shmid) == IPC_SHMOP); + assert (hFileMap); + assert (shmaddr); + + segment_t *previous = NULL; // Insert pointer. + + const segment_t *const tmp = find (shmaddr, &previous); + + assert (!tmp); + assert (previous \ + ? (!previous->next || previous->next->shmaddr > shmaddr) \ + : (!_segments_head || _segments_head->shmaddr > shmaddr)); + + segment_t *const segptr = new segment_t (shmid, shmaddr, shmflg, hFileMap); + + assert (segptr); + + if (previous) { - // FIXME: Race potential - attachnode = tempnode->attachhead; - while (attachnode && attachnode->data != shmaddr) - attachnode = attachnode->next; - if (attachnode) - break; - tempnode = tempnode->next; + segptr->next = previous->next; + previous->next = segptr; } - if (!tempnode) + else { - // dt cannot be called by an app that hasn't alreadu at'd - set_errno (EINVAL); - return -1; + segptr->next = _segments_head; + _segments_head = segptr; } - UnmapViewOfFile (attachnode->data); - /* tell the daemon we have attached */ - client_request_shm req (SHM_DETACH, tempnode->shm_id); + return segptr; +} - if (req.make_request () == -1) - { - debug_printf ("failed to tell daemon that we have detached"); - } +/*---------------------------------------------------------------------------* + * shmat () + *---------------------------------------------------------------------------*/ - return 0; +extern "C" void * +shmat (const int shmid, const void *const shmaddr, const int shmflg) +{ + return shmmgr.shmat (shmid, shmaddr, shmflg); } -//FIXME: who is allowed to perform STAT? +/*---------------------------------------------------------------------------* + * shmctl () + *---------------------------------------------------------------------------*/ + extern "C" int -shmctl (int shmid, int cmd, struct shmid_ds *buf) +shmctl (const int shmid, const int cmd, struct shmid_ds *const buf) { - shmnode *tempnode = shm_head; - while (tempnode && tempnode->shm_id != shmid) - tempnode = tempnode->next; - if (!tempnode) - { - /* 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 req (SHM_REATTACH, shmid); - - if (req.make_request () == -1) - { - set_errno (ENOSYS); /* daemon communication failed */ - return -1; - } - - if (req.error_code ()) /* shm_get failed in the daemon */ - { - set_errno (req.error_code ()); - return -1; - } - - /* we've got the id, now we open the memory area ourselves. - * This tests security automagically - * FIXME: make this a method of shmnode ? - */ - tempnode = - build_inprocess_shmds (req.parameters.out.filemap, - req.parameters.out.attachmap, - req.parameters.out.key, - req.parameters.out.shm_id); - if (!tempnode) - return -1; - } + return shmmgr.shmctl (shmid, cmd, buf); +} - switch (cmd) - { - case IPC_STAT: - *buf = tempnode->shmds->ds; - break; - case IPC_RMID: - { - /* TODO: check permissions. Or possibly, the daemon gets to be the only - * one with write access to the memory area? - */ - if (tempnode->shmds->ds.shm_nattch) - system_printf - ("call to shmctl with cmd= IPC_RMID when memory area still has" - " attachees"); - /* how does this work? - * we mark the ds area as "deleted", and the at and get calls all fail from now on - * on, when nattch becomes 0, the mapped data area is destroyed. - * and each process, as they touch this area detaches. eventually only the - * daemon has an attach. The daemon gets asked to detach immediately. - */ - //waiting for the daemon to handle terminating process's - client_request_shm req (SHM_DEL, shmid); - - if (req.make_request () == -1) - { - set_errno (ENOSYS); /* daemon communication failed */ - return -1; - } - - if (req.error_code ()) /* shm_del failed in the daemon */ - { - set_errno (req.error_code ()); - return -1; - } - - /* the daemon has deleted it's references */ - /* now for us */ - - // FIXME: create a destructor - delete_inprocess_shmds (&tempnode); +/*---------------------------------------------------------------------------* + * shmdt () + *---------------------------------------------------------------------------*/ - } - break; - case IPC_SET: - default: - set_errno (EINVAL); - return -1; - } - return 0; +extern "C" int +shmdt (const void *const shmaddr) +{ + return shmmgr.shmdt (shmaddr); } -/* FIXME: evaluate getuid32() and getgid32() against the requested mode. Then - * choose PAGE_READWRITE | PAGE_READONLY and FILE_MAP_WRITE | FILE_MAP_READ - * appropriately - */ +/*---------------------------------------------------------------------------* + * shmget () + *---------------------------------------------------------------------------*/ -/* FIXME: shmid should be a verifyable object - */ - -/* FIXME: on NT we should check everything against the SD. On 95 we just emulate. - */ extern "C" int -shmget (key_t key, size_t size, int shmflg) +shmget (const key_t key, const size_t size, const int shmflg) { - if (key == (key_t) - 1) - { - set_errno (ENOENT); - return -1; - } + return shmmgr.shmget (key, size, shmflg); +} - /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide - * to prevent races on shmget. - */ +/*---------------------------------------------------------------------------* + * fixup_shms_after_fork () + *---------------------------------------------------------------------------*/ - /* walk the list of currently open keys and return the id if found - */ - shmnode *tempnode = shm_head; - while (tempnode) - { - if (tempnode->key == key && key != IPC_PRIVATE) - { - // FIXME: free the mutex - if (size && tempnode->shmds->ds.shm_segsz < size) - { - set_errno (EINVAL); - return -1; - } - if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) - { - set_errno (EEXIST); - // FIXME: free the mutex - return -1; - } - // FIXME: do we need to other tests of the requested mode with the - // tempnode->shmid mode ? testcase on unix needed. - // FIXME do we need a security test? We are only examining the keys we already have open. - // FIXME: what are the sec implications for fork () if we don't check here? - return tempnode->shm_id; - } - tempnode = tempnode->next; - } - /* 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 req (key, size, shmflg); +int __stdcall +fixup_shms_after_fork () +{ + return shmmgr.fixup_shms_after_fork (); +} - if (req.make_request () == -1) - { - set_errno (ENOSYS); /* daemon communication failed */ - return -1; - } +/*---------------------------------------------------------------------------* + * client_request_shm::client_request_shm () + *---------------------------------------------------------------------------*/ - if (req.error_code ()) /* shm_get failed in the daemon */ - { - set_errno (req.error_code ()); - return -1; - } +client_request_shm::client_request_shm (const int shmid, const int shmflg) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) +{ + _parameters.in.shmop = SHMOP_shmat; + + _parameters.shmid = shmid; + _parameters.in.shmflg = shmflg; + + _parameters.in.cygpid = getpid (); + _parameters.in.winpid = GetCurrentProcessId (); + _parameters.in.uid = geteuid (); + _parameters.in.gid = getegid (); +} + +/*---------------------------------------------------------------------------* + * client_request_shm::client_request_shm () + *---------------------------------------------------------------------------*/ + +client_request_shm::client_request_shm (const int shmid, + const int cmd, + const struct shmid_ds * const buf) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) +{ + _parameters.in.shmop = SHMOP_shmctl; + + _parameters.shmid = shmid; + if (cmd == IPC_SET) + _parameters.ds = *buf; + _parameters.in.cmd = cmd; + + _parameters.in.cygpid = getpid (); + _parameters.in.winpid = GetCurrentProcessId (); + _parameters.in.uid = geteuid (); + _parameters.in.gid = getegid (); +} + +/*---------------------------------------------------------------------------* + * client_request_shm::client_request_shm () + *---------------------------------------------------------------------------*/ + +client_request_shm::client_request_shm (const int shmid) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) +{ + _parameters.in.shmop = SHMOP_shmdt; + + _parameters.shmid = shmid; + + _parameters.in.cygpid = getpid (); + _parameters.in.winpid = GetCurrentProcessId (); + _parameters.in.uid = geteuid (); + _parameters.in.gid = getegid (); +} + +/*---------------------------------------------------------------------------* + * client_request_shm::client_request_shm () + *---------------------------------------------------------------------------*/ + +client_request_shm::client_request_shm (const key_t key, + const size_t size, + const int shmflg) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) +{ + _parameters.in.shmop = SHMOP_shmget; + + _parameters.in.key = key; + _parameters.in.size = size; + _parameters.in.shmflg = shmflg; - /* we've got the id, now we open the memory area ourselves. - * This tests security automagically - * FIXME: make this a method of shmnode ? - */ - shmnode *shmtemp = build_inprocess_shmds (req.parameters.out.filemap, - req.parameters.out.attachmap, - key, - req.parameters.out.shm_id); - if (shmtemp) - return shmtemp->shm_id; - return -1; + _parameters.in.cygpid = getpid (); + _parameters.in.winpid = GetCurrentProcessId (); + _parameters.in.uid = geteuid (); + _parameters.in.gid = getegid (); } |