diff options
Diffstat (limited to 'winsup/cygserver/shm.cc')
-rw-r--r-- | winsup/cygserver/shm.cc | 896 |
1 files changed, 0 insertions, 896 deletions
diff --git a/winsup/cygserver/shm.cc b/winsup/cygserver/shm.cc deleted file mode 100644 index 18b1c3d..0000000 --- a/winsup/cygserver/shm.cc +++ /dev/null @@ -1,896 +0,0 @@ -/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin. - - Copyright 2002 Red Hat, Inc. - - 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. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#include "woutsup.h" - -#include <errno.h> -#include <pthread.h> -#include <stdio.h> -#include <string.h> -#include <time.h> - -#include "cygserver_ipc.h" -#include "cygserver_shm.h" -#include "security.h" - -#include "cygwin/cygserver.h" -#include "cygwin/cygserver_process.h" -#include "cygwin/cygserver_transport.h" - -/*---------------------------------------------------------------------------* - * class server_shmmgr - * - * A singleton class. - *---------------------------------------------------------------------------*/ - -#define shmmgr (server_shmmgr::instance ()) - -class server_shmmgr -{ -private: - class attach_t - { - public: - class process *const _client; - unsigned int _refcnt; - - attach_t *_next; - - attach_t (class process *const client) - : _client (client), - _refcnt (0), - _next (NULL) - {} - }; - - class segment_t - { - private: - // Bits for the _flg field. - enum { IS_DELETED = 0x01 }; - - public: - const int _intid; - const int _shmid; - struct shmid_ds _ds; - - segment_t *_next; - - segment_t (const key_t key, const int intid, const HANDLE hFileMap); - ~segment_t (); - - bool is_deleted () const - { - return _flg & IS_DELETED; - } - - bool is_pending_delete () const - { - return !_ds.shm_nattch && is_deleted (); - } - - void mark_deleted () - { - assert (!is_deleted ()); - - _flg |= IS_DELETED; - } - - int attach (class process *, HANDLE & hFileMap); - int detach (class process *); - - private: - static long _sequence; - - int _flg; - const HANDLE _hFileMap; - attach_t *_attach_head; // A list sorted by winpid; - - attach_t *find (const class process *, attach_t **previous = NULL); - }; - - class cleanup_t : public cleanup_routine - { - public: - cleanup_t (const segment_t *const segptr) - : cleanup_routine (reinterpret_cast<void *> (segptr->_shmid)) - { - assert (key ()); - } - - int shmid () const { return reinterpret_cast<int> (key ()); } - - virtual void cleanup (class process *const client) - { - const int res = shmmgr.shmdt (shmid (), client); - - if (res != 0) - debug_printf ("process cleanup failed [shmid = %d]: %s", - shmid (), strerror (-res)); - } - }; - -public: - static server_shmmgr & instance (); - - int shmat (HANDLE & hFileMap, - int shmid, int shmflg, class process *); - int shmctl (int & out_shmid, struct shmid_ds & out_ds, - 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, class process *); - int shmget (int & out_shmid, key_t, size_t, int shmflg, uid_t, gid_t, - class process *); - -private: - static server_shmmgr *_instance; - static pthread_once_t _instance_once; - - static void initialise_instance (); - - CRITICAL_SECTION _segments_lock; - segment_t *_segments_head; // A list sorted by int_id. - - int _shm_ids; // Number of shm segments (for ipcs(8)). - int _shm_tot; // Total bytes of shm segments (for ipcs(8)). - int _shm_atts; // Number of attached segments (for ipcs(8)). - int _intid_max; // Highest intid yet allocated (for ipcs(8)). - - server_shmmgr (); - ~server_shmmgr (); - - // Undefined (as this class is a singleton): - server_shmmgr (const server_shmmgr &); - server_shmmgr & operator= (const server_shmmgr &); - - segment_t *find_by_key (key_t); - segment_t *find (int intid, segment_t **previous = NULL); - - int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t); - - segment_t *new_segment (key_t, size_t, HANDLE); - void delete_segment (segment_t *); -}; - -/* static */ long server_shmmgr::segment_t::_sequence = 0; - -/* static */ server_shmmgr *server_shmmgr::_instance = NULL; -/* static */ pthread_once_t server_shmmgr::_instance_once = PTHREAD_ONCE_INIT; - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::segment_t () - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t::segment_t (const key_t key, - const int intid, - const HANDLE hFileMap) - : _intid (intid), - _shmid (ipc_int2ext (intid, IPC_SHMOP, _sequence)), - _next (NULL), - _flg (0), - _hFileMap (hFileMap), - _attach_head (NULL) -{ - assert (0 <= _intid && _intid < SHMMNI); - - memset (&_ds, '\0', sizeof (_ds)); - _ds.shm_perm.key = key; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::~segment_t () - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t::~segment_t () -{ - assert (!_attach_head); - - if (!CloseHandle (_hFileMap)) - syscall_printf ("failed to close file map [handle = 0x%x]: %E", _hFileMap); -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::attach () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::segment_t::attach (class process *const client, - HANDLE & hFileMap) -{ - assert (client); - - if (!DuplicateHandle (GetCurrentProcess (), - _hFileMap, - client->handle (), - &hFileMap, - 0, - FALSE, // bInheritHandle - DUPLICATE_SAME_ACCESS)) - { - syscall_printf (("failed to duplicate handle for client " - "[key = 0x%016llx, shmid = %d, handle = 0x%x]: %E"), - _ds.shm_perm.key, _shmid, _hFileMap); - - return -EACCES; // FIXME: Case analysis? - } - - _ds.shm_lpid = client->cygpid (); - _ds.shm_nattch += 1; - _ds.shm_atime = time (NULL); // FIXME: sub-second times. - - attach_t *previous = NULL; - attach_t *attptr = find (client, &previous); - - if (!attptr) - { - attptr = safe_new (attach_t, client); - - if (previous) - { - attptr->_next = previous->_next; - previous->_next = attptr; - } - else - { - attptr->_next = _attach_head; - _attach_head = attptr; - } - } - - attptr->_refcnt += 1; - - cleanup_t *const cleanup = safe_new (cleanup_t, this); - - // FIXME: ::add should only fail if the process object is already - // cleaning up; but it can't be doing that since this thread has it - // locked. - - const bool result = client->add (cleanup); - - assert (result); - - return 0; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::detach () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::segment_t::detach (class process *const client) -{ - attach_t *previous = NULL; - attach_t *const attptr = find (client, &previous); - - 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) - { - assert (previous ? previous->_next == attptr : _attach_head == attptr); - - if (previous) - previous->_next = attptr->_next; - else - _attach_head = attptr->_next; - - safe_delete (attptr); - } - - assert (_ds.shm_nattch > 0); - - _ds.shm_lpid = client->cygpid (); - _ds.shm_nattch -= 1; - _ds.shm_dtime = time (NULL); // FIXME: sub-second times. - - return 0; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::find () - *---------------------------------------------------------------------------*/ - -server_shmmgr::attach_t * -server_shmmgr::segment_t::find (const class process *const client, - attach_t **previous) -{ - if (previous) - *previous = NULL; - - // Nb. The _attach_head list is sorted by winpid. - - for (attach_t *attptr = _attach_head; attptr; attptr = attptr->_next) - if (attptr->_client == client) - return attptr; - else if (attptr->_client->winpid () > client->winpid ()) - return NULL; - else if (previous) - *previous = attptr; - - return NULL; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::instance () - *---------------------------------------------------------------------------*/ - -/* static */ server_shmmgr & -server_shmmgr::instance () -{ - pthread_once (&_instance_once, &initialise_instance); - - assert (_instance); - - return *_instance; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::shmat () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::shmat (HANDLE & hFileMap, - const int shmid, const int shmflg, - class process *const client) -{ - syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d(%lu)", - shmid, shmflg, client->cygpid (), client->winpid ()); - - int result = 0; - EnterCriticalSection (&_segments_lock); - - segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP)); - - if (!segptr) - result = -EINVAL; - else - result = segptr->attach (client, hFileMap); - - if (!result) - _shm_atts += 1; - - LeaveCriticalSection (&_segments_lock); - - if (result < 0) - syscall_printf (("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) " - "for %d(%lu)"), - -result, shmid, shmflg, - client->cygpid (), client->winpid ()); - else - syscall_printf (("0x%x = shmat (shmid = %d, shmflg = 0%o) " - "for %d(%lu)"), - hFileMap, shmid, shmflg, - client->cygpid (), client->winpid ()); - - return result; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::shmctl () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::shmctl (int & out_shmid, - struct shmid_ds & out_ds, - struct shminfo & out_shminfo, - struct shm_info & out_shm_info, - const int shmid, const int cmd, - const struct shmid_ds & ds, - class process *const client) -{ - syscall_printf ("shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)", - shmid, cmd, client->cygpid (), client->winpid ()); - - int result = 0; - EnterCriticalSection (&_segments_lock); - - switch (cmd) - { - case IPC_STAT: - case SHM_STAT: // Uses intids rather than shmids. - case IPC_SET: - case IPC_RMID: - { - int intid; - - if (cmd == SHM_STAT) - intid = shmid; - else - intid = ipc_ext2int (shmid, IPC_SHMOP); - - segment_t *const segptr = find (intid); - - if (!segptr) - result = -EINVAL; - else - switch (cmd) - { - case IPC_STAT: - out_ds = segptr->_ds; - break; - - case IPC_SET: - segptr->_ds.shm_perm.uid = ds.shm_perm.uid; - segptr->_ds.shm_perm.gid = ds.shm_perm.gid; - segptr->_ds.shm_perm.mode = ds.shm_perm.mode & 0777; - segptr->_ds.shm_lpid = client->cygpid (); - segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times. - break; - - case IPC_RMID: - if (segptr->is_deleted ()) - result = -EIDRM; - else - { - segptr->mark_deleted (); - if (segptr->is_pending_delete ()) - delete_segment (segptr); - } - break; - - case SHM_STAT: // ipcs(8) i'face. - out_ds = segptr->_ds; - out_shmid = segptr->_shmid; - break; - } - } - break; - - case IPC_INFO: - out_shminfo.shmmax = SHMMAX; - out_shminfo.shmmin = SHMMIN; - out_shminfo.shmmni = SHMMNI; - out_shminfo.shmseg = SHMSEG; - out_shminfo.shmall = SHMALL; - break; - - case SHM_INFO: // ipcs(8) i'face. - out_shmid = _intid_max; - out_shm_info.shm_ids = _shm_ids; - out_shm_info.shm_tot = _shm_tot; - out_shm_info.shm_atts = _shm_atts; - break; - - default: - result = -EINVAL; - break; - } - - LeaveCriticalSection (&_segments_lock); - - if (result < 0) - syscall_printf (("-1 [%d] = " - "shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"), - -result, - shmid, cmd, client->cygpid (), client->winpid ()); - else - syscall_printf (("%d = " - "shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"), - ((cmd == SHM_STAT || cmd == SHM_INFO) - ? out_shmid - : result), - shmid, cmd, client->cygpid (), client->winpid ()); - - return result; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::shmdt () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::shmdt (const int shmid, class process *const client) -{ - syscall_printf ("shmdt (shmid = %d) for %d(%lu)", - shmid, client->cygpid (), client->winpid ()); - - int result = 0; - EnterCriticalSection (&_segments_lock); - - segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP)); - - if (!segptr) - result = -EINVAL; - else - result = segptr->detach (client); - - if (!result) - _shm_atts -= 1; - - if (!result && segptr->is_pending_delete ()) - delete_segment (segptr); - - LeaveCriticalSection (&_segments_lock); - - if (result < 0) - syscall_printf ("-1 [%d] = shmdt (shmid = %d) for %d(%lu)", - -result, shmid, client->cygpid (), client->winpid ()); - else - syscall_printf ("%d = shmdt (shmid = %d) for %d(%lu)", - result, shmid, client->cygpid (), client->winpid ()); - - return result; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::shmget () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::shmget (int & out_shmid, - const key_t key, const size_t size, const int shmflg, - const uid_t uid, const gid_t gid, - class process *const client) -{ - syscall_printf (("shmget (key = 0x%016llx, size = %u, shmflg = 0%o) " - "for %d(%lu)"), - key, size, shmflg, - client->cygpid (), client->winpid ()); - - int result = 0; - EnterCriticalSection (&_segments_lock); - - if (key == IPC_PRIVATE) - result = new_segment (key, size, shmflg, - client->cygpid (), uid, gid); - else - { - segment_t *const segptr = find_by_key (key); - - if (!segptr) - if (shmflg & IPC_CREAT) - result = new_segment (key, size, shmflg, - client->cygpid (), uid, gid); - else - result = -ENOENT; - else if (segptr->is_deleted ()) - result = -EIDRM; - else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) - result = -EEXIST; - else if ((shmflg & ~(segptr->_ds.shm_perm.mode)) & 0777) - result = -EACCES; - else if (size && segptr->_ds.shm_segsz < size) - result = -EINVAL; - else - result = segptr->_shmid; - } - - LeaveCriticalSection (&_segments_lock); - - if (result >= 0) - { - out_shmid = result; - result = 0; - } - - if (result < 0) - syscall_printf (("-1 [%d] = " - "shmget (key = 0x%016llx, size = %u, shmflg = 0%o) " - "for %d(%lu)"), - -result, - key, size, shmflg, - client->cygpid (), client->winpid ()); - else - syscall_printf (("%d = " - "shmget (key = 0x%016llx, size = %u, shmflg = 0%o) " - "for %d(%lu)"), - out_shmid, - key, size, shmflg, - client->cygpid (), client->winpid ()); - - return result; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::initialise_instance () - *---------------------------------------------------------------------------*/ - -/* static */ void -server_shmmgr::initialise_instance () -{ - assert (!_instance); - - _instance = safe_new0 (server_shmmgr); - - assert (_instance); -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::server_shmmgr () - *---------------------------------------------------------------------------*/ - -server_shmmgr::server_shmmgr () - : _segments_head (NULL), - _shm_ids (0), - _shm_tot (0), - _shm_atts (0), - _intid_max (0) -{ - InitializeCriticalSection (&_segments_lock); -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::~server_shmmgr () - *---------------------------------------------------------------------------*/ - -server_shmmgr::~server_shmmgr () -{ - DeleteCriticalSection (&_segments_lock); -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::find_by_key () - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t * -server_shmmgr::find_by_key (const key_t key) -{ - for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next) - if (segptr->_ds.shm_perm.key == key) - return segptr; - - return NULL; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::find () - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t * -server_shmmgr::find (const int intid, segment_t **previous) -{ - if (previous) - *previous = NULL; - - for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next) - if (segptr->_intid == intid) - return segptr; - else if (segptr->_intid > intid) // The list is sorted by intid. - return NULL; - else if (previous) - *previous = segptr; - - return NULL; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::new_segment () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::new_segment (const key_t key, - const size_t size, - const int shmflg, - const pid_t cygpid, - const uid_t uid, - const gid_t gid) -{ - if (size < SHMMIN || size > SHMMAX) - return -EINVAL; - - const HANDLE hFileMap = CreateFileMapping (INVALID_HANDLE_VALUE, - NULL, PAGE_READWRITE, - 0, size, - NULL); - - if (!hFileMap) - { - syscall_printf ("failed to create file mapping [size = %lu]: %E", size); - return -ENOMEM; // FIXME - } - - segment_t *const segptr = new_segment (key, size, hFileMap); - - if (!segptr) - { - (void) CloseHandle (hFileMap); - return -ENOSPC; - } - - segptr->_ds.shm_perm.cuid = segptr->_ds.shm_perm.uid = uid; - segptr->_ds.shm_perm.cgid = segptr->_ds.shm_perm.gid = gid; - segptr->_ds.shm_perm.mode = shmflg & 0777; - segptr->_ds.shm_segsz = size; - segptr->_ds.shm_cpid = cygpid; - segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times. - - return segptr->_shmid; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::new_segment () - * - * Allocate a new segment for the given key and file map with the - * lowest available intid and insert into the segment map. - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t * -server_shmmgr::new_segment (const key_t key, const size_t size, - const HANDLE hFileMap) -{ - // FIXME: Overflow risk. - if (_shm_tot + size > SHMALL) - return NULL; - - int intid = 0; // Next expected intid value. - segment_t *previous = NULL; // Insert pointer. - - // Find first unallocated intid. - for (segment_t *segptr = _segments_head; - segptr && segptr->_intid == intid; - segptr = segptr->_next, intid++) - { - previous = segptr; - } - - /* By the time this condition is reached (given the default value of - * SHMMNI), the linear searches should all replaced by something - * just a *little* cleverer . . . - */ - if (intid >= SHMMNI) - return NULL; - - segment_t *const segptr = safe_new (segment_t, key, intid, hFileMap); - - assert (segptr); - - if (previous) - { - segptr->_next = previous->_next; - previous->_next = segptr; - } - else - { - segptr->_next = _segments_head; - _segments_head = segptr; - } - - _shm_ids += 1; - _shm_tot += size; - if (intid > _intid_max) - _intid_max = intid; - - return segptr; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::delete_segment () - *---------------------------------------------------------------------------*/ - -void -server_shmmgr::delete_segment (segment_t *const segptr) -{ - assert (segptr); - assert (segptr->is_pending_delete ()); - - segment_t *previous = NULL; - - const segment_t *const tmp = find (segptr->_intid, &previous); - - assert (tmp == segptr); - assert (previous ? previous->_next == segptr : _segments_head == segptr); - - if (previous) - previous->_next = segptr->_next; - else - _segments_head = segptr->_next; - - assert (_shm_ids > 0); - _shm_ids -= 1; - _shm_tot -= segptr->_ds.shm_segsz; - - safe_delete (segptr); -} - -/*---------------------------------------------------------------------------* - * client_request_shm::client_request_shm () - *---------------------------------------------------------------------------*/ - -client_request_shm::client_request_shm () - : client_request (CYGSERVER_REQUEST_SHM, - &_parameters, sizeof (_parameters)) -{ - // verbose: syscall_printf ("created"); -} - -/*---------------------------------------------------------------------------* - * client_request_shm::serve () - *---------------------------------------------------------------------------*/ - -void -client_request_shm::serve (transport_layer_base *const conn, - process_cache *const cache) -{ - assert (conn); - - assert (!error_code ()); - - if (msglen () != sizeof (_parameters.in)) - { - syscall_printf ("bad request body length: expecting %lu bytes, got %lu", - sizeof (_parameters), msglen ()); - error_code (EINVAL); - msglen (0); - return; - } - - // FIXME: Get a return code out of this and don't continue on error. - conn->impersonate_client (); - - class process *const client = cache->process (_parameters.in.cygpid, - _parameters.in.winpid); - - if (!client) - { - error_code (EAGAIN); - msglen (0); - return; - } - - int result = -EINVAL; - - switch (_parameters.in.shmop) - { - case SHMOP_shmget: - result = shmmgr.shmget (_parameters.out.shmid, - _parameters.in.key, _parameters.in.size, - _parameters.in.shmflg, - _parameters.in.uid, _parameters.in.gid, - client); - break; - - case SHMOP_shmat: - result = shmmgr.shmat (_parameters.out.hFileMap, - _parameters.in.shmid, _parameters.in.shmflg, - client); - break; - - case SHMOP_shmdt: - result = shmmgr.shmdt (_parameters.in.shmid, client); - break; - - case SHMOP_shmctl: - result = shmmgr.shmctl (_parameters.out.shmid, - _parameters.out.ds, _parameters.out.shminfo, - _parameters.out.shm_info, - _parameters.in.shmid, _parameters.in.cmd, - _parameters.in.ds, - client); - break; - } - - client->release (); - conn->revert_to_self (); - - if (result < 0) - { - error_code (-result); - msglen (0); - } - else - msglen (sizeof (_parameters.out)); -} |