bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: System V Shared Memory


From: Neal H Walfield
Subject: Re: System V Shared Memory
Date: 15 Apr 2002 17:11:17 -0400
User-agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/21.1

I have rewritten your patch.  There were a variety of problems with
it.:

  o Coding and logic errors.
  o Not robust.
  o Not thread safe.
  o You should use the libc functions, not hurd rpcs.
  o You need to use the GNU coding standards.
  o You need to follow the glibc conventions
  o Where did you get list.h (what is the copyright)?  Where did you
    copy the other files from (or why did you not change the
    copyright)?

One thing that I really did like from your patch was the use of inode
numbers as ids.

Issues with my patch:

It does not do cuig, cgid, shm_cpid, shm_lpid or shm_nattach which is
needed by the IPC_STAT function of shmctl.  I think that we need to
talk about the proper way to support this.  I considered reserving the
first vm_page_size of each file, however, we cannot be sure that all
users can write to the file -- they may only be permitted to read it.
As for overloading other fields, there just are not enough to go
around.

Additionally, I am interested with comments on how to properly
implement the IPC_RMID functionality for shmctl.  SuSV2 and SuSV3 both
state that when a segment is removed, all mappings must be destroyed.
However, no implementation that I check (which includes Linux, SunOS,
Tru64 and additionally, Stevens' book, Advanced Programming in the
UNIX Environment) does this.  Everyone just destroys the shm
descriptor and all exant mappings remain valid.  What I have done is
slightly different than even this: this code allows for shmat to work
and makes shmget fail.

It should be easy to make shm_open and shm_unlink work with this
implementation.


Comments?


2002-04-15  Neal H Walfield  <neal@cs.uml.edu>

        * sysdeps/mach/hurd/Makefile (sysdep_routines) [$(subdir) =
        sysvipc]:  Add sysvshm.
        * sysdeps/mach/hurd/shmat.c: New file.
        * sysdeps/mach/hurd/shmctl.c: New file.
        * sysdeps/mach/hurd/shmdt.c: New file.
        * sysdeps/mach/hurd/shmget.c: New file.
        * sysdeps/mach/hurd/sysvshm.c: New file.
        * sysdeps/mach/hurd/sysvshm.h: New file.

diff -uprN -x *~ glibc-2.2.5.orig/sysdeps/mach/hurd/Makefile 
glibc-2.2.5/sysdeps/mach/hurd/Makefile
--- glibc-2.2.5.orig/sysdeps/mach/hurd/Makefile Sat Nov 10 18:16:31 2001
+++ glibc-2.2.5/sysdeps/mach/hurd/Makefile      Mon Apr 15 19:01:05 2002
@@ -202,4 +202,8 @@ ifeq ($(subdir),sunrpc)
 sysdep_headers += nfs/nfs.h
 endif
 
+ifeq ($(subdir),sysvipc)
+sysdep_routines += sysvshm
+endif
+
 endif  # in-Makerules
diff -uprN -x *~ glibc-2.2.5.orig/sysdeps/mach/hurd/shmat.c 
glibc-2.2.5/sysdeps/mach/hurd/shmat.c
--- glibc-2.2.5.orig/sysdeps/mach/hurd/shmat.c  Thu Jan  1 01:00:00 1970
+++ glibc-2.2.5/sysdeps/mach/hurd/shmat.c       Mon Apr 15 17:38:54 2002
@@ -0,0 +1,104 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <utime.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include "sysvshm.h"
+
+void *
+__shmat (int id, const void *shmaddr, int flags)
+{
+  error_t err;
+  struct sysvshm_seg *shm;
+  void *addr;
+  struct stat stat;
+  struct timeval times[2];
+
+  __mutex_lock (&sysvshm_lock);
+  shm = __sysvshm_lookup_via_id (id);
+  if (! shm)
+    goto error;
+
+  err = __fstat (shm->fd, &stat);
+  if (err)
+    {
+#ifdef CARE_ABOUT_SYSVIPC_ACCOUNTING
+      goto error;
+#endif
+    }
+  else
+    {
+      char *path;
+
+      /* Recall, we overload these fields.  */
+      __gettimeofday (&times[0], NULL);
+
+      times[1].tv_sec = stat.st_mtime;
+      times[1].tv_usec = stat.st_mtime_usec;
+
+      path = __alloca (sizeof (SHM_DIR) - 1
+                      + sizeof (SHM_PREFIX) - 1
+                      + 40 /* Max size of a 128-bit int in dec.  */ + 1);
+
+      sprintf (path, SHM_DIR SHM_PREFIX "%ld", shm->key);
+
+      err = __utimes (path, &times[0]);
+      if (err)
+       {
+#ifdef CARE_ABOUT_SYSVIPC_ACCOUNTING
+         goto error;
+#endif
+       }
+    }
+
+  if (shm->addr)
+    {
+      assert (shm->attach_count > 0);
+      addr = shm->addr;
+    }
+  else
+    {
+      assert (shm->attach_count == 0);
+      addr = __mmap ((void *) shmaddr, shm->size,
+                    PROT_READ | ((flags & SHM_RDONLY) ? 0 : PROT_WRITE),
+                    MAP_SHARED, shm->fd, 0);
+      if (addr == MAP_FAILED)
+       goto error;
+
+      shm->addr = addr;
+    }
+
+  shm->attach_count ++;
+  __mutex_unlock (&sysvshm_lock);
+  return addr;
+
+ error:
+  __mutex_unlock (&sysvshm_lock);
+  return (void *) -1;
+}
+
+weak_alias(__shmat, shmat)
+
diff -uprN -x *~ glibc-2.2.5.orig/sysdeps/mach/hurd/shmctl.c 
glibc-2.2.5/sysdeps/mach/hurd/shmctl.c
--- glibc-2.2.5.orig/sysdeps/mach/hurd/shmctl.c Thu Jan  1 01:00:00 1970
+++ glibc-2.2.5/sysdeps/mach/hurd/shmctl.c      Mon Apr 15 19:58:51 2002
@@ -0,0 +1,155 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+
+#include "sysvshm.h"
+
+int
+__shmctl (int id, int cmd, struct shmid_ds *buf)
+{
+  error_t err;
+  struct sysvshm_seg *shm;
+  struct stat stat;
+
+  __mutex_lock (&sysvshm_lock);
+  shm = __sysvshm_lookup_via_id (id);
+  if (! shm)
+    {
+      __mutex_unlock (&sysvshm_lock);
+      return -1;
+    }
+
+  switch (cmd)
+    {
+    case IPC_STAT:
+      err = __fstat (shm->fd, &stat);
+      if (! err)
+       {
+         /* shmid_ds contains: */
+         /* Map file stats into shm stats */
+         buf->shm_perm.__key = shm->key;
+         buf->shm_perm.uid = stat.st_uid;
+         buf->shm_perm.gid = stat.st_gid;
+
+#if 0
+         /* XXX: Wrong, wrong, WRONG!  */
+         buf->shm_perm.cuid = stat.st_author;
+         buf->shm_perm.cgid = stat.st_gid;
+#endif
+
+         buf->shm_perm.mode = stat.st_mode;
+         buf->shm_perm.__seq = stat.st_ino;
+         buf->shm_segsz = stat.st_size;
+
+         /* Hijack access time */
+         buf->shm_atime = stat.st_atime;
+         /* Hijack modification time */
+         buf->shm_dtime = stat.st_mtime;
+         buf->shm_ctime = stat.st_ctime;
+
+#if 0
+         /* XXX: Must do shm_cpid and shm_lpid. */
+         /* Hijack low 16 bits of flags */
+         buf->shm_cpid = stat.st_flags & 0xffff;
+         /* Hijack high 16 bits of flags */
+         buf->shm_lpid = stat.st_flags >> 16 & 0xffff;
+#endif
+
+         /* XXX: Arg!  */
+         buf->shm_nattch = 0;
+       }
+      
+      break;
+
+    case IPC_SET:
+#if 0
+      /* XXX: This is *so* wrong, but what to do... */
+
+      err = __file_chown (file, buf->shm_perm.uid,
+                         buf->shm_perm.gid);
+      if (! err)
+       err = __file_chmod (file, buf->shm_perm.mode);
+
+      if (! err)
+       {
+         err = __file_chauthor (file, buf->shm_perm.cuid);
+#ifndef CARE_ABOUT_SYSVIPC_ACCOUNTING
+         if (err)
+           err = 0;
+#endif /* ! CARE_ABOUT_SYSVIPC_ACCOUNTING */
+       }
+
+      if (! err)
+       {
+         err = __file_chflags (file, __getpid ());
+#ifndef CARE_ABOUT_SYSVIPC_ACCOUNTING
+         if (err)
+           err = 0;
+#endif /* ! CARE_ABOUT_SYSVIPC_ACCOUNTING */
+       }
+
+#else /* 0 */
+      err = -1;
+#endif /* 0 */
+      break;
+
+    case IPC_RMID:
+      /* XXX: In this case, most everyone (that is, I checked:
+        Stevens, Linux, SunOS, and Tru64), just unlinks the
+        descriptor and does not allow any future shmat.  SUSv3,
+        however, says that we need to also destory all of the
+        outstanding mappings.  We will just unlink it and fail on any
+        future calls of shmget.  */
+      {
+       char *path;
+
+       path = alloca (sizeof (SHM_DIR) - 1
+                      + sizeof (SHM_PREFIX) - 1
+                      + 40 /* Max size of a 128-bit int in dec.  */ + 1);
+       sprintf (path, SHM_DIR SHM_PREFIX "%ld", shm->key);
+
+       err = __unlink(path);
+
+       if (shm->attach_count == 0)
+         {
+           __sysvshm_detach (shm);
+           free (shm);
+           __close (shm->fd);
+         }
+
+       break;
+      }
+
+    default:
+      errno = EINVAL;
+      err = -1;
+      break;
+    }
+
+  __mutex_unlock (&sysvshm_lock);
+  return err;
+}
+
+weak_alias(__shmctl, shmctl)
diff -uprN -x *~ glibc-2.2.5.orig/sysdeps/mach/hurd/shmdt.c 
glibc-2.2.5/sysdeps/mach/hurd/shmdt.c
--- glibc-2.2.5.orig/sysdeps/mach/hurd/shmdt.c  Thu Jan  1 01:00:00 1970
+++ glibc-2.2.5/sysdeps/mach/hurd/shmdt.c       Mon Apr 15 17:14:15 2002
@@ -0,0 +1,100 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include "sysvshm.h"
+
+int
+__shmdt (const void *addr)
+{
+  error_t err;
+  struct sysvshm_seg *shm;
+  char *path;
+  struct stat stat;
+  struct timeval times[2];
+
+  __mutex_lock (&sysvshm_lock);
+  shm = __sysvshm_lookup_via_addr (addr);
+  if (! shm)
+    {
+      errno = EINVAL;
+      err = -1;
+      goto out;
+    }
+
+  err = __fstat(shm->fd, &stat);
+  if (err)
+    {
+#ifdef CARE_ABOUT_SYSVIPC_ACCOUNTING    
+      goto out;
+#else /* CARE_ABOUT_SYSVIPC_ACCOUNTING */
+      err = 0;
+#endif /* CARE_ABOUT_SYSVIPC_ACCOUNTING */
+    }
+
+  /* Recall, we overload these fields.  */
+  __gettimeofday (&times[1], NULL);
+
+  times[0].tv_sec = stat.st_atime;
+  times[0].tv_usec = stat.st_atime_usec;
+
+  path = __alloca (sizeof (SHM_DIR) - 1
+                  + sizeof (SHM_PREFIX) - 1
+                  + 40 /* Max size of a 128-bit int in dec.  */ + 1);
+
+  sprintf (path, SHM_DIR SHM_PREFIX "%ld", shm->key);
+
+  err = utimes(path, &times[0]);
+  if (err)
+    {
+#ifdef CARE_ABOUT_SYSVIPC_ACCOUNTING
+      goto out;
+#else /* CARE_ABOUT_SYSVIPC_ACCOUNTING */
+      err = 0;
+#endif /* CARE_ABOUT_SYSVIPC_ACCOUNTING */
+    }
+
+  assert (shm->attach_count > 0);
+  shm->attach_count --;
+  if (shm->attach_count == 0)
+    {
+      __munmap (shm->addr, shm->size);
+      __sysvshm_detach (shm);
+      free (shm);
+      __close (shm->fd);
+    }
+
+ out:
+  __mutex_unlock (&sysvshm_lock);
+  return err;
+}
+
+weak_alias(__shmdt, shmdt)
+
+
+
diff -uprN -x *~ glibc-2.2.5.orig/sysdeps/mach/hurd/shmget.c 
glibc-2.2.5/sysdeps/mach/hurd/shmget.c
--- glibc-2.2.5.orig/sysdeps/mach/hurd/shmget.c Thu Jan  1 01:00:00 1970
+++ glibc-2.2.5/sysdeps/mach/hurd/shmget.c      Mon Apr 15 09:14:40 2002
@@ -0,0 +1,182 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "sysvshm.h"
+
+int
+__shmget (key_t key, size_t size, int shmflags)
+{
+  error_t err;
+  int id;
+  struct sysvshm_seg *shm;
+  int create_flags;
+  int private_key;
+  char *path;
+  int fd;
+  struct stat stat;
+
+  if (key != IPC_PRIVATE)
+    {
+      __mutex_lock (&sysvshm_lock);
+      shm = __sysvshm_lookup_via_key (key);
+      if (shm)
+       {
+         id = shm->id;
+         __mutex_unlock (&sysvshm_lock);
+         return id;
+       }
+      __mutex_unlock (&sysvshm_lock);
+    }
+
+  shm = malloc (sizeof (struct sysvshm_seg));
+  if (! shm)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  create_flags = (((shmflags & IPC_CREAT) ? O_CREAT : 0)
+                 | ((shmflags & IPC_EXCL) ? O_EXCL : 0));
+
+  private_key = key == IPC_PRIVATE;
+  if (private_key)
+    {
+      /* Private segments have negative keys; start the search at
+        -1.  */
+      key = -1;
+      create_flags |= O_CREAT | O_EXCL;
+    }
+
+  path = __alloca (sizeof (SHM_DIR) - 1
+                  + sizeof (SHM_PREFIX) - 1
+                  + 40 /* Max size of a 128-bit int in dec.  */ + 1);
+
+  sprintf (path, SHM_DIR SHM_PREFIX "%ld", key);
+
+  if (create_flags && ! (create_flags & O_EXCL))
+    /* We *must* know if we are the creator.  */
+    {
+      fd = __open (path, O_RDWR | create_flags | O_EXCL,
+                  shmflags & 0777);
+      if (fd < 0 && errno == EEXIST)
+       {
+         create_flags = 0;
+         goto try_open;
+       }
+    }
+  else
+    {
+    try_open:
+      for (;;)
+       {
+         /* Later, we might try to attach to the file read/write, so,
+            even if we are looking for readonly access now, try to open
+            the file read/write (unless we are creating it, then do not
+            bother with readonly access).  */
+         fd = __open (path, O_RDWR | create_flags, shmflags & 0777);
+         if (fd < 0 && ! create_flags && errno == EACCES)
+           fd = __open (path, O_RDONLY | create_flags & 0777);
+         
+         if (private_key && fd < 0 && errno == EEXIST)
+           {
+             key --;
+             sprintf (path, SHM_DIR SHM_PREFIX "%ld", key);
+           }
+         else
+           break;
+       }
+    }
+
+  if (fd < 0)
+    goto error;
+
+  if (create_flags)
+    /* Just created it; set the file's size.  */
+    {
+      char data = 0;
+      size_t count;
+
+      err = __lseek (fd, size - 1, SEEK_SET);
+      if (err < 0)
+       goto error_with_file;
+
+      count = __write (fd, &data, 1);
+      if (count != 1)
+       goto error_with_file;
+    }
+
+#if 0
+  /* If either of these fail, it's not a reason to abort: We simply
+     lose a little bit of accounting infomation that would normally be
+     provided through shmctl.  */
+  err = __file_chauthor (fd, __geteuid ());
+#ifdef CARE_ABOUT_SYSVIPC_ACCOUNTING
+  if (err)
+    {
+      errno = err;
+      goto error_with_file;
+    }
+#endif /* CARE_ABOUT_SYSVIPC_ACCOUNTING */
+
+  err = __file_chflags (fd, __getpid ());
+#ifdef CARE_ABOUT_SYSVIPC_ACCOUNTING
+  if (err)
+    {
+      errno = err;
+      goto error_with_file;
+    }
+#endif /* CARE_ABOUT_SYSVIPC_ACCOUNTING */
+#endif /* 0 */
+
+  err = __fstat (fd, &stat);
+  if (err)
+    goto error_with_file;
+
+  shm->key = key;
+  shm->id = stat.st_ino;
+  shm->fd = fd;
+  shm->size = size;
+  shm->addr = 0;
+  shm->attach_count = 0;
+
+  __mutex_lock (&sysvshm_lock);
+  __sysvshm_add_new (shm);
+  __mutex_unlock (&sysvshm_lock);
+
+  return stat.st_ino;
+
+ error_with_file:
+  __close (fd);
+  __unlink (path);
+ error:
+  free (shm);
+  return -1;
+}
+
+weak_alias(__shmget, shmget)
diff -uprN -x *~ glibc-2.2.5.orig/sysdeps/mach/hurd/sysvshm.c 
glibc-2.2.5/sysdeps/mach/hurd/sysvshm.c
--- glibc-2.2.5.orig/sysdeps/mach/hurd/sysvshm.c        Thu Jan  1 01:00:00 1970
+++ glibc-2.2.5/sysdeps/mach/hurd/sysvshm.c     Mon Apr 15 21:48:30 2002
@@ -0,0 +1,200 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/shm.h>
+
+#include "sysvshm.h"
+
+struct mutex sysvshm_lock = MUTEX_INITIALIZER;
+
+static struct sysvshm_seg *segs;
+
+void
+__sysvshm_add_new (struct sysvshm_seg *seg)
+{
+  seg->next = segs;
+  if (seg->next)
+    seg->next->prevp = &seg->next;
+  seg->prevp = &segs;
+  segs = seg;
+}
+
+void
+__sysvshm_detach (struct sysvshm_seg *seg)
+{
+  *seg->prevp = seg->next;
+  if (seg->next)
+    seg->next->prevp = seg->prevp;
+}
+
+struct sysvshm_seg *
+__sysvshm_lookup_via_id (int id)
+{
+  error_t err;
+  struct sysvshm_seg *seg;
+  DIR *d;
+  struct dirent *de;
+  int name_max;
+  key_t key;
+  char *path;
+  int fd;
+  struct stat stat;
+
+  /* Check the cache.  */
+  for (seg = segs; seg; seg = seg->next)
+    if (seg->id == id)
+      return seg;
+
+  /* Try to find the segment.  */
+
+  /* How large must DE be?  */
+  errno = 0;
+  name_max = __pathconf (SHM_DIR, _PC_NAME_MAX);
+  if (errno)
+    {
+      errno = EINVAL;
+      return (void *) -1;
+    }
+  if (name_max < 0)
+    /* XXX: Major hack.  There is no way to get the largest path
+       component.  */
+    name_max = FILENAME_MAX;
+
+  de = __alloca (offsetof (struct dirent, d_name) + name_max + 1);
+
+  d = __opendir (SHM_DIR);
+  if (! d)
+    return NULL;
+
+  for (;;)
+    {
+      char *end;
+
+      do
+       err = __readdir_r (d, de, &de);
+      while (err == 0 && de && de->d_ino != id);
+
+      if (de == NULL)
+       err = errno = EINVAL;
+      if (err)
+       {
+         __closedir (d);
+         return 0;
+       }
+
+      /* A few sanity checks -- the id may match, however, it could
+        have just been a hard link fooling us.  */
+
+      if (de->d_namlen < sizeof (SHM_PREFIX) - 1
+         || strncmp (de->d_name, SHM_PREFIX, sizeof (SHM_PREFIX) - 1))
+       continue;
+
+      end = 0;
+      key = strtol (de->d_name + sizeof (SHM_PREFIX) - 1, &end, 10);
+      if (end && *end)
+       continue;
+
+      /* Looks good.  */
+      break;
+    }
+
+  __closedir (d);
+
+  /* We have a match, read it in.  */
+
+  path = alloca (sizeof (SHM_DIR) - 1 + sizeof (SHM_PREFIX) - 1
+                + 40 /* Max size of a 128-bit int in hex.  */ + 1);
+  sprintf (path, SHM_DIR SHM_PREFIX "%ld", key);
+
+  fd = __open (path, O_RDWR);
+  if (fd < 0)
+    if (errno == EACCES)
+      fd = __open (path, O_RDONLY);
+  if (fd < 0)
+    switch (errno)
+      {
+      default:
+       errno = EINVAL;
+      case EACCES:
+      case EPERM:
+       return 0;
+      }
+
+  err = __fstat (fd, &stat);
+  if (err)
+    {
+      __close (fd);
+      return NULL;
+    }
+
+  seg = malloc (sizeof (struct sysvshm_seg));
+  if (!seg)
+    {
+      errno = ENOMEM;
+      __close (fd);
+      return NULL;
+    }
+
+  seg->id = de->d_ino;
+  seg->key = key;
+  seg->fd = fd;
+  seg->size = stat.st_size;
+  seg->addr = 0;
+  seg->attach_count = 0;
+
+  seg->next = segs;
+  if (seg->next)
+    seg->next->prevp = &seg->next;
+  seg->prevp = &segs;
+  segs = seg;
+
+  return seg;
+}
+
+struct sysvshm_seg *
+__sysvshm_lookup_via_key (int key)
+{
+  struct sysvshm_seg *seg;
+
+  for (seg = segs; seg; seg = seg->next)
+    if (seg->key == key)
+      break;
+
+  return seg;
+}
+
+struct sysvshm_seg *
+__sysvshm_lookup_via_addr (const void *addr)
+{
+  struct sysvshm_seg *seg;
+
+  for (seg = segs; seg; seg = seg->next)
+    if (seg->addr == addr)
+      break;
+
+  return seg;
+}
diff -uprN -x *~ glibc-2.2.5.orig/sysdeps/mach/hurd/sysvshm.h 
glibc-2.2.5/sysdeps/mach/hurd/sysvshm.h
--- glibc-2.2.5.orig/sysdeps/mach/hurd/sysvshm.h        Thu Jan  1 01:00:00 1970
+++ glibc-2.2.5/sysdeps/mach/hurd/sysvshm.h     Mon Apr 15 17:39:15 2002
@@ -0,0 +1,61 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <hurd.h>
+
+#define SHM_PREFIX "shm-"
+#define SHM_DIR "/dev/shm/"
+
+/* Description of an shm segment.  */
+struct sysvshm_seg
+{
+  int id;              /* Segment identifier.  This is also the inode.  */
+  key_t key;           /* The key.  Negative if created using IPC_PRIVATE.  */
+  int fd;              /* A cached file descriptor to it.  */
+  size_t size;         /* The size of the segment.  */
+  void *addr;          /* Address of the map or NULL if not yet attached.  */
+  int attach_count;     /* The attach count.  */
+  struct sysvshm_seg *next;
+  struct sysvshm_seg **prevp;
+};
+
+extern struct mutex sysvshm_lock;
+
+/* All function must be called with sysvshm_lock held; it will remain
+   so on return.  */
+
+/* Adds a segment descriptor to the local pool.  */
+void __sysvshm_add_new (struct sysvshm_seg *seg);
+
+/* Removes local shared memory segment descriptor from the cache.
+   After this call exist, the caller owns seg and is responsible for
+   freeing the associated memory via free.  */
+void __sysvshm_detach (struct sysvshm_seg *seg);
+
+/* Returns a segment descriptor describing shared memory segment ID.
+   Returns NULL and sets errno on failure.  */
+struct sysvshm_seg *__sysvshm_lookup_via_id (int id);
+
+/* Returns the local segment descriptor associated with KEY.  Returns
+   NULL on error.  */
+struct sysvshm_seg *__sysvshm_lookup_via_key (int key);
+
+/* Returns the local segment descriptor describing the shared memory
+   segment starting at address ADDR.  Returns NULL if there is
+   none.  */
+struct sysvshm_seg *__sysvshm_lookup_via_addr (const void *addr);





reply via email to

[Prev in Thread] Current Thread [Next in Thread]