diff options
Diffstat (limited to 'winsup/cygwin/shm.cc')
-rw-r--r-- | winsup/cygwin/shm.cc | 865 |
1 files changed, 257 insertions, 608 deletions
diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc index a5e7c31df..ef3248f4f 100644 --- a/winsup/cygwin/shm.cc +++ b/winsup/cygwin/shm.cc @@ -1,9 +1,6 @@ -/* shm.cc: Single unix specification IPC interface for Cygwin. +/* shm.cc: XSI IPC interface for Cygwin. - Copyright 2002,2003 Red Hat, Inc. - - Written by Conrad Scott <conrad.scott@dsl.pipex.com>. - Based on code by Robert Collins <robert.collins@hotmail.com>. + Copyright 2003 Red Hat, Inc. This file is part of Cygwin. @@ -15,697 +12,349 @@ details. */ #include "cygerrno.h" #ifdef USE_SERVER #include <sys/types.h> - -#include <assert.h> +#include <sys/queue.h> #include <stdio.h> #include <unistd.h> -#include "safe_memory.h" +#include "pinfo.h" #include "sigproc.h" #include "cygserver_ipc.h" #include "cygserver_shm.h" -/*---------------------------------------------------------------------------* - * class client_shmmgr - * - * A singleton class. - *---------------------------------------------------------------------------*/ - -#define shmmgr (client_shmmgr::instance ()) - -class client_shmmgr -{ -private: - class segment_t - { - public: - const int shmid; - const void *const shmaddr; - const int shmflg; - HANDLE hFileMap; // Updated by fixup_shms_after_fork (). - - segment_t *next; - - 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) - {} - }; - -public: - static client_shmmgr & instance (); - - 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); - - int fixup_shms_after_fork (); - -private: - static NO_COPY client_shmmgr *_instance; - - CRITICAL_SECTION _segments_lock; - static segment_t *_segments_head; // List of attached segs by shmaddr. - - static long _shmat_cnt; // No. of attached segs; for info. only. - - client_shmmgr (); - ~client_shmmgr (); - - // Undefined (as this class is a singleton): - client_shmmgr (const client_shmmgr &); - client_shmmgr & operator= (const client_shmmgr &); - - segment_t *find (const void *, segment_t **previous = NULL); - - void *attach (int shmid, const void *, int shmflg, HANDLE & hFileMap); - - segment_t *new_segment (int shmid, const void *, int shmflg, HANDLE); -}; - -/* static */ NO_COPY client_shmmgr *client_shmmgr::_instance; - -/* The following two variables must be inherited by child processes - * since they are used by fixup_shms_after_fork () to re-attach to the - * parent's shm segments. +/* + * client_request_shm Constructors */ -/* static */ client_shmmgr::segment_t *client_shmmgr::_segments_head; -/* static */ long client_shmmgr::_shmat_cnt; -/*---------------------------------------------------------------------------* - * client_shmmgr::instance () - *---------------------------------------------------------------------------*/ - -client_shmmgr & -client_shmmgr::instance () +client_request_shm::client_request_shm (int shmid, + const void *shmaddr, + int shmflg) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) { - if (!_instance) - _instance = safe_new0 (client_shmmgr); + _parameters.in.shmop = SHMOP_shmat; + ipc_set_proc_info (_parameters.in.ipcblk); - assert (_instance); + _parameters.in.atargs.shmid = shmid; + _parameters.in.atargs.shmaddr = shmaddr; + _parameters.in.atargs.shmflg = shmflg; - return *_instance; + msglen (sizeof (_parameters.in)); } -/*---------------------------------------------------------------------------* - * client_shmmgr::shmat () - *---------------------------------------------------------------------------*/ - -void * -client_shmmgr::shmat (const int shmid, - const void *const shmaddr, - const int shmflg) +client_request_shm::client_request_shm (int shmid, + int cmd, + struct shmid_ds *buf) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) { - syscall_printf ("shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)", - shmid, shmaddr, shmflg); - - EnterCriticalSection (&_segments_lock); - - HANDLE hFileMap = NULL; - - void *const ptr = attach (shmid, shmaddr, shmflg, hFileMap); - - if (ptr) - new_segment (shmid, ptr, shmflg, hFileMap); - - LeaveCriticalSection (&_segments_lock); + _parameters.in.shmop = SHMOP_shmctl; + ipc_set_proc_info (_parameters.in.ipcblk); - if (ptr) - syscall_printf ("%p = shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)", - ptr, shmid, shmaddr, shmflg); - // else - // See the syscall_printf in client_shmmgr::attach (). + _parameters.in.ctlargs.shmid = shmid; + _parameters.in.ctlargs.cmd = cmd; + _parameters.in.ctlargs.buf = buf; - return (ptr ? ptr : (void *) -1); + msglen (sizeof (_parameters.in)); } -/*---------------------------------------------------------------------------* - * client_shmmgr::shmctl () - *---------------------------------------------------------------------------*/ - -int -client_shmmgr::shmctl (const int shmid, - const int cmd, - struct shmid_ds *const buf) +client_request_shm::client_request_shm (const void *shmaddr) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) { - syscall_printf ("shmctl (shmid = %d, cmd = 0x%x, buf = %p)", - shmid, cmd, buf); - - // Check parameters and set up in parameters as required. - - const struct shmid_ds *in_buf = NULL; - - switch (cmd) - { - case IPC_SET: - if (__check_invalid_read_ptr_errno (buf, sizeof (struct shmid_ds))) - { - syscall_printf (("-1 [EFAULT] = " - "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"), - shmid, cmd, buf); - set_errno (EFAULT); - return -1; - } - in_buf = buf; - break; - - case IPC_STAT: - case SHM_STAT: - if (__check_null_invalid_struct_errno (buf, sizeof (struct shmid_ds))) - { - syscall_printf (("-1 [EFAULT] = " - "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"), - shmid, cmd, buf); - set_errno (EFAULT); - return -1; - } - break; - - case IPC_INFO: - if (__check_null_invalid_struct_errno (buf, sizeof (struct shminfo))) - { - syscall_printf (("-1 [EFAULT] = " - "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"), - shmid, cmd, buf); - set_errno (EFAULT); - return -1; - } - break; - - case SHM_INFO: - if (__check_null_invalid_struct_errno (buf, sizeof (struct shm_info))) - { - syscall_printf (("-1 [EFAULT] = " - "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"), - shmid, cmd, buf); - set_errno (EFAULT); - return -1; - } - break; - } - - // Create and issue the command. - - client_request_shm request (shmid, cmd, in_buf); - - if (request.make_request () == -1 || request.error_code ()) - { - syscall_printf (("-1 [%d] = " - "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"), - request.error_code (), shmid, cmd, buf); - set_errno (request.error_code ()); - return -1; - } - - // Some commands require special processing for their out parameters. - - int result = 0; - - switch (cmd) - { - case IPC_STAT: - *buf = request.ds (); - break; - - case IPC_INFO: - *(struct shminfo *) buf = request.shminfo (); - break; - - case SHM_STAT: // ipcs(8) i'face. - result = request.shmid (); - *buf = request.ds (); - break; - - case SHM_INFO: // ipcs(8) i'face. - result = request.shmid (); - *(struct shm_info *) buf = request.shm_info (); - break; - } + _parameters.in.shmop = SHMOP_shmdt; + ipc_set_proc_info (_parameters.in.ipcblk); - syscall_printf ("%d = shmctl (shmid = %d, cmd = 0x%x, buf = %p)", - result, shmid, cmd, buf); + _parameters.in.dtargs.shmaddr = shmaddr; - return result; + msglen (sizeof (_parameters.in)); } -/*---------------------------------------------------------------------------* - * 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) +client_request_shm::client_request_shm (key_t key, + size_t size, + int shmflg) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) { - syscall_printf ("shmdt (shmaddr = %p)", shmaddr); - - EnterCriticalSection (&_segments_lock); - - segment_t *previous = NULL; - - segment_t *const segptr = find (shmaddr, &previous); - - if (!segptr) - { - LeaveCriticalSection (&_segments_lock); - syscall_printf ("-1 [EINVAL] = shmdt (shmaddr = %p)", shmaddr); - set_errno (EINVAL); - return -1; - } - - assert (previous ? previous->next == segptr : _segments_head == segptr); - - if (previous) - previous->next = segptr->next; - else - _segments_head = segptr->next; - - LeaveCriticalSection (&_segments_lock); - - const long cnt = InterlockedDecrement (&_shmat_cnt); - assert (cnt >= 0); - - if (!UnmapViewOfFile ((void *) shmaddr)) - syscall_printf (("failed to unmap view " - "[shmid = %d, handle = %p, shmaddr = %p]:" - "%E"), - segptr->shmid, segptr->hFileMap, shmaddr); + _parameters.in.shmop = SHMOP_shmget; + ipc_set_proc_info (_parameters.in.ipcblk); - assert (segptr->hFileMap); + _parameters.in.getargs.key = key; + _parameters.in.getargs.size = size; + _parameters.in.getargs.shmflg = shmflg; - if (!CloseHandle (segptr->hFileMap)) - syscall_printf (("failed to close file map handle " - "[shmid = %d, handle = %p]: %E"), - segptr->shmid, segptr->hFileMap); + msglen (sizeof (_parameters.in)); +} - client_request_shm request (segptr->shmid); +client_request_shm::client_request_shm (proc *p1) + : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters)) +{ + _parameters.in.shmop = SHMOP_shmfork; + ipc_set_proc_info (_parameters.in.ipcblk); - 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 ())); + _parameters.in.forkargs = *p1; +} - safe_delete (segptr); +/* List of shmid's with file mapping HANDLE and size, returned by shmget. */ +struct shm_shmid_list { + SLIST_ENTRY(shm_shmid_list) ssh_next; + int shmid; + vm_object_t hdl; + size_t size; +}; - syscall_printf ("0 = shmdt (shmaddr = %p)", shmaddr); +static SLIST_HEAD(, shm_shmid_list) ssh_list; - return 0; -} +/* List of attached mappings, as returned by shmat. */ +struct shm_attached_list { + SLIST_ENTRY(shm_attached_list) sph_next; + vm_object_t ptr; + vm_object_t hdl; + size_t size; + int access; +}; -/*---------------------------------------------------------------------------* - * client_shmmgr::shmget () - *---------------------------------------------------------------------------*/ +static SLIST_HEAD(, shm_attached_list) sph_list; -int -client_shmmgr::shmget (const key_t key, const size_t size, const int shmflg) +int __stdcall +fixup_shms_after_fork () { - syscall_printf ("shmget (key = 0x%016X, size = %u, shmflg = 0%o)", - key, size, shmflg); + if (!SLIST_FIRST (&sph_list)) + return 0; + pinfo p (myself->ppid); + proc parent = { myself->ppid, p->dwProcessId, p->uid, p->gid }; - client_request_shm request (key, size, shmflg); - - if (request.make_request () == -1 || request.error_code ()) + client_request_shm request (&parent); + if (request.make_request () == -1 || request.retval () == -1) { - syscall_printf (("-1 [%d] = " - "shmget (key = 0x%016X, size = %u, shmflg = 0%o)"), - request.error_code (), - key, size, shmflg); + syscall_printf ("-1 [%d] = shmctl ()", request.error_code ()); set_errno (request.error_code ()); - return -1; + return 0; + } + shm_attached_list *sph_entry; + /* Remove map from list... */ + SLIST_FOREACH (sph_entry, &sph_list, sph_next) + { + vm_object_t ptr = MapViewOfFileEx(sph_entry->hdl, sph_entry->access, + 0, 0, sph_entry->size, sph_entry->ptr); + if (ptr != sph_entry->ptr) + api_fatal ("MapViewOfFileEx (%p), %E. Terminating.", sph_entry->ptr); } - - syscall_printf (("%d = shmget (key = 0x%016X, size = %u, shmflg = 0%o)"), - request.shmid (), - key, size, shmflg); - - return request.shmid (); -} - -/*---------------------------------------------------------------------------* - * client_shmmgr::fixup_shms_after_fork () - * - * The hFileMap handles are non-inheritable: so they have to be - * re-acquired from cygserver. - * - * Nb. This routine need not be thread-safe as it is only called at startup. - *---------------------------------------------------------------------------*/ - -int -client_shmmgr::fixup_shms_after_fork () -{ - debug_printf ("re-attaching to shm segments: %d attached", _shmat_cnt); - - { - int length = 0; - for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next) - length += 1; - - if (_shmat_cnt != length) - { - system_printf (("state inconsistent: " - "_shmat_cnt = %d, length of segments list = %d"), - _shmat_cnt, length); - return 1; - } - } - - 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 shm segment %d", - segptr->shmid); - return 1; - } - - if (_shmat_cnt) - debug_printf ("re-attached all %d shm segments", _shmat_cnt); - return 0; } +#endif /* USE_SERVER */ -/*---------------------------------------------------------------------------* - * client_shmmgr::client_shmmgr () - *---------------------------------------------------------------------------*/ - -client_shmmgr::client_shmmgr () -{ - InitializeCriticalSection (&_segments_lock); -} - -/*---------------------------------------------------------------------------* - * client_shmmgr::~client_shmmgr () - *---------------------------------------------------------------------------*/ - -client_shmmgr::~client_shmmgr () -{ - DeleteCriticalSection (&_segments_lock); -} - -/*---------------------------------------------------------------------------* - * client_shmmgr::find () - *---------------------------------------------------------------------------*/ - -client_shmmgr::segment_t * -client_shmmgr::find (const void *const shmaddr, segment_t **previous) -{ - if (previous) - *previous = NULL; - - 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; - - return NULL; -} +/* + * XSI shmaphore API. These are exported by the DLL. + */ -/*---------------------------------------------------------------------------* - * 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) +extern "C" void * +shmat (int shmid, const void *shmaddr, int shmflg) { - client_request_shm request (shmid, shmflg); +#ifdef USE_SERVER + sigframe thisframe (mainthread); + syscall_printf ("shmat (shmid = %d, shmaddr = %p, shmflg = 0x%x)", + shmid, shmaddr, shmflg); - if (request.make_request () == -1 || request.error_code ()) + shm_shmid_list *ssh_entry; + SLIST_FOREACH (ssh_entry, &ssh_list, ssh_next) { - syscall_printf (("-1 [%d] = " - "shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)"), - request.error_code (), shmid, shmaddr, shmflg); - set_errno (request.error_code ()); - return NULL; + if (ssh_entry->shmid == shmid) + break; } - - 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 (!ptr) + if (!ssh_entry) { - syscall_printf (("failed to map view " - "[shmid = %d, handle = %p, shmaddr = %p]: %E"), - shmid, request.hFileMap (), shmaddr); - result = EINVAL; // FIXME + /* Invalid shmid */ + set_errno (EINVAL); + return NULL; } - else if (shmaddr && ptr != shmaddr) + vm_object_t attach_va = NULL; + if (shmaddr) { - 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 + if (shmflg & SHM_RND) + attach_va = (vm_object_t)((vm_offset_t)shmaddr & ~(SHMLBA-1)); + else + attach_va = (vm_object_t)shmaddr; + /* Don't even bother to call anything if shmaddr is NULL or + not aligned. */ + if (!attach_va || (vm_offset_t)attach_va % SHMLBA) + { + set_errno (EINVAL); + return NULL; + } } - - if (result != 0) + /* Try allocating memory before calling cygserver. */ + shm_attached_list *sph_entry = new (shm_attached_list); + if (!sph_entry) { - if (!CloseHandle (request.hFileMap ())) - syscall_printf (("failed to close file map handle " - "[shmid = %d, handle = %p]: %E"), - shmid, request.hFileMap ()); - - 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); + set_errno (ENOMEM); return NULL; } - - hFileMap = request.hFileMap (); - return ptr; -} - -/*---------------------------------------------------------------------------* - * 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) -{ - 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 = - safe_new (segment_t, shmid, shmaddr, shmflg, hFileMap); - - assert (segptr); - - if (previous) + DWORD access = (shmflg & SHM_RDONLY) ? FILE_MAP_READ : FILE_MAP_WRITE; + vm_object_t ptr = MapViewOfFileEx(ssh_entry->hdl, access, 0, 0, + ssh_entry->size, attach_va); + if (!ptr) { - segptr->next = previous->next; - previous->next = segptr; + __seterrno (); + delete sph_entry; + return NULL; } - else + /* Use returned ptr address as is, so it's stored using the exact value + in cygserver. */ + client_request_shm request (shmid, ptr, shmflg & ~SHM_RND); + if (request.make_request () == -1 || request.ptrval () == NULL) { - segptr->next = _segments_head; - _segments_head = segptr; + syscall_printf ("-1 [%d] = shmctl ()", request.error_code ()); + UnmapViewOfFile (ptr); + delete sph_entry; + set_errno (request.error_code ()); + return NULL; } - - const long cnt = InterlockedIncrement (&_shmat_cnt); - assert (cnt > 0); - - return segptr; -} - -/*---------------------------------------------------------------------------* - * fixup_shms_after_fork () - *---------------------------------------------------------------------------*/ - -int __stdcall -fixup_shms_after_fork () -{ - return shmmgr.fixup_shms_after_fork (); -} - -/*---------------------------------------------------------------------------* - * client_request_shm::client_request_shm () - *---------------------------------------------------------------------------*/ - -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.in.shmid = shmid; - _parameters.in.shmflg = shmflg; - - _parameters.in.cygpid = getpid (); - _parameters.in.winpid = GetCurrentProcessId (); - _parameters.in.uid = geteuid32 (); - _parameters.in.gid = getegid32 (); - - msglen (sizeof (_parameters.in)); -} - -/*---------------------------------------------------------------------------* - * 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.in.shmid = shmid; - _parameters.in.cmd = cmd; - if (buf) - _parameters.in.ds = *buf; - - _parameters.in.cygpid = getpid (); - _parameters.in.winpid = GetCurrentProcessId (); - _parameters.in.uid = geteuid32 (); - _parameters.in.gid = getegid32 (); - - msglen (sizeof (_parameters.in)); -} - -/*---------------------------------------------------------------------------* - * 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.in.shmid = shmid; - - _parameters.in.cygpid = getpid (); - _parameters.in.winpid = GetCurrentProcessId (); - _parameters.in.uid = geteuid32 (); - _parameters.in.gid = getegid32 (); - - msglen (sizeof (_parameters.in)); -} - -/*---------------------------------------------------------------------------* - * 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; - - _parameters.in.cygpid = getpid (); - _parameters.in.winpid = GetCurrentProcessId (); - _parameters.in.uid = geteuid32 (); - _parameters.in.gid = getegid32 (); - - msglen (sizeof (_parameters.in)); -} -#endif /* USE_SERVER */ - -/*---------------------------------------------------------------------------* - * shmat () - *---------------------------------------------------------------------------*/ - -extern "C" void * -shmat (const int shmid, const void *const shmaddr, const int shmflg) -{ -#ifdef USE_SERVER - sigframe thisframe (mainthread); - return shmmgr.shmat (shmid, shmaddr, shmflg); + sph_entry->ptr = ptr; + sph_entry->hdl = ssh_entry->hdl; + sph_entry->size = ssh_entry->size; + sph_entry->access = access; + SLIST_INSERT_HEAD (&sph_list, sph_entry, sph_next); + return ptr; #else set_errno (ENOSYS); - return (void *) -1; + return NULL; #endif } -/*---------------------------------------------------------------------------* - * shmctl () - *---------------------------------------------------------------------------*/ - extern "C" int -shmctl (const int shmid, const int cmd, struct shmid_ds *const buf) +shmctl (int shmid, int cmd, struct shmid_ds *buf) { #ifdef USE_SERVER sigframe thisframe (mainthread); - return shmmgr.shmctl (shmid, cmd, buf); + syscall_printf ("shmctl (shmid = %d, cmd = %d, buf = 0x%x)", + shmid, cmd, buf); + switch (cmd) + { + case IPC_STAT: + case IPC_SET: + if (__check_null_invalid_struct_errno (buf, sizeof (struct shmid_ds))) + return -1; + break; + case IPC_INFO: + /* shmid == 0: Request for shminfo struct. */ + if (!shmid + && __check_null_invalid_struct_errno (buf, sizeof (struct shminfo))) + return -1; + /* Otherwise, request shmid entries from internal shmid_ds array. */ + if (shmid) + if (__check_null_invalid_struct_errno (buf, shmid * sizeof (struct shmid_ds))) + return -1; + break; + case SHM_INFO: + if (__check_null_invalid_struct_errno (buf, sizeof (struct shm_info))) + return -1; + break; + } + client_request_shm request (shmid, cmd, buf); + if (request.make_request () == -1 || request.retval () == -1) + { + syscall_printf ("-1 [%d] = shmctl ()", request.error_code ()); + set_errno (request.error_code ()); + return -1; + } + if (cmd == IPC_RMID) + { + /* The process must cleanup its own storage... */ + shm_shmid_list *ssh_entry, *ssh_next_entry; + SLIST_FOREACH_SAFE (ssh_entry, &ssh_list, ssh_next, ssh_next_entry) + { + if (ssh_entry->shmid == shmid) + { + SLIST_REMOVE (&ssh_list, ssh_entry, shm_shmid_list, ssh_next); + /* ...and close the handle. */ + CloseHandle (ssh_entry->hdl); + delete ssh_entry; + break; + } + } + } + return request.retval (); #else set_errno (ENOSYS); return -1; #endif } -/*---------------------------------------------------------------------------* - * shmdt () - *---------------------------------------------------------------------------*/ - extern "C" int -shmdt (const void *const shmaddr) +shmdt (const void *shmaddr) { #ifdef USE_SERVER sigframe thisframe (mainthread); - return shmmgr.shmdt (shmaddr); + syscall_printf ("shmget (shmaddr = %p)", shmaddr); + client_request_shm request (shmaddr); + if (request.make_request () == -1 || request.retval () == -1) + { + syscall_printf ("-1 [%d] = shmctl ()", request.error_code ()); + set_errno (request.error_code ()); + return -1; + } + shm_attached_list *sph_entry, *sph_next_entry; + /* Remove map from list... */ + SLIST_FOREACH_SAFE (sph_entry, &sph_list, sph_next, sph_next_entry) + { + if (sph_entry->ptr == shmaddr) + { + SLIST_REMOVE (&sph_list, sph_entry, shm_attached_list, sph_next); + /* ...and unmap view. */ + UnmapViewOfFile (sph_entry->ptr); + delete sph_entry; + break; + } + } + return request.retval (); #else set_errno (ENOSYS); return -1; #endif } -/*---------------------------------------------------------------------------* - * shmget () - *---------------------------------------------------------------------------*/ - extern "C" int -shmget (const key_t key, const size_t size, const int shmflg) +shmget (key_t key, size_t size, int shmflg) { #ifdef USE_SERVER sigframe thisframe (mainthread); - return shmmgr.shmget (key, size, shmflg); + syscall_printf ("shmget (key = %U, size = %d, shmflg = 0x%x)", + key, size, shmflg); + /* Try allocating memory before calling cygserver. */ + shm_shmid_list *ssh_new_entry = new (shm_shmid_list); + if (!ssh_new_entry) + { + set_errno (ENOMEM); + return -1; + } + client_request_shm request (key, size, shmflg); + if (request.make_request () == -1 || request.retval () == -1) + { + syscall_printf ("-1 [%d] = shmctl ()", request.error_code ()); + delete ssh_new_entry; + set_errno (request.error_code ()); + return -1; + } + int shmid = request.retval (); /* Shared mem ID */ + vm_object_t hdl = request.objval (); /* HANDLE associated with it. */ + shm_shmid_list *ssh_entry; + SLIST_FOREACH (ssh_entry, &ssh_list, ssh_next) + { + if (ssh_entry->shmid == shmid) + { + /* We already maintain an entry for this shmid. That means, + the hdl returned by cygserver is a superfluous duplicate + of the original hdl maintained by cygserver. We can safely + delete it. */ + CloseHandle (hdl); + delete ssh_new_entry; + return shmid; + } + } + /* We arrive here only if shmid is a new one for this process. Add the + shmid and hdl value to the list. */ + ssh_new_entry->shmid = shmid; + ssh_new_entry->hdl = hdl; + ssh_new_entry->size = size; + SLIST_INSERT_HEAD (&ssh_list, ssh_new_entry, ssh_next); + return shmid; #else set_errno (ENOSYS); return -1; |