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:
authorConrad Scott <conrad.scott@dsl.pipex.com>2002-06-28 22:04:02 +0400
committerConrad Scott <conrad.scott@dsl.pipex.com>2002-06-28 22:04:02 +0400
commiteaedba9ac4665b81a284281cce2b63dab3f9941d (patch)
treecf70c3a96763287920b5e07eafb5ab12a70432c2 /winsup/cygwin
parent74a1317a08be0c435a58e61eda8a28a4b015d5f4 (diff)
* cygserver_ipc.h: New file.
* cygserver_shm.h: Re-written from scratch. * cygserver_shm.cc: Ditto. * shm.cc: Ditto.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/ChangeLog7
-rw-r--r--winsup/cygwin/cygserver_ipc.h71
-rwxr-xr-xwinsup/cygwin/cygserver_shm.cc1014
-rw-r--r--winsup/cygwin/cygserver_shm.h138
-rw-r--r--winsup/cygwin/shm.cc915
5 files changed, 1117 insertions, 1028 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 03f4dece3..88f24726a 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,12 @@
2002-06-28 Conrad Scott <conrad.scott@dsl.pipex.com>
+ * cygserver_ipc.h: New file.
+ * cygserver_shm.h: Re-written from scratch.
+ * cygserver_shm.cc: Ditto.
+ * shm.cc: Ditto.
+
+2002-06-28 Conrad Scott <conrad.scott@dsl.pipex.com>
+
* threaded_queue.h (class queue_request): Re-write.
(threaded_queue_thread_function): Remove.
(class queue_process_param): Remove.
diff --git a/winsup/cygwin/cygserver_ipc.h b/winsup/cygwin/cygserver_ipc.h
new file mode 100644
index 000000000..a69dd9c88
--- /dev/null
+++ b/winsup/cygwin/cygserver_ipc.h
@@ -0,0 +1,71 @@
+/* cygserver_ipc.h
+
+ Copyright 2002 Red Hat, Inc.
+
+ Originally written by Conrad Scott <conrad.scott@dsl.pipex.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. */
+
+#ifndef __CYGSERVER_IPC_H__
+#define __CYGSERVER_IPC_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.
+ *
+ * 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, . . .
+ *
+ * Internal ipc id's, which are 0, 1, ... within each subsystem, are
+ * used solely by the ipcs(8) interface.
+ */
+
+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;
+}
+
+inline int
+ipc_ext2int (const int id)
+{
+ return (id - OPEN_MAX) / IPC_SUBSYS_COUNT;
+}
+
+inline int
+ipc_ext2int_subsys (const int id)
+{
+ return (id - OPEN_MAX) % IPC_SUBSYS_COUNT;
+}
+
+inline int
+ipc_inc_id (const int id, const ipc_subsys_t subsys)
+{
+ return id + IPC_SUBSYS_COUNT;
+}
+
+inline int
+ipc_dec_id (const int id, const ipc_subsys_t subsys)
+{
+ return id - IPC_SUBSYS_COUNT;
+}
+
+#endif /* __CYGSERVER_IPC_H__ */
diff --git a/winsup/cygwin/cygserver_shm.cc b/winsup/cygwin/cygserver_shm.cc
index 0d30616b0..2df6522ed 100755
--- a/winsup/cygwin/cygserver_shm.cc
+++ b/winsup/cygwin/cygserver_shm.cc
@@ -1,8 +1,9 @@
-/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin
+/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin.
- Copyright 2001, 2002 Red Hat, Inc.
+ Copyright 2002 Red Hat, Inc.
- Originally written by Robert Collins <robert.collins@hotmail.com>
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
+ Based on code by Robert Collins <robert.collins@hotmail.com>.
This file is part of Cygwin.
@@ -12,13 +13,13 @@ details. */
#include "woutsup.h"
-#include <assert.h>
#include <errno.h>
+#include <pthread.h>
#include <stdio.h>
+#include <string.h>
#include <time.h>
-#include <unistd.h>
-#include "cygerrno.h"
+#include "cygserver_ipc.h"
#include "cygserver_shm.h"
#include "security.h"
@@ -26,581 +27,550 @@ details. */
#include "cygwin/cygserver_process.h"
#include "cygwin/cygserver_transport.h"
-// FIXME IS THIS CORRECT
-/* Implementation notes: We use two shared memory regions per key:
- * One for the control structure, and one for the shared memory.
- * While this has a higher overhead tham a single shared area,
- * It allows more flexability. As the entire code is transparent to the user
- * We can merge these in the future should it be needed.
- * Also, IPC_PRIVATE keys create unique mappings each time. The shm_ids just
- * keep monotonically incrementing - system wide.
- */
-size_t
-getsystemallocgranularity ()
+/*---------------------------------------------------------------------------*
+ * with_strerr ()
+ *---------------------------------------------------------------------------*/
+
+#define with_strerr(MSG, ACTION) \
+ do \
+ { \
+ const DWORD lasterr = GetLastError (); \
+ char *MSG = NULL; \
+ if (!FormatMessage ((FORMAT_MESSAGE_ALLOCATE_BUFFER \
+ | FORMAT_MESSAGE_FROM_SYSTEM \
+ | FORMAT_MESSAGE_IGNORE_INSERTS), \
+ NULL, \
+ lasterr, \
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), \
+ reinterpret_cast<char *>(&MSG), \
+ 0, \
+ NULL)) \
+ { \
+ MSG = static_cast<char *> \
+ (LocalAlloc (LMEM_FIXED, 24)); /* Big enough. */ \
+ if (!MSG) \
+ { \
+ system_printf (("failure in LocalAlloc(LMEM_FIXED, 16): " \
+ "error = %lu"), \
+ GetLastError ()); \
+ } \
+ else \
+ { \
+ snprintf (MSG, 24, "error = %lu", lasterr); \
+ } \
+ } \
+ SetLastError (lasterr); \
+ { ACTION; } \
+ if (MSG && !LocalFree (MSG)) \
+ { \
+ system_printf ("failed to free memory at %p, error = %lu", \
+ MSG, GetLastError ()); \
+ } \
+ SetLastError (lasterr); \
+ } while (false)
+
+/*---------------------------------------------------------------------------*
+ * class server_shmmgr
+ *
+ * A singleton class.
+ *---------------------------------------------------------------------------*/
+
+#define shmmgr (server_shmmgr::instance ())
+
+class server_shmmgr
{
- SYSTEM_INFO sysinfo;
- static size_t buffer_offset = 0;
- if (buffer_offset)
- return buffer_offset;
- GetSystemInfo (&sysinfo);
- buffer_offset = sysinfo.dwAllocationGranularity;
- return buffer_offset;
-}
+private:
+ class segment_t
+ {
+ public:
+ // Bits for the _flg field.
+ enum { REMOVED = 0x01 };
+
+ const key_t key;
+ const int shmid;
+ struct 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)
+ {
+ bzero (&ds, sizeof (ds));
+ }
+ };
-client_request_shm::client_request_shm ()
- : client_request (CYGSERVER_REQUEST_SHM, &parameters, sizeof (parameters))
+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 shmdt (int shmid, pid_t);
+ int shmget (key_t, size_t, int shmflg, pid_t, uid_t, gid_t);
+
+private:
+ CRITICAL_SECTION _segments_lock;
+ segment_t *_segments_head; // A list sorted by shmid.
+
+ int _shmid_cnt; // Number of shmid's allocated (for ipcs(8)).
+ int _shmid_max; // Highest shmid 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 shmid, 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, HANDLE);
+ void delete_segment (segment_t *);
+};
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::instance ()
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr &
+server_shmmgr::instance ()
{
- syscall_printf ("created");
+ static server_shmmgr instance;
+
+ return instance;
}
-/* FIXME: evaluate getuid() and getgid() against the requested mode. Then
- * choose PAGE_READWRITE | PAGE_READONLY and FILE_MAP_WRITE | FILE_MAP_READ
- * appropriately
- */
-
-/* Test result from openbsd: shm ids are persistent cross process if a handle is left
- * open. This could lead to resource starvation: we're not copying that behaviour
- * unless we have to. (It will involve acygwin1.dll gloal shared list :[ ).
- */
-/* FIXME: shmid should be a verifyable object
- */
-
-/* FIXME: on NT we should check everything against the SD. On 95 we just emulate.
- */
-
-extern GENERIC_MAPPING
- access_mapping;
-
-extern int
-check_and_dup_handle (HANDLE from_process, HANDLE to_process,
- HANDLE from_process_token,
- DWORD access,
- HANDLE from_handle,
- HANDLE * to_handle_ptr, BOOL bInheritHandle);
-
-//FIXME: where should this live
-static shmnode *
- shm_head =
- NULL;
-//FIXME: ditto.
-static shmnode *
- deleted_head = NULL;
-/* must be long for InterlockedIncrement */
-static long
- new_id =
- 0;
-static long
- new_private_key =
- 0;
-
-static void
-delete_shmnode (shmnode **nodeptr)
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::shmat ()
+ *---------------------------------------------------------------------------*/
+
+int
+server_shmmgr::shmat (const int shmid, const int shmflg,
+ const pid_t pid, HANDLE & hFileMap,
+ process_cache *const cache, const DWORD winpid)
{
- shmnode *node = *nodeptr;
+ process *const client = cache->process (winpid);
+
+ if (!client)
+ {
+ return -EAGAIN;
+ }
+
+ int result;
+ EnterCriticalSection (&_segments_lock);
- // remove from the list
- if (node == shm_head)
- shm_head = shm_head->next;
+ segment_t *const segptr = find (shmid);
+
+ 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 = %lld, shmid = %d, handle = %p]:"
+ "%s"),
+ segptr->key, segptr->shmid,
+ segptr->hFileMap, msg));
+
+ result = -EACCES; // FIXME
+ }
else
{
- shmnode *tempnode = shm_head;
- while (tempnode && tempnode->next != node)
- tempnode = tempnode->next;
- if (tempnode)
- tempnode->next = node->next;
- // else log the unexpected !
+ segptr->ds.shm_lpid = pid;
+ segptr->ds.shm_nattch += 1;
+ segptr->ds.shm_atime = time (NULL); // FIXME: sub-second times.
+
+ result = 0;
}
- // release the shared data view
- UnmapViewOfFile (node->shmds->mapptr);
- delete node->shmds;
- CloseHandle (node->filemap);
- CloseHandle (node->attachmap);
+ LeaveCriticalSection (&_segments_lock);
- // free the memory
- delete node;
- nodeptr = NULL;
+ client->release ();
+ return result;
}
-void
-client_request_shm::serve (transport_layer_base * const conn,
- process_cache * const cache)
-{
- assert (conn);
- assert (cache);
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::shmctl ()
+ *---------------------------------------------------------------------------*/
- assert (!error_code ());
+int
+server_shmmgr::shmctl (const int shmid, const int cmd, struct shmid_ds & ds,
+ const pid_t pid)
+{
+ int result;
+ EnterCriticalSection (&_segments_lock);
- // The minimum possible request length. SHM_CREATE requests should
- // be longer than this.
- const size_t min_req_msglen =
- (sizeof (parameters.in) - sizeof (parameters.in.sd_buf));
+ segment_t *const segptr = find (shmid);
- if (msglen () < min_req_msglen)
+ if (!segptr)
+ result = -EINVAL;
+ else
{
- syscall_printf (("bad request body length: "
- "expecting at least %lu bytes, got %lu"),
- min_req_msglen, msglen ());
- error_code (EINVAL);
- msglen (0);
- return;
+ 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
+ {
+ segptr->flg |= segment_t::REMOVED;
+ if (!segptr->ds.shm_nattch)
+ delete_segment (segptr);
+ result = 0;
+ }
+ break;
+
+ case IPC_INFO:
+ result = -EINVAL;
+ break;
+
+ case SHM_STAT:
+ result = -EINVAL;
+ break;
+
+ default:
+ result = -EINVAL;
+ break;
+ }
}
- // FIXME: check length of sd_buf contents for SHM_CREATE?
+ LeaveCriticalSection (&_segments_lock);
+ return result;
+}
- msglen (sizeof (parameters.out));
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::shmdt ()
+ *---------------------------------------------------------------------------*/
- HANDLE from_process_handle = NULL;
- HANDLE token_handle = NULL;
- DWORD rc;
+int
+server_shmmgr::shmdt (const int shmid, const pid_t pid)
+{
+ int result;
+ EnterCriticalSection (&_segments_lock);
- class process *const process = cache->process (parameters.in.winpid);
- assert (process);
- from_process_handle = process->handle ();
- process->release ();
+ segment_t *const segptr = find (shmid);
- /* possible TODO: reduce the access on the handle before we use it */
- /* Note that unless we do this, we don't need to call CloseHandle - it's kept open
- * by the process cache until the process terminates.
- * We may need a refcount on the cache however...
- */
- if (!from_process_handle)
+ if (!segptr)
+ result = -EINVAL;
+ else
{
- system_printf ("error opening process (%lu)", GetLastError ());
- error_code (EACCES);
- return;
+ assert (segptr->ds.shm_nattch > 0);
+
+ segptr->ds.shm_lpid = pid;
+ 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;
}
- if (wincap.has_security ())
- {
- conn->impersonate_client ();
+ LeaveCriticalSection (&_segments_lock);
+ return result;
+}
- rc = OpenThreadToken (GetCurrentThread (),
- TOKEN_QUERY, TRUE, &token_handle);
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::shmget ()
+ *---------------------------------------------------------------------------*/
- conn->revert_to_self ();
+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)
+{
+ int result;
+ EnterCriticalSection (&_segments_lock);
- if (!rc)
- {
- system_printf ("error opening thread token (%lu)", GetLastError ());
- error_code (EACCES);
- CloseHandle (from_process_handle);
- return;
- }
+ /* Does a segment already exist with that key? */
+ if (key == IPC_PRIVATE)
+ result = new_segment (key, size, shmflg, pid, 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);
+ else
+ result = -ENOENT;
+ else if (segptr->flg & segment_t::REMOVED)
+ result = -EIDRM;
+ else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
+ result = -EEXIST;
+ else if (size && segptr->ds.shm_segsz < size)
+ result = -EINVAL;
+ else
+ result = segptr->shmid;
}
- char *shmname = NULL, *shmaname = NULL;
- char stringbuf[29], stringbuf1[29];
+ LeaveCriticalSection (&_segments_lock);
+ return result;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::server_shmmgr ()
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr::server_shmmgr ()
+ : _segments_head (NULL)
+{
+ InitializeCriticalSection (&_segments_lock);
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::~server_shmmgr ()
+ *---------------------------------------------------------------------------*/
- /* TODO: make this code block a function! */
- if (parameters.in.type == SHM_REATTACH)
+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->key == key)
+ return segptr;
+
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::find ()
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr::segment_t *
+server_shmmgr::find (const int shmid, segment_t **previous)
+{
+ if (previous)
+ *previous = NULL;
+
+ for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
+ if (segptr->shmid == shmid)
+ return segptr;
+ else if (segptr->shmid > shmid) // The list is sorted by shmid.
+ 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 pid,
+ const uid_t uid,
+ const gid_t gid)
+{
+ const HANDLE hFileMap = CreateFileMapping (INVALID_HANDLE_VALUE,
+ NULL, PAGE_READWRITE,
+ 0, size,
+ NULL);
+
+ if (!hFileMap)
{
- /* just find and fill out the existing shm_id */
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- if (tempnode->shm_id == parameters.in.shm_id)
- {
- parameters.out.shm_id = tempnode->shm_id;
- parameters.out.key = tempnode->key;
- if (check_and_dup_handle
- (GetCurrentProcess (), from_process_handle, token_handle,
- DUPLICATE_SAME_ACCESS, tempnode->filemap,
- &parameters.out.filemap, TRUE) != 0)
- {
- system_printf ("error duplicating filemap handle (%lu)",
- GetLastError ());
- error_code (EACCES);
- }
- if (check_and_dup_handle
- (GetCurrentProcess (), from_process_handle, token_handle,
- DUPLICATE_SAME_ACCESS, tempnode->attachmap,
- &parameters.out.attachmap, TRUE) != 0)
- {
- system_printf ("error duplicating attachmap handle (%lu)",
- GetLastError ());
- error_code (EACCES);
- }
- CloseHandle (token_handle);
- return;
- }
- tempnode = tempnode->next;
- }
- error_code (EINVAL);
- CloseHandle (token_handle);
- return;
+ with_strerr (msg,
+ syscall_printf (("failed to create file mapping "
+ "[size = %lu]: %s"),
+ size, msg));
+
+ return -EINVAL; // FIXME
}
- /* someone attached */
- /* someone can send shm_id's they don't have and currently we will increment those
- * attach counts. If someone wants to fix that, please go ahead.
- * The problem is that shm_get has nothing to do with the ability to attach. Attach
- * requires a permission check, which we get the OS to do in MapViewOfFile.
- */
- if (parameters.in.type == SHM_ATTACH)
+ segment_t *const segptr = new_segment (key, hFileMap);
+
+ 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_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 shmid 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.
+ 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))
{
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- if (tempnode->shm_id == parameters.in.shm_id)
- {
- InterlockedIncrement (&tempnode->shmds->ds.shm_nattch);
- CloseHandle (token_handle);
- return;
- }
- tempnode = tempnode->next;
- }
- error_code (EINVAL);
- CloseHandle (token_handle);
- return;
+ previous = segptr;
}
- /* Someone detached */
- if (parameters.in.type == SHM_DETACH)
+ segment_t *const segptr = new segment_t (key, shmid, hFileMap);
+
+ assert (segptr);
+
+ if (previous)
{
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- if (tempnode->shm_id == parameters.in.shm_id)
- {
- InterlockedDecrement (&tempnode->shmds->ds.shm_nattch);
- CloseHandle (token_handle);
- return;
- }
- tempnode = tempnode->next;
- }
- error_code (EINVAL);
- CloseHandle (token_handle);
- return;
+ segptr->next = previous->next;
+ previous->next = segptr;
}
-
- /* Someone wants the ID removed. */
- if (parameters.in.type == SHM_DEL)
+ else
{
- shmnode **tempnode = &shm_head;
- while (*tempnode)
- {
- if ((*tempnode)->shm_id == parameters.in.shm_id)
- {
- // unlink from the accessible node list
- shmnode *temp2 = *tempnode;
- *tempnode = temp2->next;
- // link into the deleted list
- temp2->next = deleted_head;
- deleted_head = temp2;
-
- // FIXME: when/where do we delete the handles?
- if (temp2->shmds->ds.shm_nattch)
- {
- // FIXME: add to a pending queue?
- }
- else
- {
- delete_shmnode (&temp2);
- }
-
- CloseHandle (token_handle);
- return;
- }
- tempnode = &(*tempnode)->next;
- }
- error_code (EINVAL);
- CloseHandle (token_handle);
- return;
+ segptr->next = _segments_head;
+ _segments_head = segptr;
}
+ _shmid_cnt += 1;
+ if (shmid > _shmid_max)
+ _shmid_max = shmid;
- if (parameters.in.type == SHM_CREATE)
- {
- /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide
- * to prevent races on shmget.
- */
+ return segptr;
+}
- if (parameters.in.key == IPC_PRIVATE)
- {
- /* create the mapping name (CYGWINSHMKPRIVATE_0x01234567 */
- /* The K refers to Key, the actual mapped area has D */
- long private_key = (int) InterlockedIncrement (&new_private_key);
- snprintf (stringbuf, 29, "CYGWINSHMKPRIVATE_0x%0x", private_key);
- shmname = stringbuf;
- snprintf (stringbuf1, 29, "CYGWINSHMDPRIVATE_0x%0x", private_key);
- shmaname = stringbuf1;
- }
- else
- {
- /* create the mapping name (CYGWINSHMK0x0123456789abcdef */
- /* The K refers to Key, the actual mapped area has D */
-
- snprintf (stringbuf, 29, "CYGWINSHMK0x%0qx", parameters.in.key);
- shmname = stringbuf;
- snprintf (stringbuf1, 29, "CYGWINSHMD0x%0qx", parameters.in.key);
- shmaname = stringbuf1;
- debug_printf ("system id strings: key = %s", shmname);
- debug_printf ("system id strings: data = %s", shmaname);
- debug_printf ("key input value is 0x%0qx", parameters.in.key);
- }
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::delete_segment ()
+ *---------------------------------------------------------------------------*/
- /* attempt to open the key */
+void
+server_shmmgr::delete_segment (segment_t *const segptr)
+{
+ assert (segptr);
+ assert (!segptr->ds.shm_nattch);
+ assert (segptr->flg & segment_t::REMOVED);
- /* get an existing key */
- /* On unix the same shmid identifier is returned on multiple calls to shm_get
- * with the same key and size. Different modes is a ?.
- */
+ segment_t *previous = NULL;
- /* walk the list of known keys and return the id if found. remember, we are
- * authoritative...
- */
+ const segment_t *const tmp = find (segptr->shmid, &previous);
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- if (tempnode->key == parameters.in.key
- && parameters.in.key != IPC_PRIVATE)
- {
- // FIXME: free the mutex
- if (parameters.in.size
- && tempnode->shmds->ds.shm_segsz < parameters.in.size)
- {
- error_code (EINVAL);
- CloseHandle (token_handle);
- return;
- }
- /* FIXME: can the same process call this twice without error ? test
- * on unix
- */
- if ((parameters.in.shmflg & IPC_CREAT)
- && (parameters.in.shmflg & IPC_EXCL))
- {
- error_code (EEXIST);
- debug_printf
- ("attempt to exclusively create already created shm_area with key 0x%0qx",
- parameters.in.key);
- // FIXME: free the mutex
- CloseHandle (token_handle);
- return;
- }
- // FIXME: do we need to other tests of the requested mode with the
- // tempnode->shm_id mode ? testcase on unix needed.
- // FIXME how do we do the security test? or
- // do we wait for shmat to bother with that?
- /* One possibly solution: impersonate the client, and then test we can
- * reopen the area. In fact we'll probably have to do that to get
- * handles back to them, alternatively just tell them the id, and then
- * let them attempt the open.
- */
- parameters.out.shm_id = tempnode->shm_id;
- if (check_and_dup_handle
- (GetCurrentProcess (), from_process_handle, token_handle,
- DUPLICATE_SAME_ACCESS, tempnode->filemap,
- &parameters.out.filemap, TRUE) != 0)
- {
- system_printf ("error duplicating filemap handle (%lu)",
- GetLastError ());
- error_code (EACCES);
- /*mutex*/
- CloseHandle (token_handle);
- return;
- }
- if (check_and_dup_handle
- (GetCurrentProcess (), from_process_handle, token_handle,
- DUPLICATE_SAME_ACCESS, tempnode->attachmap,
- &parameters.out.attachmap, TRUE) != 0)
- {
- system_printf ("error duplicating attachmap handle (%lu)",
- GetLastError ());
- error_code (EACCES);
- /*mutex*/
- CloseHandle (token_handle);
- return;
- }
-
- CloseHandle (token_handle);
- return;
- }
- tempnode = tempnode->next;
- }
- /* couldn't find a currently open shm area. */
-
- /* create one */
-
- /* we trust the clients request - we will be doing it as them, and
- * the worst they can do is open their own permissions
- */
-
- SECURITY_ATTRIBUTES sa;
- sa.nLength = sizeof (sa);
- sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) parameters.in.sd_buf;
- sa.bInheritHandle = TRUE; /* the memory structures inherit ok */
-
- /* do this as the client */
- conn->impersonate_client ();
- /* This may need sh_none... it's only a control structure */
- HANDLE filemap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile.
- &sa,
- PAGE_READWRITE, // protection
- 0x00000000,
- getsystemallocgranularity (),
- shmname // object name
- );
- DWORD lasterr = GetLastError ();
- conn->revert_to_self ();
-
- if (filemap == NULL)
- {
- /* We failed to open the filemapping ? */
- system_printf ("failed to open file mapping: %lu",
- GetLastError ());
- // free the mutex
- // we can assume that it exists, and that it was an access problem.
- error_code (EACCES);
- CloseHandle (token_handle);
- return;
- }
+ assert (tmp == segptr);
+ assert (previous ? previous->next == segptr : _segments_head == segptr);
- /* successfully opened the control region mapping */
- /* did we create it ? */
- int oldmapping = lasterr == ERROR_ALREADY_EXISTS;
- if (oldmapping)
- {
- /* should never happen - we are the global daemon! */
-#if 0
- if ((parameters.in.shmflg & IPC_CREAT)
- && (parameters.in.shmflg & IPC_EXCL))
-#endif
- {
- /* FIXME free mutex */
- CloseHandle (filemap);
- error_code (EEXIST);
- CloseHandle (token_handle);
- return;
- }
- }
+ if (previous)
+ previous->next = segptr->next;
+ else
+ _segments_head = segptr->next;
- /* we created a new mapping */
- if (parameters.in.key != IPC_PRIVATE &&
- (parameters.in.shmflg & IPC_CREAT) == 0)
- {
- CloseHandle (filemap);
- /* FIXME free mutex */
- error_code (ENOENT);
- CloseHandle (token_handle);
- return;
- }
+ if (!CloseHandle (segptr->hFileMap))
+ with_strerr (msg,
+ syscall_printf (("failed to close file map "
+ "[handle = %p]: %s"),
+ segptr->hFileMap, msg));
- conn->impersonate_client ();
- void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0);
- conn->revert_to_self ();
+ assert (_shmid_cnt > 0);
+ _shmid_cnt -= 1;
- if (!mapptr)
- {
- CloseHandle (filemap);
- //FIXME: close filemap and free the mutex
- /* we couldn't access the mapped area with the requested permissions */
- error_code (EACCES);
- CloseHandle (token_handle);
- return;
- }
+ delete segptr;
+}
- conn->impersonate_client ();
- /* Now get the user data */
- HANDLE attachmap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile
- &sa,
- PAGE_READWRITE, // protection (FIXME)
- 0x00000000,
- parameters.in.size +
- parameters.in.size %
- getsystemallocgranularity (),
- shmaname // object name
- );
- conn->revert_to_self ();
-
- if (attachmap == NULL)
- {
- system_printf ("failed to get shm attachmap");
- error_code (ENOMEM);
- UnmapViewOfFile (mapptr);
- CloseHandle (filemap);
- /* FIXME exit the mutex */
- CloseHandle (token_handle);
- return;
- }
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
- int_shmid_ds *shmtemp = new int_shmid_ds;
- if (!shmtemp)
- {
- system_printf ("failed to malloc shm node");
- error_code (ENOMEM);
- UnmapViewOfFile (mapptr);
- CloseHandle (filemap);
- CloseHandle (attachmap);
- /* FIXME exit mutex */
- CloseHandle (token_handle);
- return;
- }
+client_request_shm::client_request_shm ()
+ : client_request (CYGSERVER_REQUEST_SHM,
+ &_parameters, sizeof (_parameters))
+{
+ syscall_printf ("created");
+}
- /* fill out the node data */
- shmtemp->ds.shm_perm.cuid = getuid ();
- shmtemp->ds.shm_perm.uid = shmtemp->ds.shm_perm.cuid;
- shmtemp->ds.shm_perm.cgid = getgid ();
- shmtemp->ds.shm_perm.gid = shmtemp->ds.shm_perm.cgid;
- shmtemp->ds.shm_perm.mode = parameters.in.shmflg & 0x01ff;
- shmtemp->ds.shm_lpid = 0;
- shmtemp->ds.shm_nattch = 0;
- shmtemp->ds.shm_atime = 0;
- shmtemp->ds.shm_dtime = 0;
- shmtemp->ds.shm_ctime = time (NULL);
- shmtemp->ds.shm_segsz = parameters.in.size;
- *(shmid_ds *) mapptr = shmtemp->ds;
- shmtemp->mapptr = mapptr;
-
- /* no need for InterlockedExchange here, we're serialised by the global mutex */
- tempnode = new shmnode;
- tempnode->shmds = shmtemp;
- tempnode->shm_id = (int) InterlockedIncrement (&new_id);
- tempnode->key = parameters.in.key;
- tempnode->filemap = filemap;
- tempnode->attachmap = attachmap;
- tempnode->next = shm_head;
- shm_head = tempnode;
-
- /* we now have the area in the daemon list, opened.
-
- FIXME: leave the system wide shm mutex */
-
- parameters.out.shm_id = tempnode->shm_id;
- if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
- token_handle,
- DUPLICATE_SAME_ACCESS,
- tempnode->filemap, &parameters.out.filemap,
- TRUE) != 0)
- {
- system_printf ("error duplicating filemap handle (%lu)",
- GetLastError ());
- error_code (EACCES);
- CloseHandle (token_handle);
- /* mutex et al */
- return;
- }
- if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
- token_handle,
- DUPLICATE_SAME_ACCESS,
- tempnode->attachmap,
- &parameters.out.attachmap, TRUE) != 0)
- {
- system_printf ("error duplicating attachmap handle (%lu)",
- GetLastError ());
- error_code (EACCES);
- CloseHandle (from_process_handle);
- CloseHandle (token_handle);
- /* more cleanup... yay! */
- return;
- }
- CloseHandle (token_handle);
+/*---------------------------------------------------------------------------*
+ * 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))
+ {
+ syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
+ sizeof (_parameters), msglen ());
+ error_code (EINVAL);
+ msglen (0);
return;
}
- error_code (ENOSYS);
- CloseHandle (token_handle);
+ // FIXME: Get a return code out of this and don't continue on error.
+ conn->impersonate_client ();
+
+ int result = -EINVAL;
+
+ switch (_parameters.in.shmop)
+ {
+ case SHMOP_shmget:
+ result = shmmgr.shmget (_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,
+ cache, _parameters.in.winpid);
+ break;
+
+ case SHMOP_shmdt:
+ result = shmmgr.shmdt (_parameters.shmid, _parameters.in.cygpid);
+ break;
+
+ case SHMOP_shmctl:
+ result = shmmgr.shmctl (_parameters.shmid, _parameters.in.cmd,
+ _parameters.ds, _parameters.in.cygpid);
+ break;
+ }
+
+ conn->revert_to_self ();
- return;
+ if (result < 0)
+ {
+ error_code (-result);
+ msglen (0);
+ }
}
diff --git a/winsup/cygwin/cygserver_shm.h b/winsup/cygwin/cygserver_shm.h
index 27a49d7c1..df147f10a 100644
--- a/winsup/cygwin/cygserver_shm.h
+++ b/winsup/cygwin/cygserver_shm.h
@@ -1,7 +1,9 @@
-/* cygserver_shm.h
+/* cygserver_shm.h: Single unix specification IPC interface for Cygwin.
- Copyright 2001, 2002 Red Hat Inc.
- Written by Robert Collins <rbtcollins@hotmail.com>
+ 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.
@@ -9,77 +11,101 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#ifndef __CYGSERVER_SHM_H__
+#define __CYGSERVER_SHM_H__
+
#include <sys/types.h>
+#include <assert.h>
+
#include "cygwin_shm.h"
#include "cygwin/cygserver.h"
-/* Values for the client_request_shm::parameters.in.type field. */
-#define SHM_CREATE 0
-#define SHM_REATTACH 1
-#define SHM_ATTACH 2
-#define SHM_DETACH 3
-#define SHM_DEL 4
-
-struct _shmattach
-{
- void *data;
- int shmflg;
- struct _shmattach *next;
-};
-
-struct int_shmid_ds
-{
- struct shmid_ds ds;
- void *mapptr;
-};
+/*---------------------------------------------------------------------------*
+ * class client_request_shm
+ *---------------------------------------------------------------------------*/
-struct shmnode
-{
- struct int_shmid_ds *shmds;
- int shm_id;
- struct shmnode *next;
- key_t key;
- HANDLE filemap;
- HANDLE attachmap;
- struct _shmattach *attachhead;
-};
+#ifndef __INSIDE_CYGWIN__
+class transport_layer_base;
+class process_cache;
+#endif
class client_request_shm : public client_request
{
+ friend class client_request;
+
public:
+ enum shmop_t
+ {
+ SHMOP_shmat,
+ SHMOP_shmctl,
+ SHMOP_shmdt,
+ SHMOP_shmget
+ };
+
#ifdef __INSIDE_CYGWIN__
- client_request_shm (key_t ntype, size_t nsize, int shmflg);
- client_request_shm (int ntype, int nshmid);
-#else
- client_request_shm ();
+ 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); // shmdt
+ client_request_shm (key_t, size_t, int shmflg); // shmget
#endif
- union
+ // Accessors for out parameters.
+
+ int shmid () const
{
- struct
- {
- int type;
- pid_t cygpid;
- DWORD winpid;
- int shm_id;
- key_t key;
- size_t size;
- int shmflg;
- char sd_buf[4096]; // Must be the last item (variable length).
- } in;
- struct
- {
- int shm_id;
- HANDLE filemap;
- HANDLE attachmap;
- key_t key;
- } out;
- } parameters;
+ assert (!error_code ());
+ return _parameters.shmid;
+ }
+
+ const struct shmid_ds & ds () const
+ {
+ assert (!error_code ());
+ return _parameters.ds;
+ }
+
+ HANDLE hFileMap () const
+ {
+ assert (!error_code ());
+ return _parameters.out.hFileMap;
+ }
private:
+ struct
+ {
+ int shmid;
+ struct shmid_ds ds;
+
+ union
+ {
+ struct
+ {
+ 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;
+ };
+ } _parameters;
+
+#ifndef __INSIDE_CYGWIN__
+ client_request_shm ();
+#endif
+
#ifndef __INSIDE_CYGWIN__
virtual void serve (transport_layer_base *, process_cache *);
#endif
};
+
+#endif /* __CYGSERVER_SHM_H__ */
diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc
index 80a47318b..75fd04aa9 100644
--- a/winsup/cygwin/shm.cc
+++ b/winsup/cygwin/shm.cc
@@ -1,8 +1,9 @@
-/* shm.cc: Single unix specification IPC interface for Cygwin
+/* shm.cc: Single unix specification IPC interface for Cygwin.
- Copyright 2001, 2002 Red Hat, Inc.
+ Copyright 2002 Red Hat, Inc.
- Originally written by Robert Collins <robert.collins@hotmail.com>
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
+ Based on code by Robert Collins <robert.collins@hotmail.com>.
This file is part of Cygwin.
@@ -11,545 +12,559 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <sys/stat.h>
-#include <assert.h>
+
+#include <sys/types.h>
+
#include <errno.h>
-#include "cygerrno.h"
-#include <limits.h>
+#include <stdio.h>
#include <unistd.h>
-#include "security.h"
-#include "fhandler.h"
-#include "path.h"
-#include "dtable.h"
-#include "cygheap.h"
-#include "thread.h"
-#include "cygwin_shm.h"
-#include "cygserver_shm.h"
-/*
- * FIXME: These must be defined somewhere? i.e. get the high and low
- * double words of a quad word? They are required here to allow keys
- * to be printed out via XXX_printf (i.e. small_printf()). Note that
- * even if the key is only 32 bits (the old default), these routine
- * should still give sensible results, i.e. hi_ulong() => 0.
- */
+#include "cygerrno.h"
-inline long int hi_ulong (const key_t key)
-{
- return (unsigned long)
- (((unsigned long long) key >> 32) & ULONG_MAX);
-}
+#include "cygserver_ipc.h"
+#include "cygserver_shm.h"
-inline long int lo_ulong (const key_t key)
+/*---------------------------------------------------------------------------*
+ * with_strerr ()
+ *---------------------------------------------------------------------------*/
+
+#define with_strerr(MSG, ACTION) \
+ do \
+ { \
+ const DWORD lasterr = GetLastError (); \
+ char *MSG = NULL; \
+ if (!FormatMessage ((FORMAT_MESSAGE_ALLOCATE_BUFFER \
+ | FORMAT_MESSAGE_FROM_SYSTEM \
+ | FORMAT_MESSAGE_IGNORE_INSERTS), \
+ NULL, \
+ lasterr, \
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), \
+ reinterpret_cast<char *>(&MSG), \
+ 0, \
+ NULL)) \
+ { \
+ MSG = static_cast<char *> \
+ (LocalAlloc (LMEM_FIXED, 24)); /* Big enough. */ \
+ if (!MSG) \
+ { \
+ system_printf (("failure in LocalAlloc(LMEM_FIXED, 16): " \
+ "error = %lu"), \
+ GetLastError ()); \
+ } \
+ else \
+ { \
+ snprintf (MSG, 24, "error = %lu", lasterr); \
+ } \
+ } \
+ SetLastError (lasterr); \
+ { ACTION; } \
+ if (MSG && !LocalFree (MSG)) \
+ { \
+ system_printf ("failed to free memory at %p, error = %lu", \
+ MSG, GetLastError ()); \
+ } \
+ SetLastError (lasterr); \
+ } while (false)
+
+/*---------------------------------------------------------------------------*
+ * class client_shmmgr
+ *
+ * A singleton class.
+ *---------------------------------------------------------------------------*/
+
+#define shmmgr (client_shmmgr::instance ())
+
+class client_shmmgr
{
- return (unsigned long)
- ((unsigned long long) key & ULONG_MAX);
-}
+private:
+ class segment_t
+ {
+ public:
+ const int shmid;
+ const void *const shmaddr;
+ const int shmflg;
+ HANDLE hFileMap; // Updated by fixup_shms_after_fork ().
-// FIXME IS THIS CORRECT
-/* Implementation notes: We use two shared memory regions per key:
- * One for the control structure, and one for the shared memory.
- * While this has a higher overhead tham a single shared area,
- * It allows more flexability. As the entire code is transparent to the user
- * We can merge these in the future should it be needed.
- */
-extern "C" size_t
-getsystemallocgranularity ()
-{
- SYSTEM_INFO sysinfo;
- static size_t buffer_offset = 0;
- if (buffer_offset)
- return buffer_offset;
- GetSystemInfo (&sysinfo);
- buffer_offset = sysinfo.dwAllocationGranularity;
- return buffer_offset;
-}
+ segment_t *next;
-/*
- * Used for: SHM_ATTACH, SHM_DETACH, SHM_REATTACH, and SHM_DEL.
- */
-client_request_shm::client_request_shm (int ntype, int nshmid)
- : client_request (CYGSERVER_REQUEST_SHM, &parameters, sizeof (parameters))
-{
- assert (ntype == SHM_REATTACH \
- || ntype == SHM_ATTACH \
- || ntype == SHM_DETACH \
- || ntype == SHM_DEL);
+ segment_t (const int shmid, const void *const shmaddr, const int shmflg,
+ const HANDLE hFileMap)
+ : shmid (shmid), shmaddr (shmaddr), shmflg (shmflg), hFileMap (hFileMap),
+ next (NULL)
+ {}
+ };
- parameters.in.type = ntype;
- parameters.in.cygpid = getpid ();
- parameters.in.winpid = GetCurrentProcessId ();
- parameters.in.shm_id = nshmid;
+public:
+ static client_shmmgr & instance ();
- assert (parameters.in.cygpid > 0);
- assert (parameters.in.winpid != 0);
+ void *shmat (int shmid, const void *, int shmflg);
+ int shmctl (int shmid, int cmd, struct shmid_ds *);
+ int shmdt (const void *);
+ int shmget (key_t, size_t, int shmflg);
- msglen (sizeof (parameters.in) - sizeof (parameters.in.sd_buf));
+ int fixup_shms_after_fork ();
- syscall_printf ("created: type = %d, shmid = %d",
- parameters.in.type, parameters.in.shm_id);
-}
+private:
+ CRITICAL_SECTION _segments_lock;
+ static segment_t *_segments_head; // A list sorted by shmaddr.
-/*
- * Used for: SHM_CREATE.
- */
-client_request_shm::client_request_shm (key_t nkey, size_t nsize, int nshmflg)
- : client_request (CYGSERVER_REQUEST_SHM, &parameters, sizeof (parameters))
-{
- assert (nkey != (key_t) -1);
- assert (nsize >= 0);
+ client_shmmgr ();
+ ~client_shmmgr ();
- parameters.in.type = SHM_CREATE;
- parameters.in.cygpid = getpid ();
- parameters.in.winpid = GetCurrentProcessId ();
- parameters.in.key = nkey;
- parameters.in.size = nsize;
- parameters.in.shmflg = nshmflg;
+ // Undefined (as this class is a singleton):
+ client_shmmgr (const client_shmmgr &);
+ client_shmmgr & operator= (const client_shmmgr &);
- assert (parameters.in.cygpid > 0);
- assert (parameters.in.winpid != 0);
+ segment_t *find (const void *, segment_t **previous = NULL);
- DWORD sd_buf_size = 0;
+ void *attach (int shmid, const void *, int shmflg, HANDLE & hFileMap);
- if (wincap.has_security ())
- {
- SECURITY_ATTRIBUTES sa = sec_none;
- sd_buf_size = sizeof (parameters.in.sd_buf);
+ segment_t *new_segment (int shmid, const void *, int shmflg, HANDLE);
+};
- PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) parameters.in.sd_buf;
+client_shmmgr::segment_t *client_shmmgr::_segments_head;
- InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION);
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::instance ()
+ *---------------------------------------------------------------------------*/
- alloc_sd (geteuid32 (), getegid32 (), parameters.in.shmflg & 0777,
- psd, &sd_buf_size);
- }
+client_shmmgr &
+client_shmmgr::instance ()
+{
+ static NO_COPY client_shmmgr instance;
+
+ return instance;
+}
- msglen (sizeof (parameters.in) - sizeof (parameters.in.sd_buf)
- + sd_buf_size);
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::shmat ()
+ *---------------------------------------------------------------------------*/
- syscall_printf (("created: type = %d, "
- "key = 0x%x%08x, size = %ld, shmflg = %o"),
- parameters.in.type,
- hi_ulong(parameters.in.key), lo_ulong(parameters.in.key),
- parameters.in.size, parameters.in.shmflg);
+void *
+client_shmmgr::shmat (const int shmid,
+ const void *const shmaddr,
+ const int shmflg)
+{
+ HANDLE hFileMap = NULL;
+
+ void *const ptr = attach (shmid, shmaddr, shmflg, hFileMap);
+
+ if (ptr)
+ new_segment (shmid, ptr, shmflg, hFileMap);
+
+ return (ptr ? ptr : (void *) -1);
}
-static shmnode *shm_head = NULL;
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::shmctl ()
+ *---------------------------------------------------------------------------*/
-static shmnode *
-build_inprocess_shmds (HANDLE hfilemap, HANDLE hattachmap, key_t key,
- int shm_id)
+int
+client_shmmgr::shmctl (const int shmid,
+ const int cmd,
+ struct shmid_ds *const buf)
{
- HANDLE filemap = hfilemap;
- void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0);
+ client_request_shm request (shmid, cmd, buf);
- if (!mapptr)
+ if (request.make_request () == -1 || request.error_code ())
{
- CloseHandle (hfilemap);
- CloseHandle (hattachmap);
- //FIXME: close filemap and free the mutex
- /* we couldn't access the mapped area with the requested permissions */
- set_errno (EACCES);
- return NULL;
+ set_errno (request.error_code ());
+ return -1;
}
- /* Now get the user data */
- HANDLE attachmap = hattachmap;
- int_shmid_ds *shmtemp = new int_shmid_ds;
- if (!shmtemp)
+ // Some commands require special processing, e.g. for out parameters.
+
+ switch (cmd)
{
- system_printf ("failed to malloc shm node");
- set_errno (ENOMEM);
- UnmapViewOfFile (mapptr);
- CloseHandle (filemap);
- CloseHandle (attachmap);
- /* exit mutex */
- return NULL;
+ case IPC_STAT:
+ *buf = request.ds ();
+ break;
+ }
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::shmdt ()
+ *
+ * According to Posix, the only error condition for this system call
+ * is EINVAL if shmaddr is not the address of the start of an attached
+ * shared memory segment. Given that, all other errors just generate
+ * tracing noise.
+ *---------------------------------------------------------------------------*/
+
+int
+client_shmmgr::shmdt (const void *const shmaddr)
+{
+ segment_t *previous = NULL;
+
+ segment_t *const segptr = find (shmaddr, &previous);
+
+ if (!segptr)
+ {
+ set_errno (EINVAL);
+ return -1;
}
- /* get the system node data */
- shmtemp->ds = *(shmid_ds *) mapptr;
+ assert (previous ? previous->next == segptr : _segments_head == segptr);
+
+ if (previous)
+ previous->next = segptr->next;
+ else
+ _segments_head = segptr->next;
+
+ if (!UnmapViewOfFile ((void *) shmaddr))
+ with_strerr (msg,
+ syscall_printf (("failed to unmap view "
+ "[shmid = %d, handle = %p, shmaddr = %p]:"
+ "%s"),
+ segptr->shmid, segptr->hFileMap, shmaddr,
+ msg));
+
+ assert (segptr->hFileMap);
- /* process local data */
- shmnode *tempnode = new shmnode;
+ if (!CloseHandle (segptr->hFileMap))
+ with_strerr (msg,
+ syscall_printf (("failed to close file map handle "
+ "[shmid = %d, handle = %p]:"
+ "%s"),
+ segptr->shmid, segptr->hFileMap,
+ msg));
- tempnode->filemap = filemap;
- tempnode->attachmap = attachmap;
- shmtemp->mapptr = mapptr;
+ client_request_shm request (segptr->shmid);
- /* no need for InterlockedExchange here, we're serialised by the global mutex */
- tempnode->shmds = shmtemp;
- tempnode->shm_id = shm_id;
- tempnode->key = key;
- tempnode->next = shm_head;
- tempnode->attachhead = NULL;
- shm_head = tempnode;
+ if (request.make_request () == -1 || request.error_code ())
+ syscall_printf ("shmdt request failed [shmid = %d, handle = %p]: %s",
+ segptr->shmid, segptr->hFileMap,
+ strerror (request.error_code ()));
- /* FIXME: leave the system wide shm mutex */
+ delete segptr;
- return tempnode;
+ return 0;
}
-static void
-delete_inprocess_shmds (shmnode **nodeptr)
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::shmget ()
+ *---------------------------------------------------------------------------*/
+
+int
+client_shmmgr::shmget (const key_t key, const size_t size, const int shmflg)
{
- shmnode *node = *nodeptr;
+ client_request_shm request (key, size, shmflg);
- // remove from the list
- if (node == shm_head)
- shm_head = shm_head->next;
- else
+ if (request.make_request () == -1 || request.error_code ())
{
- shmnode *tempnode = shm_head;
- while (tempnode && tempnode->next != node)
- tempnode = tempnode->next;
- if (tempnode)
- tempnode->next = node->next;
- // else log the unexpected !
+ set_errno (request.error_code ());
+ return -1;
}
- // release the shared data view
- UnmapViewOfFile (node->shmds);
- CloseHandle (node->filemap);
- CloseHandle (node->attachmap);
-
- // free the memory
- delete node;
- nodeptr = NULL;
+ return request.shmid ();
}
-int __stdcall
-fixup_shms_after_fork ()
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::fixup_shms_after_fork ()
+ *
+ * The hFileMap handles are non-inheritable: so the
+ *---------------------------------------------------------------------------*/
+
+int
+client_shmmgr::fixup_shms_after_fork ()
{
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- void *newshmds =
- MapViewOfFile (tempnode->filemap, FILE_MAP_WRITE, 0, 0, 0);
- if (!newshmds)
- {
- /* don't worry about handle cleanup, we're dying! */
- system_printf ("failed to reattach to shm control file view %x",
- tempnode);
- return 1;
- }
- tempnode->shmds->ds = *(shmid_ds *) newshmds;
- tempnode->shmds->mapptr = newshmds;
- _shmattach *attachnode = tempnode->attachhead;
- while (attachnode)
- {
- void *newdata = MapViewOfFileEx (tempnode->attachmap,
- (attachnode->shmflg & SHM_RDONLY) ?
- FILE_MAP_READ : FILE_MAP_WRITE, 0,
- 0, 0, attachnode->data);
- if (newdata != attachnode->data)
- {
- /* don't worry about handle cleanup, we're dying! */
- system_printf ("failed to reattach to mapped file view %x",
- attachnode->data);
- return 1;
- }
- attachnode = attachnode->next;
- }
- tempnode = tempnode->next;
- }
+ for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
+ if (!attach (segptr->shmid,
+ segptr->shmaddr,
+ segptr->shmflg & ~SHM_RND,
+ segptr->hFileMap))
+ {
+ system_printf ("fatal error re-attaching to shared memory segments");
+ return 1;
+ }
+
return 0;
}
-/* this is ugly. Yes, I know that.
- * FIXME: abstract the lookup functionality,
- * So that it can be an array, list, whatever without us being worried
- */
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::client_shmmgr ()
+ *---------------------------------------------------------------------------*/
-/* FIXME: after fork, every memory area needs to have the attach count
- * incremented. This should be done in the server?
- */
+client_shmmgr::client_shmmgr ()
+{
+ InitializeCriticalSection (&_segments_lock);
+}
-/* FIXME: tell the daemon when we attach, so at process close it can clean up
- * the attach count
- */
-extern "C" void *
-shmat (int shmid, const void *shmaddr, int shmflg)
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::~client_shmmgr ()
+ *---------------------------------------------------------------------------*/
+
+client_shmmgr::~client_shmmgr ()
{
- shmnode *tempnode = shm_head;
- while (tempnode && tempnode->shm_id != shmid)
- tempnode = tempnode->next;
+ DeleteCriticalSection (&_segments_lock);
+}
- if (!tempnode)
- {
- /* couldn't find a currently open shm control area for the key - probably because
- * shmget hasn't been called.
- * Allocate a new control block - this has to be handled by the daemon */
- client_request_shm req (SHM_REATTACH, shmid);
-
- if (req.make_request () == -1)
- {
- set_errno (ENOSYS); /* daemon communication failed */
- return (void *) -1;
- }
-
- if (req.error_code ()) /* shm_get failed in the daemon */
- {
- set_errno (req.error_code ());
- return (void *) -1;
- }
-
- /* we've got the id, now we open the memory area ourselves.
- * This tests security automagically
- * FIXME: make this a method of shmnode ?
- */
- tempnode =
- build_inprocess_shmds (req.parameters.out.filemap,
- req.parameters.out.attachmap,
- req.parameters.out.key,
- req.parameters.out.shm_id);
- if (!tempnode)
- return (void *) -1;
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::find ()
+ *---------------------------------------------------------------------------*/
- }
+client_shmmgr::segment_t *
+client_shmmgr::find (const void *const shmaddr, segment_t **previous)
+{
+ if (previous)
+ *previous = NULL;
- // class shmid_ds *shm = tempnode->shmds;
+ for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
+ if (segptr->shmaddr == shmaddr)
+ return segptr;
+ else if (segptr->shmaddr > shmaddr) // The list is sorted by shmaddr.
+ return NULL;
+ else if (previous)
+ *previous = segptr;
- if (shmaddr)
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::attach ()
+ *
+ * The body of shmat (), also used by fixup_shms_after_fork ().
+ *---------------------------------------------------------------------------*/
+
+void *
+client_shmmgr::attach (const int shmid,
+ const void *shmaddr,
+ const int shmflg,
+ HANDLE & hFileMap)
+{
+ client_request_shm request (shmid, shmflg);
+
+ if (request.make_request () == -1 || request.error_code ())
{
- //FIXME: requested base address ?! (Don't forget to fix the fixup_after_fork too)
- set_errno (EINVAL);
- return (void *) -1;
+ set_errno (request.error_code ());
+ return NULL;
}
- void *rv = MapViewOfFile (tempnode->attachmap,
- (shmflg & SHM_RDONLY) ? FILE_MAP_READ :
- FILE_MAP_WRITE, 0, 0, 0);
+ int result = 0;
+
+ const DWORD access = (shmflg & SHM_RDONLY) ? FILE_MAP_READ : FILE_MAP_WRITE;
+
+ if (shmaddr && (shmflg & SHM_RND))
+ shmaddr = (char *) shmaddr - ((ssize_t) shmaddr % SHMLBA);
+
+ void *const ptr =
+ MapViewOfFileEx (request.hFileMap (), access, 0, 0, 0, (void *) shmaddr);
- if (!rv)
+ if (!ptr)
{
- //FIXME: translate GetLastError()
- set_errno (EACCES);
- return (void *) -1;
+ with_strerr (msg,
+ syscall_printf (("failed to map view "
+ "[shmid = %d, handle = %p, shmaddr = %p]:"
+ "%s"),
+ shmid, request.hFileMap (), shmaddr,
+ msg));
+ result = EINVAL; // FIXME
}
- /* tell the daemon we have attached */
- client_request_shm req (SHM_ATTACH, shmid);
-
- if (req.make_request () == -1)
+ else if (shmaddr && ptr != shmaddr)
{
- debug_printf ("failed to tell daemon that we have attached");
+ syscall_printf (("failed to map view at requested address "
+ "[shmid = %d, handle = %p]: "
+ "requested address = %p, mapped address = %p"),
+ shmid, request.hFileMap (),
+ shmaddr, ptr);
+ result = EINVAL; // FIXME
}
- _shmattach *attachnode = new _shmattach;
- attachnode->data = rv;
- attachnode->shmflg = shmflg;
- attachnode->next =
- (_shmattach *) InterlockedExchangePointer (&tempnode->attachhead,
- attachnode);
-
+ if (result != 0)
+ {
+ if (!CloseHandle (request.hFileMap ()))
+ with_strerr (msg,
+ syscall_printf (("failed to close file map handle "
+ "[shmid = %d, handle = %p]:"
+ "%s"),
+ shmid, request.hFileMap (),
+ msg));
+
+ client_request_shm dt_req (shmid);
+
+ if (dt_req.make_request () == -1 || dt_req.error_code ())
+ syscall_printf ("shmdt request failed [shmid = %d, handle = %p]: %s",
+ shmid, request.hFileMap (),
+ strerror (dt_req.error_code ()));
+
+ set_errno (result);
+ return NULL;
+ }
- return rv;
+ hFileMap = request.hFileMap ();
+ return ptr;
}
-/* FIXME: tell the daemon when we detach so it doesn't cleanup incorrectly.
- */
-extern "C" int
-shmdt (const void *shmaddr)
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::new_segment ()
+ *
+ * Allocate a new segment for the given shmid, file map and address
+ * and insert into the segment map.
+ *---------------------------------------------------------------------------*/
+
+client_shmmgr::segment_t *
+client_shmmgr::new_segment (const int shmid,
+ const void *const shmaddr,
+ const int shmflg,
+ const HANDLE hFileMap)
{
- /* this should be "rare" so a hefty search is ok. If this is common, then we
- * should alter the data structs to allow more optimisation
- */
- shmnode *tempnode = shm_head;
- _shmattach *attachnode;
- while (tempnode)
+ assert (ipc_ext2int_subsys (shmid) == IPC_SHMOP);
+ assert (hFileMap);
+ assert (shmaddr);
+
+ segment_t *previous = NULL; // Insert pointer.
+
+ const segment_t *const tmp = find (shmaddr, &previous);
+
+ assert (!tmp);
+ assert (previous \
+ ? (!previous->next || previous->next->shmaddr > shmaddr) \
+ : (!_segments_head || _segments_head->shmaddr > shmaddr));
+
+ segment_t *const segptr = new segment_t (shmid, shmaddr, shmflg, hFileMap);
+
+ assert (segptr);
+
+ if (previous)
{
- // FIXME: Race potential
- attachnode = tempnode->attachhead;
- while (attachnode && attachnode->data != shmaddr)
- attachnode = attachnode->next;
- if (attachnode)
- break;
- tempnode = tempnode->next;
+ segptr->next = previous->next;
+ previous->next = segptr;
}
- if (!tempnode)
+ else
{
- // dt cannot be called by an app that hasn't alreadu at'd
- set_errno (EINVAL);
- return -1;
+ segptr->next = _segments_head;
+ _segments_head = segptr;
}
- UnmapViewOfFile (attachnode->data);
- /* tell the daemon we have attached */
- client_request_shm req (SHM_DETACH, tempnode->shm_id);
+ return segptr;
+}
- if (req.make_request () == -1)
- {
- debug_printf ("failed to tell daemon that we have detached");
- }
+/*---------------------------------------------------------------------------*
+ * shmat ()
+ *---------------------------------------------------------------------------*/
- return 0;
+extern "C" void *
+shmat (const int shmid, const void *const shmaddr, const int shmflg)
+{
+ return shmmgr.shmat (shmid, shmaddr, shmflg);
}
-//FIXME: who is allowed to perform STAT?
+/*---------------------------------------------------------------------------*
+ * shmctl ()
+ *---------------------------------------------------------------------------*/
+
extern "C" int
-shmctl (int shmid, int cmd, struct shmid_ds *buf)
+shmctl (const int shmid, const int cmd, struct shmid_ds *const buf)
{
- shmnode *tempnode = shm_head;
- while (tempnode && tempnode->shm_id != shmid)
- tempnode = tempnode->next;
- if (!tempnode)
- {
- /* couldn't find a currently open shm control area for the key - probably because
- * shmget hasn't been called.
- * Allocate a new control block - this has to be handled by the daemon */
- client_request_shm req (SHM_REATTACH, shmid);
-
- if (req.make_request () == -1)
- {
- set_errno (ENOSYS); /* daemon communication failed */
- return -1;
- }
-
- if (req.error_code ()) /* shm_get failed in the daemon */
- {
- set_errno (req.error_code ());
- return -1;
- }
-
- /* we've got the id, now we open the memory area ourselves.
- * This tests security automagically
- * FIXME: make this a method of shmnode ?
- */
- tempnode =
- build_inprocess_shmds (req.parameters.out.filemap,
- req.parameters.out.attachmap,
- req.parameters.out.key,
- req.parameters.out.shm_id);
- if (!tempnode)
- return -1;
- }
+ return shmmgr.shmctl (shmid, cmd, buf);
+}
- switch (cmd)
- {
- case IPC_STAT:
- *buf = tempnode->shmds->ds;
- break;
- case IPC_RMID:
- {
- /* TODO: check permissions. Or possibly, the daemon gets to be the only
- * one with write access to the memory area?
- */
- if (tempnode->shmds->ds.shm_nattch)
- system_printf
- ("call to shmctl with cmd= IPC_RMID when memory area still has"
- " attachees");
- /* how does this work?
- * we mark the ds area as "deleted", and the at and get calls all fail from now on
- * on, when nattch becomes 0, the mapped data area is destroyed.
- * and each process, as they touch this area detaches. eventually only the
- * daemon has an attach. The daemon gets asked to detach immediately.
- */
- //waiting for the daemon to handle terminating process's
- client_request_shm req (SHM_DEL, shmid);
-
- if (req.make_request () == -1)
- {
- set_errno (ENOSYS); /* daemon communication failed */
- return -1;
- }
-
- if (req.error_code ()) /* shm_del failed in the daemon */
- {
- set_errno (req.error_code ());
- return -1;
- }
-
- /* the daemon has deleted it's references */
- /* now for us */
-
- // FIXME: create a destructor
- delete_inprocess_shmds (&tempnode);
+/*---------------------------------------------------------------------------*
+ * shmdt ()
+ *---------------------------------------------------------------------------*/
- }
- break;
- case IPC_SET:
- default:
- set_errno (EINVAL);
- return -1;
- }
- return 0;
+extern "C" int
+shmdt (const void *const shmaddr)
+{
+ return shmmgr.shmdt (shmaddr);
}
-/* FIXME: evaluate getuid32() and getgid32() against the requested mode. Then
- * choose PAGE_READWRITE | PAGE_READONLY and FILE_MAP_WRITE | FILE_MAP_READ
- * appropriately
- */
+/*---------------------------------------------------------------------------*
+ * shmget ()
+ *---------------------------------------------------------------------------*/
-/* FIXME: shmid should be a verifyable object
- */
-
-/* FIXME: on NT we should check everything against the SD. On 95 we just emulate.
- */
extern "C" int
-shmget (key_t key, size_t size, int shmflg)
+shmget (const key_t key, const size_t size, const int shmflg)
{
- if (key == (key_t) - 1)
- {
- set_errno (ENOENT);
- return -1;
- }
+ return shmmgr.shmget (key, size, shmflg);
+}
- /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide
- * to prevent races on shmget.
- */
+/*---------------------------------------------------------------------------*
+ * fixup_shms_after_fork ()
+ *---------------------------------------------------------------------------*/
- /* walk the list of currently open keys and return the id if found
- */
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- if (tempnode->key == key && key != IPC_PRIVATE)
- {
- // FIXME: free the mutex
- if (size && tempnode->shmds->ds.shm_segsz < size)
- {
- set_errno (EINVAL);
- return -1;
- }
- if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
- {
- set_errno (EEXIST);
- // FIXME: free the mutex
- return -1;
- }
- // FIXME: do we need to other tests of the requested mode with the
- // tempnode->shmid mode ? testcase on unix needed.
- // FIXME do we need a security test? We are only examining the keys we already have open.
- // FIXME: what are the sec implications for fork () if we don't check here?
- return tempnode->shm_id;
- }
- tempnode = tempnode->next;
- }
- /* couldn't find a currently open shm control area for the key.
- * Allocate a new control block - this has to be handled by the daemon */
- client_request_shm req (key, size, shmflg);
+int __stdcall
+fixup_shms_after_fork ()
+{
+ return shmmgr.fixup_shms_after_fork ();
+}
- if (req.make_request () == -1)
- {
- set_errno (ENOSYS); /* daemon communication failed */
- return -1;
- }
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
- if (req.error_code ()) /* shm_get failed in the daemon */
- {
- set_errno (req.error_code ());
- return -1;
- }
+client_request_shm::client_request_shm (const int shmid, const int shmflg)
+ : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
+{
+ _parameters.in.shmop = SHMOP_shmat;
+
+ _parameters.shmid = shmid;
+ _parameters.in.shmflg = shmflg;
+
+ _parameters.in.cygpid = getpid ();
+ _parameters.in.winpid = GetCurrentProcessId ();
+ _parameters.in.uid = geteuid ();
+ _parameters.in.gid = getegid ();
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
+
+client_request_shm::client_request_shm (const int shmid,
+ const int cmd,
+ const struct shmid_ds * const buf)
+ : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
+{
+ _parameters.in.shmop = SHMOP_shmctl;
+
+ _parameters.shmid = shmid;
+ if (cmd == IPC_SET)
+ _parameters.ds = *buf;
+ _parameters.in.cmd = cmd;
+
+ _parameters.in.cygpid = getpid ();
+ _parameters.in.winpid = GetCurrentProcessId ();
+ _parameters.in.uid = geteuid ();
+ _parameters.in.gid = getegid ();
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
+
+client_request_shm::client_request_shm (const int shmid)
+ : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
+{
+ _parameters.in.shmop = SHMOP_shmdt;
+
+ _parameters.shmid = shmid;
+
+ _parameters.in.cygpid = getpid ();
+ _parameters.in.winpid = GetCurrentProcessId ();
+ _parameters.in.uid = geteuid ();
+ _parameters.in.gid = getegid ();
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
+
+client_request_shm::client_request_shm (const key_t key,
+ const size_t size,
+ const int shmflg)
+ : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
+{
+ _parameters.in.shmop = SHMOP_shmget;
+
+ _parameters.in.key = key;
+ _parameters.in.size = size;
+ _parameters.in.shmflg = shmflg;
- /* we've got the id, now we open the memory area ourselves.
- * This tests security automagically
- * FIXME: make this a method of shmnode ?
- */
- shmnode *shmtemp = build_inprocess_shmds (req.parameters.out.filemap,
- req.parameters.out.attachmap,
- key,
- req.parameters.out.shm_id);
- if (shmtemp)
- return shmtemp->shm_id;
- return -1;
+ _parameters.in.cygpid = getpid ();
+ _parameters.in.winpid = GetCurrentProcessId ();
+ _parameters.in.uid = geteuid ();
+ _parameters.in.gid = getegid ();
}