diff options
author | scottc <scottc> | 2002-07-03 02:40:48 +0000 |
---|---|---|
committer | scottc <scottc> | 2002-07-03 02:40:48 +0000 |
commit | d5db49380f53a4ecbf794f106c13cc63c1d6ab43 (patch) | |
tree | dc0d81d02fa7f40501022ab4111cdcf225b6808a | |
parent | eea6a644adf1641beca7744f6f4aecc82191331e (diff) | |
download | gdb-d5db49380f53a4ecbf794f106c13cc63c1d6ab43.tar.gz |
* cygserver_shm.cc: Implement the ipcs(8) interfaces, IPC_INFO,
SHM_STAT and SHM_INFO.
(server_shmmgr::segment_t::sequence): New static field.
(server_shmmgr::segment_t::key): Remove field, use the new
ds.shm_perm.key field instead.
(server_shmmgr::segment_t::shmid): Remove field.
(server_shmmgr::segment_t::intid): New field.
(server_shmmgr::segment_t::segment_t): Use the `key' argument to
initialise `ds.shm_perm.key'. Change from using `shmid' to
`intid'.
(server_shmmgr::_shmseg_cnt): Renamed from `_shmid_cnt'.
(server_shmmgr::_intid_max): Renamed from `_shmid_max.
(server_shmmgr::shmat): Move the out arguments to the start of the
argument list. Rename the `pid' argument as `cygpid'. Add
tracing. Pass an intid to `find ()', not a shmid.
(server_shmmgr::shmctl): Add separate out arguments. Rename the
`pid' argument as `cygpid'. Add support for the ipcs(8)
interfaces. Add tracing. Pass an intid to `find ()', not a
shmid.
(server_shmmgr::shmdt): Rename the `pid' argument as `cygpid'.
Add tracing. Pass an intid to `find ()', not a shmid.
(server_shmmgr::shmget): Add a separate out arguments. Rename the
`pid' argument as `cygpid'. Add tracing.
(server_shmmgr::server_shmmgr): Update for new field names.
(server_shmmgr::find_by_key): Update for the new `ds.shm_perm.key'
field.
(server_shmmgr::find): Update to use the new `segment_t::intid'
field.
(server_shmmgr::new_segment): Rename the `pid' argument as
`cygpid'. Check that the requested size is within bounds. Handle
new error result from `new_segment (key, HANDLE)'.
(server_shmmgr::new_segment): Work with intids, not shmids. Check
that the new intid is within bounds. Update for new field names.
(server_shmmgr::delete_segment): Pass an intid to `find ()', not a
shmid. Update for new field names.
(client_request_shm::serve): Check that the incoming message
length is the size of the `_parameters.in' struct, not of the
whole in/out parameter union. Likewise, set the outgoing message
length to the size of the `_parameters.out' struct. Update for
the new server_shmmgr interfaces.
* include/sys/ipc.h (ipc_perm::key): New field.
* include/sys/shm.h (SHM_INFO): New constant.
* cygserver_ipc.h (IPCMNI): New constant.
(ipc_int2ext): Add `sequence' argument and munge this into the
external ipc id.
(ipc_ext2int_subsys): Unmunge the sequence number from the
external ipc id.
(ipc_ext2int): Ditto.
(ipc_inc_id): Remove.
(ipc_dec_id): Remove.
* cygserver_shm.h (SHMMAX): New constant.
(SHMMIN): Ditto.
(SHMMNI): Ditto.
(SHMSEG): Ditto.
(SHMALL): Ditto.
(client_request_shm::_parameters): Re-arrange as a union of two
separate structs, one for in arguments, the other for out.
(client_request_shm::shmid): Update for the new parameter layout.
(client_request_shm::ds): Ditto.
(client_request_shm::info): New method.
* shm.cc (client_shmmgr::_shmat_cnt): New static field.
(client_shmmgr::shmat): Add locking. Add tracing.
(client_shmmgr::shmctl): Update for ipcs(8) commands. Add
tracing. Add more argument checking.
(client_shmmgr::shmdt): Add locking. Add tracing. Update the new
`_shmat_cnt' field.
(client_shmmgr::shmget): Add tracing.
(client_shmmgr::fixup_shms_after_fork): Add tracing. Add
consistency checking.
(client_shmmgr::attach): Add more tracing.
(client_shmmgr::new_segment): Update the new `_shmat_cnt' field.
(client_request_shm::client_request_shm): Update for the new
parameter layout. Set the outgoing message length to the size of
the `_parameters.in' struct, not of the whole in/out parameter
union.
-rw-r--r-- | winsup/cygwin/ChangeLog | 78 | ||||
-rw-r--r-- | winsup/cygwin/cygserver_ipc.h | 77 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver_shm.cc | 337 | ||||
-rw-r--r-- | winsup/cygwin/cygserver_shm.h | 87 | ||||
-rw-r--r-- | winsup/cygwin/include/sys/ipc.h | 1 | ||||
-rw-r--r-- | winsup/cygwin/include/sys/shm.h | 1 | ||||
-rw-r--r-- | winsup/cygwin/shm.cc | 179 |
7 files changed, 576 insertions, 184 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index c350d7a8d6e..c8720dd5b39 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,81 @@ +2002-07-03 Conrad Scott <conrad.scott@dsl.pipex.com> + + * cygserver_shm.cc: Implement the ipcs(8) interfaces, IPC_INFO, + SHM_STAT and SHM_INFO. + (server_shmmgr::segment_t::sequence): New static field. + (server_shmmgr::segment_t::key): Remove field, use the new + ds.shm_perm.key field instead. + (server_shmmgr::segment_t::shmid): Remove field. + (server_shmmgr::segment_t::intid): New field. + (server_shmmgr::segment_t::segment_t): Use the `key' argument to + initialise `ds.shm_perm.key'. Change from using `shmid' to + `intid'. + (server_shmmgr::_shmseg_cnt): Renamed from `_shmid_cnt'. + (server_shmmgr::_intid_max): Renamed from `_shmid_max. + (server_shmmgr::shmat): Move the out arguments to the start of the + argument list. Rename the `pid' argument as `cygpid'. Add + tracing. Pass an intid to `find ()', not a shmid. + (server_shmmgr::shmctl): Add separate out arguments. Rename the + `pid' argument as `cygpid'. Add support for the ipcs(8) + interfaces. Add tracing. Pass an intid to `find ()', not a + shmid. + (server_shmmgr::shmdt): Rename the `pid' argument as `cygpid'. + Add tracing. Pass an intid to `find ()', not a shmid. + (server_shmmgr::shmget): Add a separate out arguments. Rename the + `pid' argument as `cygpid'. Add tracing. + (server_shmmgr::server_shmmgr): Update for new field names. + (server_shmmgr::find_by_key): Update for the new `ds.shm_perm.key' + field. + (server_shmmgr::find): Update to use the new `segment_t::intid' + field. + (server_shmmgr::new_segment): Rename the `pid' argument as + `cygpid'. Check that the requested size is within bounds. Handle + new error result from `new_segment (key, HANDLE)'. + (server_shmmgr::new_segment): Work with intids, not shmids. Check + that the new intid is within bounds. Update for new field names. + (server_shmmgr::delete_segment): Pass an intid to `find ()', not a + shmid. Update for new field names. + (client_request_shm::serve): Check that the incoming message + length is the size of the `_parameters.in' struct, not of the + whole in/out parameter union. Likewise, set the outgoing message + length to the size of the `_parameters.out' struct. Update for + the new server_shmmgr interfaces. + * include/sys/ipc.h (ipc_perm::key): New field. + * include/sys/shm.h (SHM_INFO): New constant. + * cygserver_ipc.h (IPCMNI): New constant. + (ipc_int2ext): Add `sequence' argument and munge this into the + external ipc id. + (ipc_ext2int_subsys): Unmunge the sequence number from the + external ipc id. + (ipc_ext2int): Ditto. + (ipc_inc_id): Remove. + (ipc_dec_id): Remove. + * cygserver_shm.h (SHMMAX): New constant. + (SHMMIN): Ditto. + (SHMMNI): Ditto. + (SHMSEG): Ditto. + (SHMALL): Ditto. + (client_request_shm::_parameters): Re-arrange as a union of two + separate structs, one for in arguments, the other for out. + (client_request_shm::shmid): Update for the new parameter layout. + (client_request_shm::ds): Ditto. + (client_request_shm::info): New method. + * shm.cc (client_shmmgr::_shmat_cnt): New static field. + (client_shmmgr::shmat): Add locking. Add tracing. + (client_shmmgr::shmctl): Update for ipcs(8) commands. Add + tracing. Add more argument checking. + (client_shmmgr::shmdt): Add locking. Add tracing. Update the new + `_shmat_cnt' field. + (client_shmmgr::shmget): Add tracing. + (client_shmmgr::fixup_shms_after_fork): Add tracing. Add + consistency checking. + (client_shmmgr::attach): Add more tracing. + (client_shmmgr::new_segment): Update the new `_shmat_cnt' field. + (client_request_shm::client_request_shm): Update for the new + parameter layout. Set the outgoing message length to the size of + the `_parameters.in' struct, not of the whole in/out parameter + union. + 2002-07-02 Conrad Scott <conrad.scott@dsl.pipex.com> * shm.cc: Remove the use of a static client_shmmgr object. diff --git a/winsup/cygwin/cygserver_ipc.h b/winsup/cygwin/cygserver_ipc.h index f57a4649d8c..0d0ebbc76a0 100644 --- a/winsup/cygwin/cygserver_ipc.h +++ b/winsup/cygwin/cygserver_ipc.h @@ -13,59 +13,72 @@ details. */ #ifndef __CYGSERVER_IPC_H__ #define __CYGSERVER_IPC_H__ +#include <assert.h> #include <limits.h> /* For OPEN_MAX. */ /* - * The sysv ipc id's (msgid, semid, shmid) are small integers arranged - * such that they no subsystem will generate the same id as some other - * subsystem, and nor do these ids overlap file descriptors (the other - * common small integer ids). Since Cygwin can allocate more than - * OPEN_MAX file descriptor, it can't be guarenteed not to overlap, - * but it should help catch some errors. + * The sysv ipc id's (msgid, semid, shmid) are integers arranged such + * that they no subsystem will generate the same id as some other + * subsystem; nor do these ids overlap file descriptors (the other + * common integer ids). Since Cygwin can allocate more than OPEN_MAX + * file descriptors, it can't be guaranteed not to overlap, but it + * should help catch some errors. * * msgid's: OPEN_MAX, OPEN_MAX + 3, OPEN_MAX + 6, . . . - * semid's: OPEN_MAX + 1, OPEN_MAX + 4, OPEN_MAX + 7, . . . - * shmid's: OPEN_MAX + 2, OPEN_MAX + 5, OPEN_MAX + 8, . . . + * semid's: OPEN_MAX + 1, OPEN_MAX + 4, OPEN_MAX + 7, . . . + * shmid's: OPEN_MAX + 2, OPEN_MAX + 5, OPEN_MAX + 8, . . . * - * Internal ipc id's, which are 0, 1, ... within each subsystem, are - * used solely by the ipcs(8) interface. + * To further ensure that ids are unique, if ipc objects are created + * and destroyed and then re-created, they are given new ids by + * munging the basic id (as above) with a sequence number. + * + * Internal ipc id's, which are 0, 1, ... within each subsystem (and + * not munged with a sequence number), are used solely by the ipcs(8) + * interface. */ -enum ipc_subsys_t { - IPC_MSGOP = 0, - IPC_SEMOP = 1, - IPC_SHMOP = 2, - IPC_SUBSYS_COUNT -}; +enum ipc_subsys_t + { + IPC_MSGOP = 0, + IPC_SEMOP = 1, + IPC_SHMOP = 2, + IPC_SUBSYS_COUNT + }; -inline int -ipc_int2ext (const int id, const ipc_subsys_t subsys) -{ - return OPEN_MAX + (id * IPC_SUBSYS_COUNT) + subsys; -} +/* + * IPCMNI - The absolute maximum number of simultaneous ipc ids for + * any one subsystem. + */ -inline int -ipc_ext2int (const int id) -{ - return (id - OPEN_MAX) / IPC_SUBSYS_COUNT; -} +enum + { + IPCMNI = 0x10000 // Must be a power of two. + }; inline int -ipc_ext2int_subsys (const int id) +ipc_int2ext (const int intid, const ipc_subsys_t subsys, long & sequence) { - return (id - OPEN_MAX) % IPC_SUBSYS_COUNT; + assert (0 <= intid && intid < IPCMNI); + + const long tmp = InterlockedIncrement (&sequence); + + return (((tmp & 0x7fff) << 16) + | (OPEN_MAX + (intid * IPC_SUBSYS_COUNT) + subsys)); } inline int -ipc_inc_id (const int id, const ipc_subsys_t subsys) +ipc_ext2int_subsys (const int extid) { - return id + IPC_SUBSYS_COUNT; + return ((extid & (IPCMNI - 1)) - OPEN_MAX) % IPC_SUBSYS_COUNT; } inline int -ipc_dec_id (const int id, const ipc_subsys_t subsys) +ipc_ext2int (const int extid, const ipc_subsys_t subsys) { - return id - IPC_SUBSYS_COUNT; + if (ipc_ext2int_subsys (extid) != subsys) + return -1; + else + return ((extid & (IPCMNI - 1)) - OPEN_MAX) / IPC_SUBSYS_COUNT; } #endif /* __CYGSERVER_IPC_H__ */ diff --git a/winsup/cygwin/cygserver_shm.cc b/winsup/cygwin/cygserver_shm.cc index 5551494161d..ea710f37648 100755 --- a/winsup/cygwin/cygserver_shm.cc +++ b/winsup/cygwin/cygserver_shm.cc @@ -63,7 +63,7 @@ details. */ { ACTION; } \ if (MSG && !LocalFree (MSG)) \ { \ - system_printf ("failed to free memory at %p, error = %lu", \ + system_printf ("failed to free memory at 0x%p, error = %lu", \ MSG, GetLastError ()); \ } \ SetLastError (lasterr); \ @@ -86,30 +86,39 @@ private: // Bits for the _flg field. enum { REMOVED = 0x01 }; - const key_t key; + static long sequence; + + const int intid; const int shmid; - struct shmid_ds ds; + shmid_ds ds; int flg; const HANDLE hFileMap; segment_t *next; - segment_t (const key_t key, const int shmid, const HANDLE hFileMap) - : key (key), shmid (shmid), flg (0), hFileMap (hFileMap), next (NULL) + segment_t (const key_t key, const int intid, const HANDLE hFileMap) + : intid (intid), + shmid (ipc_int2ext (intid, IPC_SHMOP, sequence)), + flg (0), + hFileMap (hFileMap), + next (NULL) { - bzero (&ds, sizeof (ds)); + assert (0 <= intid && intid < SHMMNI); + + memset (&ds, '\0', sizeof (ds)); + ds.shm_perm.key = key; } }; public: static server_shmmgr & instance (); - int shmat (int shmid, int shmflg, - pid_t, HANDLE & hFileMap, - process_cache *, DWORD winpid); - int shmctl (int shmid, int cmd, struct shmid_ds &, pid_t); + int shmat (HANDLE & hFileMap, + int shmid, int shmflg, pid_t, process_cache *, DWORD winpid); + int shmctl (int & out_shmid, shmid_ds & out_ds, shminfo & out_info, + const int shmid, int cmd, const shmid_ds &, pid_t); int shmdt (int shmid, pid_t); - int shmget (key_t, size_t, int shmflg, pid_t, uid_t, gid_t); + int shmget (int & out_shmid, key_t, size_t, int shmflg, pid_t, uid_t, gid_t); private: static server_shmmgr *_instance; @@ -118,10 +127,10 @@ private: static void initialise_instance (); CRITICAL_SECTION _segments_lock; - segment_t *_segments_head; // A list sorted by shmid. + segment_t *_segments_head; // A list sorted by int_id. - int _shmid_cnt; // Number of shmid's allocated (for ipcs(8)). - int _shmid_max; // Highest shmid yet allocated (for ipcs(8)). + int _shmseg_cnt; // Number of shm segments (for ipcs(8)). + int _intid_max; // Highest intid yet allocated (for ipcs(8)). server_shmmgr (); ~server_shmmgr (); @@ -131,7 +140,7 @@ private: server_shmmgr & operator= (const server_shmmgr &); segment_t *find_by_key (key_t); - segment_t *find (int shmid, segment_t **previous = NULL); + segment_t *find (int intid, segment_t **previous = NULL); int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t); @@ -139,6 +148,8 @@ private: 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; @@ -161,21 +172,29 @@ server_shmmgr::instance () *---------------------------------------------------------------------------*/ int -server_shmmgr::shmat (const int shmid, const int shmflg, - const pid_t pid, HANDLE & hFileMap, +server_shmmgr::shmat (HANDLE & hFileMap, + const int shmid, const int shmflg, + const pid_t cygpid, process_cache *const cache, const DWORD winpid) { + syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d(%lu)", + shmid, shmflg, cygpid, winpid); + process *const client = cache->process (winpid); if (!client) { + syscall_printf (("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) " + "for %d(%lu)"), + 0, EAGAIN, shmid, shmflg, + cygpid, winpid); return -EAGAIN; } - int result; + int result = 0; EnterCriticalSection (&_segments_lock); - segment_t *const segptr = find (shmid); + segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP)); if (!segptr) result = -EINVAL; @@ -189,25 +208,31 @@ server_shmmgr::shmat (const int shmid, const int shmflg, { with_strerr (msg, syscall_printf (("failed to duplicate handle for client " - "[key = %lld, shmid = %d, handle = %p]:" + "[key = 0x%016llx, shmid = %d, handle = 0x%x]:" "%s"), - segptr->key, segptr->shmid, + segptr->ds.shm_perm.key, segptr->shmid, segptr->hFileMap, msg)); result = -EACCES; // FIXME } else { - segptr->ds.shm_lpid = pid; + segptr->ds.shm_lpid = cygpid; segptr->ds.shm_nattch += 1; segptr->ds.shm_atime = time (NULL); // FIXME: sub-second times. - - result = 0; } LeaveCriticalSection (&_segments_lock); client->release (); + + if (result < 0) + syscall_printf ("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) for %d(%lu)", + -result, shmid, shmflg, cygpid, winpid); + else + syscall_printf ("0x%x = shmat (shmid = %d, shmflg = 0%o) for %d(%lu)", + hFileMap, shmid, shmflg, cygpid, winpid); + return result; } @@ -216,61 +241,100 @@ server_shmmgr::shmat (const int shmid, const int shmflg, *---------------------------------------------------------------------------*/ int -server_shmmgr::shmctl (const int shmid, const int cmd, struct shmid_ds & ds, - const pid_t pid) +server_shmmgr::shmctl (int & out_shmid, shmid_ds & out_ds, shminfo & out_info, + const int shmid, const int cmd, const shmid_ds & ds, + const pid_t cygpid) { - int result; - EnterCriticalSection (&_segments_lock); + syscall_printf ("shmctl (shmid = %d, cmd = 0x%x) for %d", + shmid, cmd, cygpid); - segment_t *const segptr = find (shmid); + int result = 0; + EnterCriticalSection (&_segments_lock); - if (!segptr) - result = -EINVAL; - else + switch (cmd) { - switch (cmd) - { - case IPC_STAT: - ds = segptr->ds; - result = 0; - 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 = pid; - segptr->ds.shm_ctime = time (NULL); // FIXME: sub-second times. - result = 0; - break; - - case IPC_RMID: - if (segptr->flg & segment_t::REMOVED) - result = -EIDRM; - else + 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) { - segptr->flg |= segment_t::REMOVED; - if (!segptr->ds.shm_nattch) - delete_segment (segptr); - result = 0; + 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 = cygpid; + segptr->ds.shm_ctime = time (NULL); // FIXME: sub-second times. + break; + + case IPC_RMID: + if (segptr->flg & segment_t::REMOVED) + result = -EIDRM; + else + { + segptr->flg |= segment_t::REMOVED; + if (!segptr->ds.shm_nattch) + delete_segment (segptr); + } + break; + + case SHM_STAT: // ipcs(8) i'face. + out_ds = segptr->ds; + out_shmid = segptr->shmid; + break; } - break; + } + break; - case IPC_INFO: - result = -EINVAL; - break; + case IPC_INFO: + out_info.shmmax = SHMMAX; + out_info.shmmin = SHMMIN; + out_info.shmmni = SHMMNI; + out_info.shmseg = SHMSEG; + out_info.shmall = SHMALL; + break; - case SHM_STAT: - result = -EINVAL; - break; + case SHM_INFO: // ipcs(8) i'face. + out_shmid = _intid_max; + break; - default: - result = -EINVAL; - break; - } + default: + result = -EINVAL; + break; } LeaveCriticalSection (&_segments_lock); + + if (result < 0) + syscall_printf (("-1 [%d] = " + "shmctl (shmid = %d, cmd = 0x%x) for %d"), + -result, + shmid, cmd, cygpid); + else + syscall_printf (("%d = " + "shmctl (shmid = %d, cmd = 0x%x) for %d"), + ((cmd == SHM_STAT || cmd == SHM_INFO) + ? out_shmid + : result), + shmid, cmd, cygpid); + return result; } @@ -279,12 +343,15 @@ server_shmmgr::shmctl (const int shmid, const int cmd, struct shmid_ds & ds, *---------------------------------------------------------------------------*/ int -server_shmmgr::shmdt (const int shmid, const pid_t pid) +server_shmmgr::shmdt (const int shmid, const pid_t cygpid) { - int result; + syscall_printf ("shmdt (shmid = %d) for %d", + shmid, cygpid); + + int result = 0; EnterCriticalSection (&_segments_lock); - segment_t *const segptr = find (shmid); + segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP)); if (!segptr) result = -EINVAL; @@ -292,17 +359,23 @@ server_shmmgr::shmdt (const int shmid, const pid_t pid) { assert (segptr->ds.shm_nattch > 0); - segptr->ds.shm_lpid = pid; + segptr->ds.shm_lpid = cygpid; segptr->ds.shm_nattch -= 1; segptr->ds.shm_dtime = time (NULL); // FIXME: sub-second times. if (!segptr->ds.shm_nattch && (segptr->flg & segment_t::REMOVED)) delete_segment (segptr); - - result = 0; } LeaveCriticalSection (&_segments_lock); + + if (result < 0) + syscall_printf ("-1 [%d] = shmdt (shmid = %d) for %d", + -result, shmid, cygpid); + else + syscall_printf ("%d = shmdt (shmid = %d) for %d", + result, shmid, cygpid); + return result; } @@ -311,22 +384,27 @@ server_shmmgr::shmdt (const int shmid, const pid_t pid) *---------------------------------------------------------------------------*/ int -server_shmmgr::shmget (const key_t key, const size_t size, const int shmflg, - const pid_t pid, const uid_t uid, const gid_t gid) +server_shmmgr::shmget (int & out_shmid, + const key_t key, const size_t size, const int shmflg, + const pid_t cygpid, const uid_t uid, const gid_t gid) { - int result; + syscall_printf ("shmget (key = 0x%016llx, size = %u, shmflg = 0%o) for %d", + key, size, shmflg, + cygpid); + + int result = 0; EnterCriticalSection (&_segments_lock); /* Does a segment already exist with that key? */ if (key == IPC_PRIVATE) - result = new_segment (key, size, shmflg, pid, uid, gid); + result = new_segment (key, size, shmflg, cygpid, uid, gid); else { segment_t *const segptr = find_by_key (key); if (!segptr) if (shmflg & IPC_CREAT) - result = new_segment (key, size, shmflg, pid, uid, gid); + result = new_segment (key, size, shmflg, cygpid, uid, gid); else result = -ENOENT; else if (segptr->flg & segment_t::REMOVED) @@ -340,6 +418,28 @@ server_shmmgr::shmget (const key_t key, const size_t size, const int shmflg, } 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"), + -result, + key, size, shmflg, + cygpid); + else + syscall_printf (("%d = " + "shmget (key = 0x%016llx, size = %u, shmflg = 0%o) " + "for %d"), + out_shmid, + key, size, shmflg, + cygpid); + return result; } @@ -361,8 +461,8 @@ server_shmmgr::initialise_instance () server_shmmgr::server_shmmgr () : _segments_head (NULL), - _shmid_cnt (0), - _shmid_max (0) + _shmseg_cnt (0), + _intid_max (0) { InitializeCriticalSection (&_segments_lock); } @@ -384,7 +484,7 @@ 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->key == key) + if (segptr->ds.shm_perm.key == key) return segptr; return NULL; @@ -395,15 +495,15 @@ server_shmmgr::find_by_key (const key_t key) *---------------------------------------------------------------------------*/ server_shmmgr::segment_t * -server_shmmgr::find (const int shmid, segment_t **previous) +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->shmid == shmid) + if (segptr->intid == intid) return segptr; - else if (segptr->shmid > shmid) // The list is sorted by shmid. + else if (segptr->intid > intid) // The list is sorted by intid. return NULL; else if (previous) *previous = segptr; @@ -419,10 +519,13 @@ int server_shmmgr::new_segment (const key_t key, const size_t size, const int shmflg, - const pid_t pid, + 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, @@ -440,11 +543,17 @@ server_shmmgr::new_segment (const key_t key, segment_t *const segptr = new_segment (key, 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 = pid; + segptr->ds.shm_cpid = cygpid; segptr->ds.shm_ctime = time (NULL); // FIXME: sub-second times. return segptr->shmid; @@ -454,24 +563,31 @@ server_shmmgr::new_segment (const key_t key, * server_shmmgr::new_segment () * * Allocate a new segment for the given key and file map with the - * lowest available shmid and insert into the segment map. + * lowest available intid and insert into the segment map. *---------------------------------------------------------------------------*/ server_shmmgr::segment_t * server_shmmgr::new_segment (const key_t key, const HANDLE hFileMap) { - int shmid = ipc_int2ext (0, IPC_SHMOP); // Next expected shmid value. + int intid = 0; // Next expected intid value. segment_t *previous = NULL; // Insert pointer. - // Find first unallocated shmid. - for ( segment_t *segptr = _segments_head; - segptr && segptr->shmid == shmid; - segptr = segptr->next, shmid = ipc_inc_id (shmid, IPC_SHMOP)) + // Find first unallocated intid. + for (segment_t *segptr = _segments_head; + segptr && segptr->intid == intid; + segptr = segptr->next, intid++) { previous = segptr; } - segment_t *const segptr = safe_new (segment_t, key, shmid, hFileMap); + /* 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); @@ -486,9 +602,9 @@ server_shmmgr::new_segment (const key_t key, const HANDLE hFileMap) _segments_head = segptr; } - _shmid_cnt += 1; - if (shmid > _shmid_max) - _shmid_max = shmid; + _shmseg_cnt += 1; + if (intid > _intid_max) + _intid_max = intid; return segptr; } @@ -506,7 +622,7 @@ server_shmmgr::delete_segment (segment_t *const segptr) segment_t *previous = NULL; - const segment_t *const tmp = find (segptr->shmid, &previous); + const segment_t *const tmp = find (segptr->intid, &previous); assert (tmp == segptr); assert (previous ? previous->next == segptr : _segments_head == segptr); @@ -519,11 +635,11 @@ server_shmmgr::delete_segment (segment_t *const segptr) if (!CloseHandle (segptr->hFileMap)) with_strerr (msg, syscall_printf (("failed to close file map " - "[handle = %p]: %s"), + "[handle = 0x%x]: %s"), segptr->hFileMap, msg)); - assert (_shmid_cnt > 0); - _shmid_cnt -= 1; + assert (_shmseg_cnt > 0); + _shmseg_cnt -= 1; safe_delete (segment_t, segptr); } @@ -551,7 +667,7 @@ client_request_shm::serve (transport_layer_base *const conn, assert (!error_code ()); - if (msglen () != sizeof (_parameters)) + if (msglen () != sizeof (_parameters.in)) { syscall_printf ("bad request body length: expecting %lu bytes, got %lu", sizeof (_parameters), msglen ()); @@ -568,25 +684,28 @@ client_request_shm::serve (transport_layer_base *const conn, switch (_parameters.in.shmop) { case SHMOP_shmget: - result = shmmgr.shmget (_parameters.in.key, _parameters.in.size, + result = shmmgr.shmget (_parameters.out.shmid, + _parameters.in.key, _parameters.in.size, _parameters.in.shmflg, _parameters.in.cygpid, _parameters.in.uid, _parameters.in.gid); - _parameters.shmid = result; break; case SHMOP_shmat: - result = shmmgr.shmat (_parameters.shmid, _parameters.in.shmflg, - _parameters.in.cygpid, _parameters.out.hFileMap, + result = shmmgr.shmat (_parameters.out.hFileMap, + _parameters.in.shmid, _parameters.in.shmflg, + _parameters.in.cygpid, cache, _parameters.in.winpid); break; case SHMOP_shmdt: - result = shmmgr.shmdt (_parameters.shmid, _parameters.in.cygpid); + result = shmmgr.shmdt (_parameters.in.shmid, _parameters.in.cygpid); break; case SHMOP_shmctl: - result = shmmgr.shmctl (_parameters.shmid, _parameters.in.cmd, - _parameters.ds, _parameters.in.cygpid); + result = shmmgr.shmctl (_parameters.out.shmid, + _parameters.out.ds, _parameters.out.info, + _parameters.in.shmid, _parameters.in.cmd, + _parameters.in.ds, _parameters.in.cygpid); break; } @@ -597,4 +716,6 @@ client_request_shm::serve (transport_layer_base *const conn, error_code (-result); msglen (0); } + else + msglen (sizeof (_parameters.out)); } diff --git a/winsup/cygwin/cygserver_shm.h b/winsup/cygwin/cygserver_shm.h index 5f04d6bebe1..b323651fbbd 100644 --- a/winsup/cygwin/cygserver_shm.h +++ b/winsup/cygwin/cygserver_shm.h @@ -15,14 +15,36 @@ details. */ #define __CYGSERVER_SHM_H__ #include <sys/types.h> +#include <sys/shm.h> #include <assert.h> +#include <limits.h> -#include <sys/shm.h> +#include "cygserver_ipc.h" #include "cygwin/cygserver.h" /*---------------------------------------------------------------------------* + * Values for the shminfo entries. + * + * Nb. The values are segregated between two enums so that the `small' + * values aren't promoted to `unsigned long' equivalents. + *---------------------------------------------------------------------------*/ + +enum + { + SHMMAX = ULONG_MAX, + SHMSEG = ULONG_MAX, + SHMALL = ULONG_MAX + }; + +enum + { + SHMMIN = 1, + SHMMNI = IPCMNI // Must be <= IPCMNI. + }; + +/*---------------------------------------------------------------------------* * class client_request_shm *---------------------------------------------------------------------------*/ @@ -46,7 +68,7 @@ public: #ifdef __INSIDE_CYGWIN__ client_request_shm (int shmid, int shmflg); // shmat - client_request_shm (int shmid, int cmd, const struct shmid_ds *); // shmctl + client_request_shm (int shmid, int cmd, const shmid_ds *); // shmctl client_request_shm (int shmid); // shmdt client_request_shm (key_t, size_t, int shmflg); // shmget #endif @@ -56,47 +78,54 @@ public: int shmid () const { assert (!error_code ()); - return _parameters.shmid; + return _parameters.out.shmid; + } + + HANDLE hFileMap () const + { + assert (!error_code ()); + return _parameters.out.hFileMap; } - const struct shmid_ds & ds () const + const shmid_ds & ds () const { assert (!error_code ()); - return _parameters.ds; + return _parameters.out.ds; } - HANDLE hFileMap () const + const shminfo & info () const { assert (!error_code ()); - return _parameters.out.hFileMap; + return _parameters.out.info; } private: - struct + union { - int shmid; - struct shmid_ds ds; - - union + struct { - struct + shmop_t shmop; + key_t key; + size_t size; + int shmflg; + int shmid; + int cmd; + pid_t cygpid; + DWORD winpid; + uid_t uid; + gid_t gid; + shmid_ds ds; + } in; + + struct { + int shmid; + HANDLE hFileMap; + union { - shmop_t shmop; - key_t key; - size_t size; - int shmflg; - int cmd; - pid_t cygpid; - DWORD winpid; - uid_t uid; - gid_t gid; - } in; - - struct - { - HANDLE hFileMap; - } out; - }; + shmid_ds ds; + shminfo info; + }; + } out; } _parameters; #ifndef __INSIDE_CYGWIN__ diff --git a/winsup/cygwin/include/sys/ipc.h b/winsup/cygwin/include/sys/ipc.h index b9aa7c2e661..a809fd4ec7a 100644 --- a/winsup/cygwin/include/sys/ipc.h +++ b/winsup/cygwin/include/sys/ipc.h @@ -28,6 +28,7 @@ struct ipc_perm { uid_t cuid; gid_t cgid; mode_t mode; + key_t key; }; /* diff --git a/winsup/cygwin/include/sys/shm.h b/winsup/cygwin/include/sys/shm.h index 190f9bad4a6..15be9e6494f 100644 --- a/winsup/cygwin/include/sys/shm.h +++ b/winsup/cygwin/include/sys/shm.h @@ -36,6 +36,7 @@ extern "C" * Commands 4000-4fff are reserved for SHM_xxx. */ #define SHM_STAT 0x4000 /* For ipcs(8) */ +#define SHM_INFO 0x4001 /* For ipcs(8) */ typedef long int shmatt_t; diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc index cb3caa3d077..028310b346a 100644 --- a/winsup/cygwin/shm.cc +++ b/winsup/cygwin/shm.cc @@ -15,6 +15,7 @@ details. */ #include <sys/types.h> +#include <assert.h> #include <errno.h> #include <stdio.h> #include <unistd.h> @@ -98,7 +99,7 @@ public: static client_shmmgr & instance (); void *shmat (int shmid, const void *, int shmflg); - int shmctl (int shmid, int cmd, struct shmid_ds *); + int shmctl (int shmid, int cmd, shmid_ds *); int shmdt (const void *); int shmget (key_t, size_t, int shmflg); @@ -108,7 +109,9 @@ private: static NO_COPY client_shmmgr *_instance; CRITICAL_SECTION _segments_lock; - static segment_t *_segments_head; // A list sorted by shmaddr. + 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 (); @@ -126,6 +129,7 @@ private: /* static */ NO_COPY client_shmmgr *client_shmmgr::_instance; /* static */ client_shmmgr::segment_t *client_shmmgr::_segments_head; +/* static */ long client_shmmgr::_shmat_cnt; /*---------------------------------------------------------------------------* * client_shmmgr::instance () @@ -151,6 +155,11 @@ client_shmmgr::shmat (const int shmid, const void *const shmaddr, const int shmflg) { + syscall_printf ("shmat (shmid = %d, shmaddr = 0x%p, shmflg = 0%o)", + shmid, shmaddr, shmflg); + + EnterCriticalSection (&_segments_lock); + HANDLE hFileMap = NULL; void *const ptr = attach (shmid, shmaddr, shmflg, hFileMap); @@ -158,6 +167,14 @@ client_shmmgr::shmat (const int shmid, if (ptr) new_segment (shmid, ptr, shmflg, hFileMap); + LeaveCriticalSection (&_segments_lock); + + if (ptr) + syscall_printf ("0x%p = shmat (shmid = %d, shmaddr = 0x%p, shmflg = 0%o)", + ptr, shmid, shmaddr, shmflg); + // else + // See the syscall_printf in client_shmmgr::attach (). + return (ptr ? ptr : (void *) -1); } @@ -168,26 +185,94 @@ client_shmmgr::shmat (const int shmid, int client_shmmgr::shmctl (const int shmid, const int cmd, - struct shmid_ds *const buf) + shmid_ds *const buf) { - client_request_shm request (shmid, cmd, buf); + syscall_printf ("shmctl (shmid = %d, cmd = 0x%x, buf = 0x%p)", + shmid, cmd, buf); + + // Check parameters and set up in parameters as required. + + const shmid_ds *in_buf = NULL; + + switch (cmd) + { + case IPC_SET: + if (__check_invalid_read_ptr_errno (buf, sizeof (shmid_ds))) + { + syscall_printf (("-1 [EFAULT] = " + "shmctl (shmid = %d, cmd = 0x%x, buf = 0x%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 (shmid_ds))) + { + syscall_printf (("-1 [EFAULT] = " + "shmctl (shmid = %d, cmd = 0x%x, buf = 0x%p)"), + shmid, cmd, buf); + set_errno (EFAULT); + return -1; + } + break; + + case IPC_INFO: + if (__check_null_invalid_struct_errno (buf, sizeof (shminfo))) + { + syscall_printf (("-1 [EFAULT] = " + "shmctl (shmid = %d, cmd = 0x%x, buf = 0x%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 = 0x%p)"), + request.error_code (), shmid, cmd, buf); set_errno (request.error_code ()); return -1; } - // Some commands require special processing, e.g. for out parameters. + // Some commands require special processing for their out parameters. + + int result = 0; switch (cmd) { case IPC_STAT: *buf = request.ds (); break; + + case IPC_INFO: + *(shminfo *) buf = request.info (); + break; + + case SHM_STAT: // ipcs(8) i'face. + *buf = request.ds (); + result = request.shmid (); + break; + + case SHM_INFO: // ipcs(8) i'face. + result = request.shmid (); + break; } - return 0; + syscall_printf ("%d = shmctl (shmid = %d, cmd = 0x%x, buf = 0x%p)", + result, shmid, cmd, buf); + + return result; } /*---------------------------------------------------------------------------* @@ -202,12 +287,18 @@ client_shmmgr::shmctl (const int shmid, int client_shmmgr::shmdt (const void *const shmaddr) { + syscall_printf ("shmdt (shmaddr = 0x%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 = 0x%p)", shmaddr); set_errno (EINVAL); return -1; } @@ -219,6 +310,11 @@ client_shmmgr::shmdt (const void *const shmaddr) else _segments_head = segptr->next; + LeaveCriticalSection (&_segments_lock); + + const long cnt = InterlockedDecrement (&_shmat_cnt); + assert (cnt >= 0); + if (!UnmapViewOfFile ((void *) shmaddr)) with_strerr (msg, syscall_printf (("failed to unmap view " @@ -246,46 +342,85 @@ client_shmmgr::shmdt (const void *const shmaddr) delete segptr; + syscall_printf ("0 = shmdt (shmaddr = 0x%p)", shmaddr); + return 0; } /*---------------------------------------------------------------------------* * client_shmmgr::shmget () + * + * The `key = 0x%08x%08x' contortions in the tracing statements is + * because small_printf () doesn't support 64-bit integers. *---------------------------------------------------------------------------*/ int client_shmmgr::shmget (const key_t key, const size_t size, const int shmflg) { + syscall_printf ("shmget (key = 0x%08x%08x, size = %u, shmflg = 0%o)", + (unsigned) (key >> 32), (unsigned) key, size, shmflg); + client_request_shm request (key, size, shmflg); if (request.make_request () == -1 || request.error_code ()) { + syscall_printf (("-1 [%d] = " + "shmget (key = 0x%08x%08x, size = %u, shmflg = 0%o)"), + request.error_code (), + (unsigned) (key >> 32), (unsigned) key, size, shmflg); set_errno (request.error_code ()); return -1; } + syscall_printf (("%d = shmget (key = 0x%08x%08x, size = %u, shmflg = 0%o)"), + request.shmid (), + (unsigned) (key >> 32), (unsigned) key, size, shmflg); + return request.shmid (); } /*---------------------------------------------------------------------------* * client_shmmgr::fixup_shms_after_fork () * - * The hFileMap handles are non-inheritable: so the + * 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 shared memory segments"); + 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; } @@ -344,6 +479,9 @@ client_shmmgr::attach (const int shmid, if (request.make_request () == -1 || request.error_code ()) { + syscall_printf (("-1 [%d] = " + "shmat (shmid = %d, shmaddr = 0x%p, shmflg = 0%o)"), + request.error_code (), shmid, shmaddr, shmflg); set_errno (request.error_code ()); return NULL; } @@ -444,6 +582,9 @@ client_shmmgr::new_segment (const int shmid, _segments_head = segptr; } + const long cnt = InterlockedIncrement (&_shmat_cnt); + assert (cnt > 0); + return segptr; } @@ -462,7 +603,7 @@ shmat (const int shmid, const void *const shmaddr, const int shmflg) *---------------------------------------------------------------------------*/ extern "C" int -shmctl (const int shmid, const int cmd, struct shmid_ds *const buf) +shmctl (const int shmid, const int cmd, shmid_ds *const buf) { return shmmgr.shmctl (shmid, cmd, buf); } @@ -506,13 +647,15 @@ client_request_shm::client_request_shm (const int shmid, const int shmflg) { _parameters.in.shmop = SHMOP_shmat; - _parameters.shmid = shmid; + _parameters.in.shmid = shmid; _parameters.in.shmflg = shmflg; _parameters.in.cygpid = getpid (); _parameters.in.winpid = GetCurrentProcessId (); _parameters.in.uid = geteuid (); _parameters.in.gid = getegid (); + + msglen (sizeof (_parameters.in)); } /*---------------------------------------------------------------------------* @@ -521,20 +664,22 @@ client_request_shm::client_request_shm (const int shmid, const int shmflg) client_request_shm::client_request_shm (const int shmid, const int cmd, - const struct shmid_ds * const buf) + const 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.shmid = shmid; _parameters.in.cmd = cmd; + if (buf) + _parameters.in.ds = *buf; _parameters.in.cygpid = getpid (); _parameters.in.winpid = GetCurrentProcessId (); _parameters.in.uid = geteuid (); _parameters.in.gid = getegid (); + + msglen (sizeof (_parameters.in)); } /*---------------------------------------------------------------------------* @@ -546,12 +691,14 @@ client_request_shm::client_request_shm (const int shmid) { _parameters.in.shmop = SHMOP_shmdt; - _parameters.shmid = shmid; + _parameters.in.shmid = shmid; _parameters.in.cygpid = getpid (); _parameters.in.winpid = GetCurrentProcessId (); _parameters.in.uid = geteuid (); _parameters.in.gid = getegid (); + + msglen (sizeof (_parameters.in)); } /*---------------------------------------------------------------------------* @@ -573,4 +720,6 @@ client_request_shm::client_request_shm (const key_t key, _parameters.in.winpid = GetCurrentProcessId (); _parameters.in.uid = geteuid (); _parameters.in.gid = getegid (); + + msglen (sizeof (_parameters.in)); } |