newlib/winsup/cygwin/shm.cc
Corinna Vinschen b1aae492d0 Switch to 32/64 datatypes:
* Makefile.in (OBSOLETE_FUNCTIONS): Add open acl aclcheck aclfrommode
	aclfrompbits aclfromtext aclsort acltomode acltopbits acltotext chown
	facl fchown fgetpos fopen freopen fseeko fsetpos fstat ftello
	ftruncate getegid geteuid getgid getgrent getgrgid getgrnam getgroups
	getpwuid getpwuid_r getuid initgroups lchown lseek lstat mknod mmap
	seekdir setegid seteuid setgid setgroups setregid setreuid setuid stat
	telldir truncate.
	(NEW_FUNCTIONS): Add _open64 acl32 aclcheck32 aclfrommode32
	aclfrompbits32 aclfromtext32 aclsort32 acltomode32 acltopbits32
	acltotext32 chown32 facl32 fchown32 fgetpos64 fopen64 freopen64
	fseeko64 fsetpos64 fstat64 ftello64 ftruncate64 getegid32 geteuid32
	getgid32 getgrent32 getgrgid32 getgrnam32 getgroups32 getpwuid32
	getpwuid_r32 getuid32 initgroups32 lchown32 lseek64 lstat64 mknod32
	mmap64 seekdir64 setegid32 seteuid32 setgid32 setgroups32 setregid32
	setreuid32 setuid32 stat64 telldir64 truncate64 to substitute the
	above.
	* cygserver_shm.h (class client_request_shm): Change uid_t and gid_t
	members to __uid32_t and __gid32_t.
	* cygwin.din: Add symbols acl32 aclcheck32 aclfrommode32
	aclfrompbits32 aclfromtext32 aclsort32 acltomode32 acltopbits32
	acltotext32 facl32 fgetpos64 fopen64 freopen64 fseeko64 fsetpos64
	_fstat64 ftello64 _lseek64 mknod32 _open64.
	* glob.c: Include perprocess.h.
	(globtilde): Call getpwuid32 and getuid32 instead of getpwuid and
	getuid.
	(g_lstat): Check for applications API version to call the appropriate
	typed gl_lstat function.
	(g_stat): Ditto for gl_stat.
	* shm.cc (client_request_shm::client_request_shm): Call geteuid32
	and getegid32 instead of geteuid and getegid throughout.
	* syscalls.cc (_open64): New alias for open.
	(_lseek64): New alias for lseek64.
	(_fstat64): New alias for fseek64.
	(mknod32): New function.
	(mknod): Calls mknod32 now.
	* winsup.h: Make function declarations for getuid32, geteuid32,
	and getpwuid32 accessible for plain C sources.  Add declarations
	for getegid32 and getpwnam.
	* include/cygwin/version.h: Bum API minor number to 78.
	* include/sys/cygwin.h: Guard C++ specific members of struct
	per_process against inclusion in plain C sources.
	* include/sys/mman.h (mman): Add guard to avoid type clash when
	compiling Cygwin.
2003-03-09 21:51:00 +00:00

694 lines
19 KiB
C++

/* shm.cc: Single unix specification IPC interface for Cygwin.
Copyright 2002 Red Hat, Inc.
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
Based on code by Robert Collins <robert.collins@hotmail.com>.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include "cygerrno.h"
#include "safe_memory.h"
#include "sigproc.h"
#include "cygserver_ipc.h"
#include "cygserver_shm.h"
/*---------------------------------------------------------------------------*
* class client_shmmgr
*
* A singleton class.
*---------------------------------------------------------------------------*/
#define shmmgr (client_shmmgr::instance ())
class client_shmmgr
{
private:
class segment_t
{
public:
const int shmid;
const void *const shmaddr;
const int shmflg;
HANDLE hFileMap; // Updated by fixup_shms_after_fork ().
segment_t *next;
segment_t (const int shmid, const void *const shmaddr, const int shmflg,
const HANDLE hFileMap)
: shmid (shmid), shmaddr (shmaddr), shmflg (shmflg), hFileMap (hFileMap),
next (NULL)
{}
};
public:
static client_shmmgr & instance ();
void *shmat (int shmid, const void *, int shmflg);
int shmctl (int shmid, int cmd, struct shmid_ds *);
int shmdt (const void *);
int shmget (key_t, size_t, int shmflg);
int fixup_shms_after_fork ();
private:
static NO_COPY client_shmmgr *_instance;
CRITICAL_SECTION _segments_lock;
static segment_t *_segments_head; // List of attached segs by shmaddr.
static long _shmat_cnt; // No. of attached segs; for info. only.
client_shmmgr ();
~client_shmmgr ();
// Undefined (as this class is a singleton):
client_shmmgr (const client_shmmgr &);
client_shmmgr & operator= (const client_shmmgr &);
segment_t *find (const void *, segment_t **previous = NULL);
void *attach (int shmid, const void *, int shmflg, HANDLE & hFileMap);
segment_t *new_segment (int shmid, const void *, int shmflg, HANDLE);
};
/* static */ NO_COPY client_shmmgr *client_shmmgr::_instance;
/* The following two variables must be inherited by child processes
* since they are used by fixup_shms_after_fork () to re-attach to the
* parent's shm segments.
*/
/* static */ client_shmmgr::segment_t *client_shmmgr::_segments_head;
/* static */ long client_shmmgr::_shmat_cnt;
/*---------------------------------------------------------------------------*
* client_shmmgr::instance ()
*---------------------------------------------------------------------------*/
client_shmmgr &
client_shmmgr::instance ()
{
if (!_instance)
_instance = safe_new0 (client_shmmgr);
assert (_instance);
return *_instance;
}
/*---------------------------------------------------------------------------*
* client_shmmgr::shmat ()
*---------------------------------------------------------------------------*/
void *
client_shmmgr::shmat (const int shmid,
const void *const shmaddr,
const int shmflg)
{
syscall_printf ("shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)",
shmid, shmaddr, shmflg);
EnterCriticalSection (&_segments_lock);
HANDLE hFileMap = NULL;
void *const ptr = attach (shmid, shmaddr, shmflg, hFileMap);
if (ptr)
new_segment (shmid, ptr, shmflg, hFileMap);
LeaveCriticalSection (&_segments_lock);
if (ptr)
syscall_printf ("%p = shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)",
ptr, shmid, shmaddr, shmflg);
// else
// See the syscall_printf in client_shmmgr::attach ().
return (ptr ? ptr : (void *) -1);
}
/*---------------------------------------------------------------------------*
* client_shmmgr::shmctl ()
*---------------------------------------------------------------------------*/
int
client_shmmgr::shmctl (const int shmid,
const int cmd,
struct shmid_ds *const buf)
{
syscall_printf ("shmctl (shmid = %d, cmd = 0x%x, buf = %p)",
shmid, cmd, buf);
// Check parameters and set up in parameters as required.
const struct shmid_ds *in_buf = NULL;
switch (cmd)
{
case IPC_SET:
if (__check_invalid_read_ptr_errno (buf, sizeof (struct shmid_ds)))
{
syscall_printf (("-1 [EFAULT] = "
"shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
shmid, cmd, buf);
set_errno (EFAULT);
return -1;
}
in_buf = buf;
break;
case IPC_STAT:
case SHM_STAT:
if (__check_null_invalid_struct_errno (buf, sizeof (struct shmid_ds)))
{
syscall_printf (("-1 [EFAULT] = "
"shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
shmid, cmd, buf);
set_errno (EFAULT);
return -1;
}
break;
case IPC_INFO:
if (__check_null_invalid_struct_errno (buf, sizeof (struct shminfo)))
{
syscall_printf (("-1 [EFAULT] = "
"shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
shmid, cmd, buf);
set_errno (EFAULT);
return -1;
}
break;
case SHM_INFO:
if (__check_null_invalid_struct_errno (buf, sizeof (struct shm_info)))
{
syscall_printf (("-1 [EFAULT] = "
"shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
shmid, cmd, buf);
set_errno (EFAULT);
return -1;
}
break;
}
// Create and issue the command.
client_request_shm request (shmid, cmd, in_buf);
if (request.make_request () == -1 || request.error_code ())
{
syscall_printf (("-1 [%d] = "
"shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
request.error_code (), shmid, cmd, buf);
set_errno (request.error_code ());
return -1;
}
// Some commands require special processing for their out parameters.
int result = 0;
switch (cmd)
{
case IPC_STAT:
*buf = request.ds ();
break;
case IPC_INFO:
*(struct shminfo *) buf = request.shminfo ();
break;
case SHM_STAT: // ipcs(8) i'face.
result = request.shmid ();
*buf = request.ds ();
break;
case SHM_INFO: // ipcs(8) i'face.
result = request.shmid ();
*(struct shm_info *) buf = request.shm_info ();
break;
}
syscall_printf ("%d = shmctl (shmid = %d, cmd = 0x%x, buf = %p)",
result, shmid, cmd, buf);
return result;
}
/*---------------------------------------------------------------------------*
* 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)
{
syscall_printf ("shmdt (shmaddr = %p)", shmaddr);
EnterCriticalSection (&_segments_lock);
segment_t *previous = NULL;
segment_t *const segptr = find (shmaddr, &previous);
if (!segptr)
{
LeaveCriticalSection (&_segments_lock);
syscall_printf ("-1 [EINVAL] = shmdt (shmaddr = %p)", shmaddr);
set_errno (EINVAL);
return -1;
}
assert (previous ? previous->next == segptr : _segments_head == segptr);
if (previous)
previous->next = segptr->next;
else
_segments_head = segptr->next;
LeaveCriticalSection (&_segments_lock);
const long cnt = InterlockedDecrement (&_shmat_cnt);
assert (cnt >= 0);
if (!UnmapViewOfFile ((void *) shmaddr))
syscall_printf (("failed to unmap view "
"[shmid = %d, handle = %p, shmaddr = %p]:"
"%E"),
segptr->shmid, segptr->hFileMap, shmaddr);
assert (segptr->hFileMap);
if (!CloseHandle (segptr->hFileMap))
syscall_printf (("failed to close file map handle "
"[shmid = %d, handle = %p]: %E"),
segptr->shmid, segptr->hFileMap);
client_request_shm request (segptr->shmid);
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 ()));
safe_delete (segptr);
syscall_printf ("0 = shmdt (shmaddr = %p)", shmaddr);
return 0;
}
/*---------------------------------------------------------------------------*
* client_shmmgr::shmget ()
*---------------------------------------------------------------------------*/
int
client_shmmgr::shmget (const key_t key, const size_t size, const int shmflg)
{
syscall_printf ("shmget (key = 0x%016X, size = %u, shmflg = 0%o)",
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%016X, size = %u, shmflg = 0%o)"),
request.error_code (),
key, size, shmflg);
set_errno (request.error_code ());
return -1;
}
syscall_printf (("%d = shmget (key = 0x%016X, size = %u, shmflg = 0%o)"),
request.shmid (),
key, size, shmflg);
return request.shmid ();
}
/*---------------------------------------------------------------------------*
* client_shmmgr::fixup_shms_after_fork ()
*
* The hFileMap handles are non-inheritable: so they have to be
* re-acquired from cygserver.
*
* Nb. This routine need not be thread-safe as it is only called at startup.
*---------------------------------------------------------------------------*/
int
client_shmmgr::fixup_shms_after_fork ()
{
debug_printf ("re-attaching to shm segments: %d attached", _shmat_cnt);
{
int length = 0;
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
length += 1;
if (_shmat_cnt != length)
{
system_printf (("state inconsistent: "
"_shmat_cnt = %d, length of segments list = %d"),
_shmat_cnt, length);
return 1;
}
}
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
if (!attach (segptr->shmid,
segptr->shmaddr,
segptr->shmflg & ~SHM_RND,
segptr->hFileMap))
{
system_printf ("fatal error re-attaching to shm segment %d",
segptr->shmid);
return 1;
}
if (_shmat_cnt)
debug_printf ("re-attached all %d shm segments", _shmat_cnt);
return 0;
}
/*---------------------------------------------------------------------------*
* client_shmmgr::client_shmmgr ()
*---------------------------------------------------------------------------*/
client_shmmgr::client_shmmgr ()
{
InitializeCriticalSection (&_segments_lock);
}
/*---------------------------------------------------------------------------*
* client_shmmgr::~client_shmmgr ()
*---------------------------------------------------------------------------*/
client_shmmgr::~client_shmmgr ()
{
DeleteCriticalSection (&_segments_lock);
}
/*---------------------------------------------------------------------------*
* client_shmmgr::find ()
*---------------------------------------------------------------------------*/
client_shmmgr::segment_t *
client_shmmgr::find (const void *const shmaddr, segment_t **previous)
{
if (previous)
*previous = NULL;
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
if (segptr->shmaddr == shmaddr)
return segptr;
else if (segptr->shmaddr > shmaddr) // The list is sorted by shmaddr.
return NULL;
else if (previous)
*previous = segptr;
return NULL;
}
/*---------------------------------------------------------------------------*
* 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 ())
{
syscall_printf (("-1 [%d] = "
"shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)"),
request.error_code (), shmid, shmaddr, shmflg);
set_errno (request.error_code ());
return NULL;
}
int result = 0;
const DWORD access = (shmflg & SHM_RDONLY) ? FILE_MAP_READ : FILE_MAP_WRITE;
if (shmaddr && (shmflg & SHM_RND))
shmaddr = (char *) shmaddr - ((ssize_t) shmaddr % SHMLBA);
void *const ptr =
MapViewOfFileEx (request.hFileMap (), access, 0, 0, 0, (void *) shmaddr);
if (!ptr)
{
syscall_printf (("failed to map view "
"[shmid = %d, handle = %p, shmaddr = %p]: %E"),
shmid, request.hFileMap (), shmaddr);
result = EINVAL; // FIXME
}
else if (shmaddr && ptr != shmaddr)
{
syscall_printf (("failed to map view at requested address "
"[shmid = %d, handle = %p]: "
"requested address = %p, mapped address = %p"),
shmid, request.hFileMap (),
shmaddr, ptr);
result = EINVAL; // FIXME
}
if (result != 0)
{
if (!CloseHandle (request.hFileMap ()))
syscall_printf (("failed to close file map handle "
"[shmid = %d, handle = %p]: %E"),
shmid, request.hFileMap ());
client_request_shm dt_req (shmid);
if (dt_req.make_request () == -1 || dt_req.error_code ())
syscall_printf ("shmdt request failed [shmid = %d, handle = %p]: %s",
shmid, request.hFileMap (),
strerror (dt_req.error_code ()));
set_errno (result);
return NULL;
}
hFileMap = request.hFileMap ();
return ptr;
}
/*---------------------------------------------------------------------------*
* client_shmmgr::new_segment ()
*
* Allocate a new segment for the given shmid, file map and address
* and insert into the segment map.
*---------------------------------------------------------------------------*/
client_shmmgr::segment_t *
client_shmmgr::new_segment (const int shmid,
const void *const shmaddr,
const int shmflg,
const HANDLE hFileMap)
{
assert (ipc_ext2int_subsys (shmid) == IPC_SHMOP);
assert (hFileMap);
assert (shmaddr);
segment_t *previous = NULL; // Insert pointer.
const segment_t *const tmp = find (shmaddr, &previous);
assert (!tmp);
assert (previous \
? (!previous->next || previous->next->shmaddr > shmaddr) \
: (!_segments_head || _segments_head->shmaddr > shmaddr));
segment_t *const segptr =
safe_new (segment_t, shmid, shmaddr, shmflg, hFileMap);
assert (segptr);
if (previous)
{
segptr->next = previous->next;
previous->next = segptr;
}
else
{
segptr->next = _segments_head;
_segments_head = segptr;
}
const long cnt = InterlockedIncrement (&_shmat_cnt);
assert (cnt > 0);
return segptr;
}
/*---------------------------------------------------------------------------*
* shmat ()
*---------------------------------------------------------------------------*/
extern "C" void *
shmat (const int shmid, const void *const shmaddr, const int shmflg)
{
sigframe thisframe (mainthread);
return shmmgr.shmat (shmid, shmaddr, shmflg);
}
/*---------------------------------------------------------------------------*
* shmctl ()
*---------------------------------------------------------------------------*/
extern "C" int
shmctl (const int shmid, const int cmd, struct shmid_ds *const buf)
{
sigframe thisframe (mainthread);
return shmmgr.shmctl (shmid, cmd, buf);
}
/*---------------------------------------------------------------------------*
* shmdt ()
*---------------------------------------------------------------------------*/
extern "C" int
shmdt (const void *const shmaddr)
{
sigframe thisframe (mainthread);
return shmmgr.shmdt (shmaddr);
}
/*---------------------------------------------------------------------------*
* shmget ()
*---------------------------------------------------------------------------*/
extern "C" int
shmget (const key_t key, const size_t size, const int shmflg)
{
sigframe thisframe (mainthread);
return shmmgr.shmget (key, size, shmflg);
}
/*---------------------------------------------------------------------------*
* fixup_shms_after_fork ()
*---------------------------------------------------------------------------*/
int __stdcall
fixup_shms_after_fork ()
{
return shmmgr.fixup_shms_after_fork ();
}
/*---------------------------------------------------------------------------*
* client_request_shm::client_request_shm ()
*---------------------------------------------------------------------------*/
client_request_shm::client_request_shm (const int shmid, const int shmflg)
: client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
{
_parameters.in.shmop = SHMOP_shmat;
_parameters.in.shmid = shmid;
_parameters.in.shmflg = shmflg;
_parameters.in.cygpid = getpid ();
_parameters.in.winpid = GetCurrentProcessId ();
_parameters.in.uid = geteuid32 ();
_parameters.in.gid = getegid32 ();
msglen (sizeof (_parameters.in));
}
/*---------------------------------------------------------------------------*
* client_request_shm::client_request_shm ()
*---------------------------------------------------------------------------*/
client_request_shm::client_request_shm (const int shmid,
const int cmd,
const struct shmid_ds *const buf)
: client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
{
_parameters.in.shmop = SHMOP_shmctl;
_parameters.in.shmid = shmid;
_parameters.in.cmd = cmd;
if (buf)
_parameters.in.ds = *buf;
_parameters.in.cygpid = getpid ();
_parameters.in.winpid = GetCurrentProcessId ();
_parameters.in.uid = geteuid32 ();
_parameters.in.gid = getegid32 ();
msglen (sizeof (_parameters.in));
}
/*---------------------------------------------------------------------------*
* client_request_shm::client_request_shm ()
*---------------------------------------------------------------------------*/
client_request_shm::client_request_shm (const int shmid)
: client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
{
_parameters.in.shmop = SHMOP_shmdt;
_parameters.in.shmid = shmid;
_parameters.in.cygpid = getpid ();
_parameters.in.winpid = GetCurrentProcessId ();
_parameters.in.uid = geteuid32 ();
_parameters.in.gid = getegid32 ();
msglen (sizeof (_parameters.in));
}
/*---------------------------------------------------------------------------*
* client_request_shm::client_request_shm ()
*---------------------------------------------------------------------------*/
client_request_shm::client_request_shm (const key_t key,
const size_t size,
const int shmflg)
: client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
{
_parameters.in.shmop = SHMOP_shmget;
_parameters.in.key = key;
_parameters.in.size = size;
_parameters.in.shmflg = shmflg;
_parameters.in.cygpid = getpid ();
_parameters.in.winpid = GetCurrentProcessId ();
_parameters.in.uid = geteuid32 ();
_parameters.in.gid = getegid32 ();
msglen (sizeof (_parameters.in));
}