Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/cygserver_shm.cc')
-rwxr-xr-xwinsup/cygwin/cygserver_shm.cc367
1 files changed, 277 insertions, 90 deletions
diff --git a/winsup/cygwin/cygserver_shm.cc b/winsup/cygwin/cygserver_shm.cc
index 9c32642e0..27ca6ea7c 100755
--- a/winsup/cygwin/cygserver_shm.cc
+++ b/winsup/cygwin/cygserver_shm.cc
@@ -80,45 +80,96 @@ details. */
class server_shmmgr
{
private:
- class segment_t
+ class attach_t
{
public:
- // Bits for the _flg field.
- enum { REMOVED = 0x01 };
+ class process *const _client;
+ unsigned int _refcnt;
- static long _sequence;
+ 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 (const class process *);
+
+ private:
+ static long _sequence;
+
int _flg;
const HANDLE _hFileMap;
+ attach_t *_attach_head; // A list sorted by winpid;
- segment_t *_next;
+ attach_t *find (const class process *, attach_t **previous = NULL);
+ };
+
+ class cleanup_t : public cleanup_routine
+ {
+ public:
+ cleanup_t (segment_t *const segptr)
+ : _segptr (segptr)
+ {
+ assert (_segptr);
+ }
- 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)
+ virtual void cleanup (const class process *const client)
{
- assert (0 <= _intid && _intid < SHMMNI);
+ assert (_segptr);
- memset (&_ds, '\0', sizeof (_ds));
- _ds.shm_perm.key = key;
+ shmmgr.shmdt (_segptr->_shmid, client);
}
+
+ private:
+ segment_t *const _segptr;
};
public:
static server_shmmgr & instance ();
int shmat (HANDLE & hFileMap,
- int shmid, int shmflg, pid_t, process_cache *, DWORD winpid);
+ 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 &, pid_t);
- int shmdt (int shmid, pid_t);
+ int shmdt (int shmid, const class process *);
int shmget (int & out_shmid, key_t, size_t, int shmflg, pid_t, uid_t, gid_t);
private:
@@ -132,6 +183,7 @@ private:
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 ();
@@ -156,6 +208,168 @@ private:
/* 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))
+ with_strerr
+ (msg,
+ syscall_printf (("failed to close file map [handle = 0x%x]: %s"),
+ _hFileMap, msg));
+}
+
+/*---------------------------------------------------------------------------*
+ * 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))
+ {
+ with_strerr
+ (msg,
+ syscall_printf (("failed to duplicate handle for client "
+ "[key = 0x%016llx, shmid = %d, handle = 0x%x]:"
+ "%s"),
+ _ds.shm_perm.key, _shmid, _hFileMap,
+ msg));
+
+ 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 (const class process *const client)
+{
+ attach_t *previous = NULL;
+ attach_t *const attptr = find (client, &previous);
+
+ if (!attptr)
+ return -EINVAL;
+
+ 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 (attach_t, 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 ()
*---------------------------------------------------------------------------*/
@@ -176,22 +390,10 @@ server_shmmgr::instance ()
int
server_shmmgr::shmat (HANDLE & hFileMap,
const int shmid, const int shmflg,
- const pid_t cygpid,
- process_cache *const cache, const DWORD winpid)
+ class process *const client)
{
- 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;
- }
+ syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d",
+ shmid, shmflg, client->cygpid ());
int result = 0;
EnterCriticalSection (&_segments_lock);
@@ -200,40 +402,20 @@ server_shmmgr::shmat (HANDLE & hFileMap,
if (!segptr)
result = -EINVAL;
- else if (!DuplicateHandle (GetCurrentProcess (),
- segptr->_hFileMap,
- client->handle (),
- &hFileMap,
- 0,
- FALSE, // bInheritHandle
- DUPLICATE_SAME_ACCESS))
- {
- with_strerr (msg,
- syscall_printf (("failed to duplicate handle for client "
- "[key = 0x%016llx, shmid = %d, handle = 0x%x]:"
- "%s"),
- segptr->_ds.shm_perm.key, segptr->_shmid,
- segptr->_hFileMap, msg));
-
- result = -EACCES; // FIXME
- }
else
- {
- segptr->_ds.shm_lpid = cygpid;
- segptr->_ds.shm_nattch += 1;
- segptr->_ds.shm_atime = time (NULL); // FIXME: sub-second times.
- }
+ result = segptr->attach (client, hFileMap);
- LeaveCriticalSection (&_segments_lock);
+ if (!result)
+ _shm_atts += 1;
- client->release ();
+ LeaveCriticalSection (&_segments_lock);
if (result < 0)
- syscall_printf ("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) for %d(%lu)",
- -result, shmid, shmflg, cygpid, winpid);
+ syscall_printf ("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) for %d",
+ -result, shmid, shmflg, client->cygpid ());
else
- syscall_printf ("0x%x = shmat (shmid = %d, shmflg = 0%o) for %d(%lu)",
- hFileMap, shmid, shmflg, cygpid, winpid);
+ syscall_printf ("0x%x = shmat (shmid = %d, shmflg = 0%o) for %d",
+ hFileMap, shmid, shmflg, client->cygpid ());
return result;
}
@@ -291,12 +473,12 @@ server_shmmgr::shmctl (int & out_shmid,
break;
case IPC_RMID:
- if (segptr->_flg & segment_t::REMOVED)
+ if (segptr->is_deleted ())
result = -EIDRM;
else
{
- segptr->_flg |= segment_t::REMOVED;
- if (!segptr->_ds.shm_nattch)
+ segptr->mark_deleted ();
+ if (segptr->is_pending_delete ())
delete_segment (segptr);
}
break;
@@ -321,6 +503,7 @@ server_shmmgr::shmctl (int & out_shmid,
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:
@@ -351,10 +534,10 @@ server_shmmgr::shmctl (int & out_shmid,
*---------------------------------------------------------------------------*/
int
-server_shmmgr::shmdt (const int shmid, const pid_t cygpid)
+server_shmmgr::shmdt (const int shmid, const class process *const client)
{
syscall_printf ("shmdt (shmid = %d) for %d",
- shmid, cygpid);
+ shmid, client->cygpid ());
int result = 0;
EnterCriticalSection (&_segments_lock);
@@ -364,25 +547,22 @@ server_shmmgr::shmdt (const int shmid, const pid_t cygpid)
if (!segptr)
result = -EINVAL;
else
- {
- assert (segptr->_ds.shm_nattch > 0);
+ result = segptr->detach (client);
- segptr->_ds.shm_lpid = cygpid;
- segptr->_ds.shm_nattch -= 1;
- segptr->_ds.shm_dtime = time (NULL); // FIXME: sub-second times.
+ if (!result)
+ _shm_atts -= 1;
- if (!segptr->_ds.shm_nattch && (segptr->_flg & segment_t::REMOVED))
- delete_segment (segptr);
- }
+ if (segptr->is_pending_delete ())
+ delete_segment (segptr);
LeaveCriticalSection (&_segments_lock);
if (result < 0)
syscall_printf ("-1 [%d] = shmdt (shmid = %d) for %d",
- -result, shmid, cygpid);
+ -result, shmid, client->cygpid ());
else
syscall_printf ("%d = shmdt (shmid = %d) for %d",
- result, shmid, cygpid);
+ result, shmid, client->cygpid ());
return result;
}
@@ -414,7 +594,7 @@ server_shmmgr::shmget (int & out_shmid,
result = new_segment (key, size, shmflg, cygpid, uid, gid);
else
result = -ENOENT;
- else if (segptr->_flg & segment_t::REMOVED)
+ else if (segptr->is_deleted ())
result = -EIDRM;
else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
result = -EEXIST;
@@ -462,6 +642,8 @@ server_shmmgr::initialise_instance ()
assert (!_instance);
_instance = safe_new0 (server_shmmgr);
+
+ assert (_instance);
}
/*---------------------------------------------------------------------------*
@@ -472,6 +654,7 @@ server_shmmgr::server_shmmgr ()
: _segments_head (NULL),
_shm_ids (0),
_shm_tot (0),
+ _shm_atts (0),
_intid_max (0)
{
InitializeCriticalSection (&_segments_lock);
@@ -543,10 +726,10 @@ server_shmmgr::new_segment (const key_t key,
if (!hFileMap)
{
- with_strerr (msg,
- syscall_printf (("failed to create file mapping "
- "[size = %lu]: %s"),
- size, msg));
+ with_strerr
+ (msg,
+ syscall_printf (("failed to create file mapping [size = %lu]: %s"),
+ size, msg));
return -ENOMEM; // FIXME
}
@@ -580,6 +763,7 @@ 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;
@@ -632,8 +816,7 @@ void
server_shmmgr::delete_segment (segment_t *const segptr)
{
assert (segptr);
- assert (!segptr->_ds.shm_nattch);
- assert (segptr->_flg & segment_t::REMOVED);
+ assert (segptr->is_pending_delete ());
segment_t *previous = NULL;
@@ -647,12 +830,6 @@ server_shmmgr::delete_segment (segment_t *const segptr)
else
_segments_head = segptr->_next;
- if (!CloseHandle (segptr->_hFileMap))
- with_strerr (msg,
- syscall_printf (("failed to close file map "
- "[handle = 0x%x]: %s"),
- segptr->_hFileMap, msg));
-
assert (_shm_ids > 0);
_shm_ids -= 1;
_shm_tot -= segptr->_ds.shm_segsz;
@@ -695,6 +872,16 @@ client_request_shm::serve (transport_layer_base *const conn,
// 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)
@@ -709,12 +896,11 @@ client_request_shm::serve (transport_layer_base *const conn,
case SHMOP_shmat:
result = shmmgr.shmat (_parameters.out.hFileMap,
_parameters.in.shmid, _parameters.in.shmflg,
- _parameters.in.cygpid,
- cache, _parameters.in.winpid);
+ client);
break;
case SHMOP_shmdt:
- result = shmmgr.shmdt (_parameters.in.shmid, _parameters.in.cygpid);
+ result = shmmgr.shmdt (_parameters.in.shmid, client);
break;
case SHMOP_shmctl:
@@ -726,6 +912,7 @@ client_request_shm::serve (transport_layer_base *const conn,
break;
}
+ client->release ();
conn->revert_to_self ();
if (result < 0)