⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cygserver_shm.cc

📁 cygwin, 著名的在win32下模拟unix操作系统的东东
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin.   Copyright 2002 Red Hat, Inc.   Written by Conrad Scott <conrad.scott@dsl.pipex.com>.   Based on code by Robert Collins <robert.collins@hotmail.com>.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license.  Please consult the file "CYGWIN_LICENSE" fordetails. */#include "woutsup.h"#include <errno.h>#include <pthread.h>#include <stdio.h>#include <string.h>#include <time.h>#include "cygserver_ipc.h"#include "cygserver_shm.h"#include "security.h"#include "cygwin/cygserver.h"#include "cygwin/cygserver_process.h"#include "cygwin/cygserver_transport.h"/*---------------------------------------------------------------------------* * class server_shmmgr * * A singleton class. *---------------------------------------------------------------------------*/#define shmmgr (server_shmmgr::instance ())class server_shmmgr{private:  class attach_t  {  public:    class process *const _client;    unsigned int _refcnt;    attach_t *_next;    attach_t (class process *const client)      : _client (client),	_refcnt (0),	_next (NULL)    {}  };  class segment_t  {  private:    // Bits for the _flg field.    enum { IS_DELETED = 0x01 };  public:    const int _intid;    const int _shmid;    struct shmid_ds _ds;    segment_t *_next;    segment_t (const key_t key, const int intid, const HANDLE hFileMap);    ~segment_t ();    bool is_deleted () const    {      return _flg & IS_DELETED;    }    bool is_pending_delete () const    {      return !_ds.shm_nattch && is_deleted ();    }    void mark_deleted ()    {      assert (!is_deleted ());      _flg |= IS_DELETED;    }    int attach (class process *, HANDLE & hFileMap);    int detach (class process *);  private:    static long _sequence;    int _flg;    const HANDLE _hFileMap;    attach_t *_attach_head;	// A list sorted by winpid;    attach_t *find (const class process *, attach_t **previous = NULL);  };  class cleanup_t : public cleanup_routine  {  public:    cleanup_t (const segment_t *const segptr)      : cleanup_routine (reinterpret_cast<void *> (segptr->_shmid))    {      assert (key ());    }    int shmid () const { return reinterpret_cast<int> (key ()); }    virtual void cleanup (class process *const client)    {      const int res = shmmgr.shmdt (shmid (), client);      if (res != 0)	debug_printf ("process cleanup failed [shmid = %d]: %s",		      shmid (), strerror (-res));    }  };public:  static server_shmmgr & instance ();  int shmat (HANDLE & hFileMap,	     int shmid, int shmflg, class process *);  int shmctl (int & out_shmid, struct shmid_ds & out_ds,	      struct shminfo & out_shminfo, struct shm_info & out_shm_info,	      const int shmid, int cmd, const struct shmid_ds &,	      class process *);  int shmdt (int shmid, class process *);  int shmget (int & out_shmid, key_t, size_t, int shmflg, uid_t, gid_t,	      class process *);private:  static server_shmmgr *_instance;  static pthread_once_t _instance_once;  static void initialise_instance ();  CRITICAL_SECTION _segments_lock;  segment_t *_segments_head;	// A list sorted by int_id.  int _shm_ids;			// Number of shm segments (for ipcs(8)).  int _shm_tot;			// Total bytes of shm segments (for ipcs(8)).  int _shm_atts;		// Number of attached segments (for ipcs(8)).  int _intid_max;		// Highest intid yet allocated (for ipcs(8)).  server_shmmgr ();  ~server_shmmgr ();  // Undefined (as this class is a singleton):  server_shmmgr (const server_shmmgr &);  server_shmmgr & operator= (const server_shmmgr &);  segment_t *find_by_key (key_t);  segment_t *find (int intid, segment_t **previous = NULL);  int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t);  segment_t *new_segment (key_t, size_t, HANDLE);  void delete_segment (segment_t *);};/* static */ long server_shmmgr::segment_t::_sequence = 0;/* static */ server_shmmgr *server_shmmgr::_instance = NULL;/* static */ pthread_once_t server_shmmgr::_instance_once = PTHREAD_ONCE_INIT;/*---------------------------------------------------------------------------* * server_shmmgr::segment_t::segment_t () *---------------------------------------------------------------------------*/server_shmmgr::segment_t::segment_t (const key_t key,				     const int intid,				     const HANDLE hFileMap)  : _intid (intid),    _shmid (ipc_int2ext (intid, IPC_SHMOP, _sequence)),    _next (NULL),    _flg (0),    _hFileMap (hFileMap),    _attach_head (NULL){  assert (0 <= _intid && _intid < SHMMNI);  memset (&_ds, '\0', sizeof (_ds));  _ds.shm_perm.key = key;}/*---------------------------------------------------------------------------* * server_shmmgr::segment_t::~segment_t () *---------------------------------------------------------------------------*/server_shmmgr::segment_t::~segment_t (){  assert (!_attach_head);  if (!CloseHandle (_hFileMap))    syscall_printf ("failed to close file map [handle = 0x%x]: %E", _hFileMap);}/*---------------------------------------------------------------------------* * server_shmmgr::segment_t::attach () *---------------------------------------------------------------------------*/intserver_shmmgr::segment_t::attach (class process *const client,				  HANDLE & hFileMap){  assert (client);  if (!DuplicateHandle (GetCurrentProcess (),			_hFileMap,			client->handle (),			&hFileMap,			0,			FALSE, // bInheritHandle			DUPLICATE_SAME_ACCESS))    {      syscall_printf (("failed to duplicate handle for client "		       "[key = 0x%016llx, shmid = %d, handle = 0x%x]: %E"),		      _ds.shm_perm.key, _shmid, _hFileMap);      return -EACCES;	// FIXME: Case analysis?    }  _ds.shm_lpid  = client->cygpid ();  _ds.shm_nattch += 1;  _ds.shm_atime = time (NULL); // FIXME: sub-second times.  attach_t *previous = NULL;  attach_t *attptr = find (client, &previous);  if (!attptr)    {      attptr = safe_new (attach_t, client);      if (previous)	{	  attptr->_next = previous->_next;	  previous->_next = attptr;	}      else	{	  attptr->_next = _attach_head;	  _attach_head = attptr;	}    }  attptr->_refcnt += 1;  cleanup_t *const cleanup = safe_new (cleanup_t, this);  // FIXME: ::add should only fail if the process object is already  // cleaning up; but it can't be doing that since this thread has it  // locked.  const bool result = client->add (cleanup);  assert (result);  return 0;}/*---------------------------------------------------------------------------* * server_shmmgr::segment_t::detach () *---------------------------------------------------------------------------*/intserver_shmmgr::segment_t::detach (class process *const client){  attach_t *previous = NULL;  attach_t *const attptr = find (client, &previous);  if (!attptr)    return -EINVAL;  if (client->is_active ())    {      const cleanup_t key (this);      if (!client->remove (&key))	syscall_printf (("failed to remove cleanup routine for %d(%lu) "			 "[shmid = %d]"),			client->cygpid (), client->winpid (),			_shmid);    }  attptr->_refcnt -= 1;  if (!attptr->_refcnt)    {      assert (previous ? previous->_next == attptr : _attach_head == attptr);      if (previous)	previous->_next = attptr->_next;      else	_attach_head = attptr->_next;      safe_delete (attptr);    }  assert (_ds.shm_nattch > 0);  _ds.shm_lpid  = client->cygpid ();  _ds.shm_nattch -= 1;  _ds.shm_dtime = time (NULL); // FIXME: sub-second times.  return 0;}/*---------------------------------------------------------------------------* * server_shmmgr::segment_t::find () *---------------------------------------------------------------------------*/server_shmmgr::attach_t *server_shmmgr::segment_t::find (const class process *const client,				attach_t **previous){  if (previous)    *previous = NULL;  // Nb. The _attach_head list is sorted by winpid.  for (attach_t *attptr = _attach_head; attptr; attptr = attptr->_next)    if (attptr->_client == client)      return attptr;    else if (attptr->_client->winpid () > client->winpid ())      return NULL;    else if (previous)      *previous = attptr;  return NULL;}/*---------------------------------------------------------------------------* * server_shmmgr::instance () *---------------------------------------------------------------------------*//* static */ server_shmmgr &server_shmmgr::instance (){  pthread_once (&_instance_once, &initialise_instance);  assert (_instance);  return *_instance;}/*---------------------------------------------------------------------------* * server_shmmgr::shmat () *---------------------------------------------------------------------------*/intserver_shmmgr::shmat (HANDLE & hFileMap,		      const int shmid, const int shmflg,		      class process *const client){  syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d(%lu)",		  shmid, shmflg, client->cygpid (), client->winpid ());  int result = 0;  EnterCriticalSection (&_segments_lock);  segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));  if (!segptr)    result = -EINVAL;  else    result = segptr->attach (client, hFileMap);  if (!result)    _shm_atts += 1;  LeaveCriticalSection (&_segments_lock);  if (result < 0)    syscall_printf (("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) "		     "for %d(%lu)"),		    -result, shmid, shmflg,		    client->cygpid (), client->winpid ());  else    syscall_printf (("0x%x = shmat (shmid = %d, shmflg = 0%o) "		     "for %d(%lu)"),		    hFileMap, shmid, shmflg,		    client->cygpid (), client->winpid ());  return result;}/*---------------------------------------------------------------------------* * server_shmmgr::shmctl () *---------------------------------------------------------------------------*/intserver_shmmgr::shmctl (int & out_shmid,		       struct shmid_ds & out_ds,		       struct shminfo & out_shminfo,		       struct shm_info & out_shm_info,		       const int shmid, const int cmd,		       const struct shmid_ds & ds,		       class process *const client){  syscall_printf ("shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)",		  shmid, cmd, client->cygpid (), client->winpid ());  int result = 0;  EnterCriticalSection (&_segments_lock);  switch (cmd)    {    case IPC_STAT:    case SHM_STAT:		// Uses intids rather than shmids.    case IPC_SET:    case IPC_RMID:      {	int intid;	if (cmd == SHM_STAT)	  intid = shmid;	else	  intid = ipc_ext2int (shmid, IPC_SHMOP);	segment_t *const segptr = find (intid);	if (!segptr)	  result = -EINVAL;	else	  switch (cmd)	    {	    case IPC_STAT:	      out_ds = segptr->_ds;	      break;	    case IPC_SET:	      segptr->_ds.shm_perm.uid = ds.shm_perm.uid;	      segptr->_ds.shm_perm.gid = ds.shm_perm.gid;	      segptr->_ds.shm_perm.mode = ds.shm_perm.mode & 0777;	      segptr->_ds.shm_lpid = client->cygpid ();	      segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.	      break;	    case IPC_RMID:	      if (segptr->is_deleted ())		result = -EIDRM;	      else		{		  segptr->mark_deleted ();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -