Index: trunk/src/emx/ChangeLog.LIBC
===================================================================
--- trunk/src/emx/ChangeLog.LIBC	(revision 1985)
+++ trunk/src/emx/ChangeLog.LIBC	(revision 1986)
@@ -7,4 +7,5 @@
         o Added a signal notification callback to the thread structure.
         o Changed tcpip term callback to more generic exitlist callback (SPM).
+        o Ported the BSD SysV Shared Memory module.
 
 2005-05-05: knut st. osmundsen <bird-gccos2-spam@anduin.net>
Index: trunk/src/emx/include/InnoTekLIBC/backend.h
===================================================================
--- trunk/src/emx/include/InnoTekLIBC/backend.h	(revision 1985)
+++ trunk/src/emx/include/InnoTekLIBC/backend.h	(revision 1986)
@@ -894,4 +894,15 @@
 /** @defgroup grp_Back_sysvipc LIBC Backend - SysV IPC
  * @{ */
+
+/**
+ * sysget syscall.
+ */
+int __libc_Back_sysvSemGet(key_t key, int nsems, int semflg);
+
+/**
+ * semop syscall.
+ */
+int __libc_Back_sysvSemOp(int semid, struct sembuf *sops_user, size_t nsops);
+
 /**
  * semctl syscall
@@ -899,13 +910,130 @@
 int __libc_Back_sysvSemCtl(int semid, int semnum, int cmd, union semun real_arg);
 
-/**
- * sysget syscall.
- */
-int __libc_Back_sysvSemGet(key_t key, int nsems, int semflg);
-
-/**
- * semop syscall.
- */
-int __libc_Back_sysvSemOp(int semid, struct sembuf *sops_user, size_t nsops);
+
+/**
+ * shmget.
+ */
+int __libc_Back_sysvShmGet(key_t key, size_t size, int shmflg);
+
+/**
+ * shmat.
+ */
+int __libc_Back_sysvShmAt(int shmid, const void *shmaddr, int shmflg, void **ppvActual);
+
+/**
+ * shmdt.
+ */
+int __libc_Back_sysvShmDt(const void *shmaddr);
+
+/**
+ * shmctl.
+ */
+int __libc_Back_sysvShmCtl(int shmid, int cmd, struct shmid_ds *bufptr);
+
+/** @} */
+
+
+/** @defgroup grp_Back_safesem LIBC Backend - Internal Signal-Safe Semaphores.
+ * @{ */
+
+/**
+ * Creates a safe mutex sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   phmtx       Where to store the semaphore handle.
+ * @param   fShared     Set if the semaphore should be sharable between processes.
+ */
+int __libc_Back_safesemMtxCreate(uintptr_t *phmtx, int fShared);
+
+/**
+ * Opens a shared safe mutex sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hmtx        The semaphore handle.
+ */
+int __libc_Back_safesemMtxOpen(uintptr_t hmtx);
+
+/**
+ * Closes a shared safe mutex sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hmtx        The semaphore handle.
+ */
+int __libc_Back_safesemMtxClose(uintptr_t hmtx);
+
+/**
+ * Locks a mutex semaphore.
+ *
+ * @returns 0 on success.
+ * @returns Negative errno on failure.
+ * @param   hmtx    Handle to the mutex.
+ */
+int __libc_Back_safesemMtxLock(uintptr_t hmtx);
+
+/**
+ * Unlocks a mutex semaphore.
+ *
+ * @returns 0 on success.
+ * @returns Negative errno on failure.
+ * @param   hmtx    Handle to the mutex.
+ */
+int __libc_Back_safesemMtxUnlock(uintptr_t hmtx);
+
+/**
+ * Creates a safe event sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   phev        Where to store the semaphore handle.
+ * @param   fShared     Set if the semaphore should be sharable between processes.
+ */
+int __libc_Back_safesemEvCreate(uintptr_t *phev, int fShared);
+
+/**
+ * Opens a shared safe event sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hev         The semaphore handle.
+ */
+int __libc_Back_safesemEvOpen(uintptr_t hev);
+
+/**
+ * Closes a shared safe mutex sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hev         The semaphore handle.
+ */
+int __libc_Back_safesemEvClose(uintptr_t hev);
+
+/**
+ * Sleep on a semaphore.
+ *
+ * This is the most difficult thing we're doing in this file.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ *
+ * @param   hev         The semaphore to sleep on.
+ * @param   hmtx        The semaphore protecting hev and which is to be unlocked while
+ *                      sleeping and reaquired upon waking up.
+ * @param   pfnComplete Function to execute on signal and on wait completion.
+ * @param   pvUser      User argument to pfnComplete.
+ */
+int __libc_Back_safesemEvSleep(uintptr_t hev, uintptr_t hmtx, void (*pfnComplete)(void *pvUser), void *pvUser);
+
+/**
+ * Wakes up all threads sleeping on a given event semaphore.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hev         Event semaphore to post.
+ */
+int __libc_Back_safesemEvWakeup(uintptr_t hev);
+
 
 /** @} */
Index: trunk/src/emx/include/InnoTekLIBC/logstrict.h
===================================================================
--- trunk/src/emx/include/InnoTekLIBC/logstrict.h	(revision 1985)
+++ trunk/src/emx/include/InnoTekLIBC/logstrict.h	(revision 1986)
@@ -184,4 +184,6 @@
 #define __LIBC_LOG_GRP_MMAN         16
 
+/** Backend SysV IPC APIs. */
+#define __LIBC_LOG_GRP_BACK_IPC     17
 /** Backend Thread APIs. */
 #define __LIBC_LOG_GRP_BACK_THREAD  18
Index: trunk/src/emx/include/InnoTekLIBC/sharedpm.h
===================================================================
--- trunk/src/emx/include/InnoTekLIBC/sharedpm.h	(revision 1985)
+++ trunk/src/emx/include/InnoTekLIBC/sharedpm.h	(revision 1986)
@@ -557,6 +557,10 @@
     /** 116 - Pointer to SysV Sempahore globals. */
     struct __libc_SysV_Sem             *pSysVSem;
-
-    /*  120 - The rest of the block, up to cbProcess, is undefined in this version.
+    /** 120 - Pointer to SysV Shared Memory globals. */
+    struct __libc_SysV_Shm             *pSysVShm;
+    /** 124 - Pointer to SysV Message Queue globals. */
+    struct __libc_SysV_Msg             *pSysVMsg;
+
+    /*  128 - The rest of the block, up to cbProcess, is undefined in this version.
      * Future versions of LIBC may use this area assuming it's initalized with zeros.
      */
Index: trunk/src/emx/include/sys/shm.h
===================================================================
--- trunk/src/emx/include/sys/shm.h	(revision 1985)
+++ trunk/src/emx/include/sys/shm.h	(revision 1986)
@@ -39,4 +39,5 @@
 /** @file
  * FreeBSD 5.3
+ * @changed the SHMLBA to 64KB.
  */
 
@@ -48,5 +49,5 @@
 #define SHM_RDONLY  010000  /* Attach read-only (else read-write) */
 #define SHM_RND     020000  /* Round attach address to SHMLBA */
-#define SHMLBA      PAGE_SIZE /* Segment low boundary address multiple */
+#define SHMLBA      (0x10000) /* Segment low boundary address multiple */
 
 /* "official" access mode definitions; somewhat braindead since you have
@@ -63,10 +64,22 @@
 #define	SHM_INFO	14
 
+#ifdef __EMX__
+typedef __uint32_t shmatt_t;
+#endif
+
 struct shmid_ds {
 	struct ipc_perm shm_perm;	/* operation permission structure */
+#ifdef __EMX__
+	size_t          shm_segsz;	/* size of segment in bytes */
+#else
 	int             shm_segsz;	/* size of segment in bytes */
+#endif
 	pid_t           shm_lpid;   /* process ID of last shared memory op */
 	pid_t           shm_cpid;	/* process ID of creator */
-	short		shm_nattch;	/* number of current attaches */
+#ifdef __EMX__
+	shmatt_t	shm_nattch;	/* number of current attaches */
+#else
+	short   	shm_nattch;	/* number of current attaches */
+#endif
 	time_t          shm_atime;	/* time of last shmat() */
 	time_t          shm_dtime;	/* time of last shmdt() */
@@ -88,6 +101,8 @@
 		shmall;		/* max amount of shared memory (pages) */
 };
+#ifndef __EMX__
 extern struct shminfo	shminfo;
 extern struct shmid_ds	*shmsegs;
+#endif
 
 struct shm_info {
@@ -100,4 +115,5 @@
 };
 
+#ifndef __EMX__
 struct thread;
 struct proc;
@@ -106,4 +122,5 @@
 void	shmexit(struct vmspace *);
 void	shmfork(struct proc *, struct proc *);
+#endif /* !__EMX__ */
 #else /* !_KERNEL */
 
@@ -116,5 +133,7 @@
 
 __BEGIN_DECLS
+#ifndef __EMX__
 int shmsys(int, ...);
+#endif
 void *shmat(int, const void *, int);
 int shmget(key_t, size_t, int);
Index: trunk/src/emx/src/lib/libc.def
===================================================================
--- trunk/src/emx/src/lib/libc.def	(revision 1985)
+++ trunk/src/emx/src/lib/libc.def	(revision 1986)
@@ -1529,9 +1529,27 @@
     "__getenv_long" @1534
     "__getenv_longlong" @1535
-    "___libc_Back_sysvSemCtl" @1536
-    "___libc_Back_sysvSemGet" @1537
-    "___libc_Back_sysvSemOp" @1538
-    "__std_ftok" @1539
-    "__std_semctl" @1540
-    "__std_semget" @1541
-    "__std_semop" @1542
+    "___libc_Back_safesemEvClose" @1536
+    "___libc_Back_safesemEvCreate" @1537
+    "___libc_Back_safesemEvOpen" @1538
+    "___libc_Back_safesemEvSleep" @1539
+    "___libc_Back_safesemEvWakeup" @1540
+    "___libc_Back_safesemMtxClose" @1541
+    "___libc_Back_safesemMtxCreate" @1542
+    "___libc_Back_safesemMtxLock" @1543
+    "___libc_Back_safesemMtxOpen" @1544
+    "___libc_Back_safesemMtxUnlock" @1545
+    "___libc_Back_sysvSemCtl" @1546
+    "___libc_Back_sysvSemGet" @1547
+    "___libc_Back_sysvSemOp" @1548
+    "___libc_Back_sysvShmAt" @1549
+    "___libc_Back_sysvShmCtl" @1550
+    "___libc_Back_sysvShmDt" @1551
+    "___libc_Back_sysvShmGet" @1552
+    "__std_ftok" @1553
+    "__std_semctl" @1554
+    "__std_semget" @1555
+    "__std_semop" @1556
+    "__std_shmat" @1557
+    "__std_shmctl" @1558
+    "__std_shmdt" @1559
+    "__std_shmget" @1560
Index: trunk/src/emx/src/lib/process/semctl.c
===================================================================
--- trunk/src/emx/src/lib/process/semctl.c	(revision 1985)
+++ trunk/src/emx/src/lib/process/semctl.c	(revision 1986)
@@ -40,5 +40,5 @@
 
 /**
- * semop.
+ * semctl.
  */
 int _STD(semctl)(int semid, int semnum, int cmd, ...)
Index: trunk/src/emx/src/lib/process/shmat.c
===================================================================
--- trunk/src/emx/src/lib/process/shmat.c	(revision 1986)
+++ trunk/src/emx/src/lib/process/shmat.c	(revision 1986)
@@ -0,0 +1,54 @@
+/* $Id$ */
+/** @file
+ *
+ * LIBC - shmat.
+ *
+ * Copyright (c) 2005 knut st. osmundsen <bird@anduin.net>
+ *
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "libc-alias.h"
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <InnoTekLIBC/backend.h>
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_PROCESS
+#include <InnoTekLIBC/logstrict.h>
+
+
+/**
+ * shmat.
+ */
+void *_STD(shmat)(int shmid, const void *shmaddr, int shmflg)
+{
+    LIBCLOG_ENTER("shmid=%#x shmaddr=%p shmflg=%#x\n", shmid, shmaddr, shmflg);
+    void *pvActual = NULL;
+    int rc = __libc_Back_sysvShmAt(shmid, shmaddr, shmflg, &pvActual);
+    if (rc >= 0)
+        LIBCLOG_RETURN_P(pvActual);
+    errno = -rc;
+    LIBCLOG_RETURN_P(NULL);
+}
+
Index: trunk/src/emx/src/lib/process/shmctl.c
===================================================================
--- trunk/src/emx/src/lib/process/shmctl.c	(revision 1986)
+++ trunk/src/emx/src/lib/process/shmctl.c	(revision 1986)
@@ -0,0 +1,53 @@
+/* $Id$ */
+/** @file
+ *
+ * LIBC - shmctl.
+ *
+ * Copyright (c) 2005 knut st. osmundsen <bird@anduin.net>
+ *
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "libc-alias.h"
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <InnoTekLIBC/backend.h>
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_PROCESS
+#include <InnoTekLIBC/logstrict.h>
+
+
+/**
+ * shmctl.
+ */
+int _STD(shmctl)(int shmid, int cmd, struct shmid_ds *bufptr)
+{
+    LIBCLOG_ENTER("shmid=%#x cmd=%d bufptr=%p\n", shmid, cmd, (void *)bufptr);
+    int rc = __libc_Back_sysvShmCtl(shmid, cmd, bufptr);
+    if (rc >= 0)
+        LIBCLOG_RETURN_INT(rc);
+    errno = -rc;
+    LIBCLOG_RETURN_INT(-1);
+}
+
Index: trunk/src/emx/src/lib/process/shmdt.c
===================================================================
--- trunk/src/emx/src/lib/process/shmdt.c	(revision 1986)
+++ trunk/src/emx/src/lib/process/shmdt.c	(revision 1986)
@@ -0,0 +1,53 @@
+/* $Id$ */
+/** @file
+ *
+ * LIBC - shmdt.
+ *
+ * Copyright (c) 2005 knut st. osmundsen <bird@anduin.net>
+ *
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "libc-alias.h"
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <InnoTekLIBC/backend.h>
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_PROCESS
+#include <InnoTekLIBC/logstrict.h>
+
+
+/**
+ * shmdt.
+ */
+int _STD(shmdt)(const void *shmaddr)
+{
+    LIBCLOG_ENTER("shmaddr=%p\n", shmaddr);
+    int rc = __libc_Back_sysvShmDt(shmaddr);
+    if (rc >= 0)
+        LIBCLOG_RETURN_INT(rc);
+    errno = -rc;
+    LIBCLOG_RETURN_INT(-1);
+}
+
Index: trunk/src/emx/src/lib/process/shmget.c
===================================================================
--- trunk/src/emx/src/lib/process/shmget.c	(revision 1986)
+++ trunk/src/emx/src/lib/process/shmget.c	(revision 1986)
@@ -0,0 +1,53 @@
+/* $Id$ */
+/** @file
+ *
+ * LIBC - shmctl.
+ *
+ * Copyright (c) 2005 knut st. osmundsen <bird@anduin.net>
+ *
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "libc-alias.h"
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <InnoTekLIBC/backend.h>
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_PROCESS
+#include <InnoTekLIBC/logstrict.h>
+
+
+/**
+ * shmget.
+ */
+int _STD(shmget)(key_t key, size_t size, int shmflg)
+{
+    LIBCLOG_ENTER("key=%#lx size=%#x shmflg=%#x\n", key, size, shmflg);
+    int rc = __libc_Back_sysvShmGet(key, size, shmflg);
+    if (rc >= 0)
+        LIBCLOG_RETURN_INT(rc);
+    errno = -rc;
+    LIBCLOG_RETURN_INT(-1);
+}
+
Index: trunk/src/emx/src/lib/sys/safesems.c
===================================================================
--- trunk/src/emx/src/lib/sys/safesems.c	(revision 1986)
+++ trunk/src/emx/src/lib/sys/safesems.c	(revision 1986)
@@ -0,0 +1,381 @@
+/* $Id$ */
+/** @file
+ *
+ * LIBC SYS Backend - Internal Signal-Safe Semaphores.
+ *
+ * Copyright (c) 2005 knut st. osmundsen <bird@anduin.net>
+ *
+ *
+ * This file is part of InnoTek LIBC.
+ *
+ * InnoTek LIBC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * InnoTek LIBC 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with InnoTek LIBC; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSEXCEPTIONS
+#define INCL_DOSERRORS
+#define INCL_FSMACROS
+#define INCL_EXAPIS
+#include <os2emx.h>
+#include <sys/errno.h>
+#include "syscalls.h"
+#include <InnoTekLIBC/thread.h>
+#include <InnoTekLIBC/backend.h>
+#define __LIBC_LOG_GROUP    __LIBC_LOG_GRP_BACK_IPC
+#include <InnoTekLIBC/logstrict.h>
+
+
+/**
+ * Creates a safe mutex sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   phmtx       Where to store the semaphore handle.
+ * @param   fShared     Set if the semaphore should be sharable between processes.
+ */
+int __libc_Back_safesemMtxCreate(uintptr_t *phmtx, int fShared)
+{
+    FS_VAR_SAVE_LOAD();
+    HMTX hmtx = NULLHANDLE;
+    int rc = DosCreateMutexSemEx(NULL, &hmtx, fShared ? DC_SEM_SHARED : 0, FALSE);
+    FS_RESTORE();
+    if (rc)
+        return -__libc_native2errno(rc);
+    *phmtx = hmtx;
+    return 0;
+}
+
+
+/**
+ * Opens a shared safe mutex sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hmtx        The semaphore handle.
+ */
+int __libc_Back_safesemMtxOpen(uintptr_t hmtx)
+{
+    FS_VAR_SAVE_LOAD();
+    HMTX hmtxOS2 = hmtx;
+    int rc = DosOpenMutexSemEx(NULL, &hmtxOS2);
+    FS_RESTORE();
+    if (rc)
+        return -__libc_native2errno(rc);
+    return 0;
+}
+
+
+/**
+ * Closes a shared safe mutex sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hmtx        The semaphore handle.
+ */
+int __libc_Back_safesemMtxClose(uintptr_t hmtx)
+{
+    FS_VAR_SAVE_LOAD();
+    int rc = DosCloseMutexSemEx(hmtx);
+    FS_RESTORE();
+    if (rc)
+        return -__libc_native2errno(rc);
+    return 0;
+}
+
+
+/**
+ * This function checks that there is at least 2k of writable
+ * stack available. If there isn't, a crash is usually the
+ * result.
+ * @internal
+ */
+static int stackChecker(void)
+{
+    char volatile *pch = alloca(2048);
+    if (!pch)
+        return -1;
+    /* With any luck the compiler doesn't optimize this away. */
+    pch[0] = pch[1024] = pch[2044] = 0x7f;
+    return 0;
+}
+
+
+/**
+ * Locks a mutex semaphore.
+ *
+ * @returns 0 on success.
+ * @returns Negative errno on failure.
+ * @param   hmtx    Handle to the mutex.
+ */
+int __libc_Back_safesemMtxLock(uintptr_t hmtx)
+{
+    LIBCLOG_ENTER("hmtx=%#x\n", hmtx);
+    ULONG       ul;
+    int         rc;
+    FS_VAR();
+
+    /*
+     * Check stack.
+     */
+    if (stackChecker())
+    {
+        LIBC_ASSERTM_FAILED("Too little stack left!\n");
+        LIBCLOG_RETURN_INT(-EFAULT);
+    }
+
+    /*
+     * Request semaphore and enter "must complete section" to avoid signal trouble.
+     */
+    FS_SAVE_LOAD();
+    rc = DosRequestMutexSem(hmtx, 30*1000);
+    DosEnterMustComplete(&ul);
+    if (!rc)
+    {
+        FS_RESTORE();
+        LIBCLOG_RETURN_INT(0);
+    }
+
+    /* failure out */
+    DosExitMustComplete(&ul);
+    LIBC_ASSERTM_FAILED("DosRequestMutexSem(%x) failed with rc=%d!\n", hmtx, rc);
+    rc = -__libc_native2errno(rc);
+    FS_RESTORE();
+    LIBCLOG_RETURN_INT(rc);
+}
+
+
+/**
+ * Unlocks a mutex semaphore.
+ *
+ * @returns 0 on success.
+ * @returns Negative errno on failure.
+ * @param   hmtx    Handle to the mutex.
+ */
+int __libc_Back_safesemMtxUnlock(uintptr_t hmtx)
+{
+    LIBCLOG_ENTER("hmtx=%#x\n", hmtx);
+    ULONG   ul = 0;
+    int     rc;
+    FS_VAR();
+
+    /*
+     * Release the semaphore.
+     */
+    FS_SAVE_LOAD();
+    rc = DosReleaseMutexSem(hmtx);
+    if (rc)
+    {
+        FS_RESTORE();
+        LIBC_ASSERTM_FAILED("DosReleaseMutexSem(%x) -> %d\n", hmtx, rc);
+        rc = -__libc_native2errno(rc);
+        LIBCLOG_RETURN_INT(rc);
+    }
+
+    DosExitMustComplete(&ul);
+    FS_RESTORE();
+    LIBCLOG_RETURN_INT(0);
+}
+
+
+
+/**
+ * Creates a safe event sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   phev        Where to store the semaphore handle.
+ * @param   fShared     Set if the semaphore should be sharable between processes.
+ */
+int __libc_Back_safesemEvCreate(uintptr_t *phev, int fShared)
+{
+    FS_VAR_SAVE_LOAD();
+    HEV hev = NULLHANDLE;
+    int rc = DosCreateEventSemEx(NULL, &hev, fShared ? DC_SEM_SHARED : 0, FALSE);
+    FS_RESTORE();
+    if (rc)
+        return -__libc_native2errno(rc);
+    *phev = hev;
+    return 0;
+}
+
+
+/**
+ * Opens a shared safe event sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hev         The semaphore handle.
+ */
+int __libc_Back_safesemEvOpen(uintptr_t hev)
+{
+    FS_VAR_SAVE_LOAD();
+    HMTX hevOS2 = hev;
+    int rc = DosOpenEventSemEx(NULL, &hevOS2);
+    FS_RESTORE();
+    if (rc)
+        return -__libc_native2errno(rc);
+    return 0;
+}
+
+
+/**
+ * Closes a shared safe mutex sem.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hev         The semaphore handle.
+ */
+int __libc_Back_safesemEvClose(uintptr_t hev)
+{
+    FS_VAR_SAVE_LOAD();
+    int rc = DosCloseEventSemEx(hev);
+    FS_RESTORE();
+    if (rc)
+        return -__libc_native2errno(rc);
+    return 0;
+}
+
+
+
+/**
+ * Arguments to semEvSleepSignalCallback().
+ */
+struct SignalArgs
+{
+    /** Set if pfnComplete have already been executed. */
+    volatile int            fDone;
+    /** Number of attempts at doing it. (in case of crashes in pfnComplete) */
+    volatile int            cTries;
+    /** Callback to execute. */
+    void                  (*pfnComplete)(void *pvUser);
+    /** User arg. */
+    void                   *pvUser;
+};
+
+/**
+ * Signal notification callback.
+ */
+static void semEvSleepSignalCallback(int iSignal, void *pvUser)
+{
+    struct SignalArgs *pArgs = (struct SignalArgs *)pvUser;
+    if (!pArgs->fDone && pArgs->cTries++ < 5)
+    {
+        pArgs->pfnComplete(pArgs->pvUser);
+        pArgs->fDone = 1;
+    }
+}
+
+/**
+ * Sleep on a semaphore.
+ *
+ * This is the most difficult thing we're doing in this file.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ *
+ * @param   hev         The semaphore to sleep on.
+ * @param   hmtx        The semaphore protecting hev and which is to be unlocked while
+ *                      sleeping and reaquired upon waking up.
+ * @param   pfnComplete Function to execute on signal and on wait completion.
+ * @param   pvUser      User argument to pfnComplete.
+ */
+int __libc_Back_safesemEvSleep(uintptr_t hev, uintptr_t hmtx, void (*pfnComplete)(void *pvUser), void *pvUser)
+{
+    LIBCLOG_ENTER("hev=%#x hmtx=%#x pfnComplete=%p pvUser=%p\n", hev, hmtx, (void *)pfnComplete, pvUser);
+
+    /*
+     * Setup signal notification.
+     */
+    __LIBC_PTHREAD pThrd = __libc_threadCurrentNoAuto();
+    int rc;
+    if (pThrd)
+    {
+        struct SignalArgs Args;
+        Args.fDone          = 0;
+        Args.cTries         = 0;
+        Args.pfnComplete    = pfnComplete;
+        Args.pvUser         = pvUser;
+        pThrd->pvSigCallbackUser = &Args;
+        pThrd->pfnSigCallback    = semEvSleepSignalCallback;
+
+        /*
+         * Reset the event semaphore.
+         */
+        ULONG ulIgnore;
+        FS_VAR_SAVE_LOAD();
+        rc = DosResetEventSem(hev, &ulIgnore);
+        if (!rc || rc == ERROR_ALREADY_RESET)
+        {
+            /*
+             * Release the sempahore and exit the must complete section.
+             */
+            rc = __libc_Back_safesemMtxUnlock(hmtx);
+            if (!rc)
+            {
+                /*
+                 * Now, lets wait.
+                 */
+                DosWaitEventSem(hev, SEM_INDEFINITE_WAIT);
+
+                /*
+                 * Regain access to the semaphore and must complete section
+                 * before checking if we got an interrupt or not.
+                 */
+                rc = __libc_Back_safesemMtxLock(hmtx);
+                if (!Args.fDone)
+		    pfnComplete(pvUser);
+                else if (!rc)
+                    rc = -EINTR;
+            }
+        }
+        else
+            rc = -__libc_native2errno(rc);
+        FS_RESTORE();
+    }
+    else
+        rc = -ENOSYS;
+
+    LIBCLOG_RETURN_INT(rc);
+}
+
+
+/**
+ * Wakes up all threads sleeping on a given event semaphore.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hev         Event semaphore to post.
+ */
+int __libc_Back_safesemEvWakeup(uintptr_t hev)
+{
+    LIBCLOG_ENTER("hev=%#x\n", hev);
+    FS_VAR_SAVE_LOAD();
+    int rc = DosPostEventSem(hev);
+    FS_RESTORE();
+    if (rc)
+    {
+        if (rc == ERROR_ALREADY_POSTED || rc == ERROR_TOO_MANY_POSTS)
+            rc = 0;
+        else
+            rc = -__libc_native2errno(rc);
+    }
+    LIBCLOG_RETURN_INT(rc);
+}
+
Index: trunk/src/emx/src/lib/sys/sysv_sem.c
===================================================================
--- trunk/src/emx/src/lib/sys/sysv_sem.c	(revision 1985)
+++ trunk/src/emx/src/lib/sys/sysv_sem.c	(revision 1986)
@@ -8,6 +8,6 @@
 
 #include "libc-alias.h"
+#include <sys/cdefs.h>
 //__FBSDID("$FreeBSD: src/sys/kern/sysv_sem.c,v 1.70.2.3 2005/03/22 17:20:07 sam Exp $");
-#include <sys/cdefs.h>
 
 #include <sys/types.h>
@@ -33,5 +33,5 @@
 #include <InnoTekLIBC/libc.h>
 #include <InnoTekLIBC/backend.h>
-#define __LIBC_LOG_GROUP    __LIBC_LOG_GRP_BACK_FS
+#define __LIBC_LOG_GROUP    __LIBC_LOG_GRP_BACK_IPC
 #include <InnoTekLIBC/logstrict.h>
 
@@ -51,7 +51,7 @@
     struct semid_ds u;
     /** Event semaphore to wait on. */
-    HEV             hev;
-    /** Mutex protecting the semid_ds and HEV members. */
-    HMTX            hmtx;
+    uintptr_t       hev;
+    /** Mutex protecting the semid_ds and hev members. */
+    uintptr_t       hmtx;
 };
 
@@ -74,5 +74,5 @@
     struct sem         *sem;
     /** Mutex protecting the undo list and other global sem stuff. */
-    HMTX                hmtx;
+    uintptr_t           hmtx;
     /** list of active undo structures. */
     SLIST_HEAD(, sem_undo) semu_list;
@@ -96,6 +96,6 @@
 
 //#define SEMUNDO_MTX		gpGlobals->hmtx
-#define SEMUNDO_LOCK()		semMtxLock(gpGlobals->hmtx);
-#define SEMUNDO_UNLOCK()	semMtxUnlock(gpGlobals->hmtx);
+#define SEMUNDO_LOCK()		__libc_Back_safesemMtxLock(gpGlobals->hmtx);
+#define SEMUNDO_UNLOCK()	__libc_Back_safesemMtxUnlock(gpGlobals->hmtx);
 #define SEMUNDO_LOCKASSERT(how)	do {} while (0) //mtx_assert(gpGlobals->hmtx, (how));
 
@@ -238,10 +238,4 @@
 #define TUNABLE_INT_FETCH(path, var) _getenv_int("LIBC_" path, (var))
 
-//static int  spmRequestMutexErrno(__LIBC_PSPMXCPTREGREC pRegRec);
-//static int  spmRequestMutex(__LIBC_PSPMXCPTREGREC pRegRec);
-//static int  spmReleaseMutex(__LIBC_PSPMXCPTREGREC pRegRec);
-
-//int __libc_spmLock(__LIBC_PSPMXCPTREGREC pRegRec);
-
 
 static int seminit(void)
@@ -290,10 +284,10 @@
          */
         size_t cb = sizeof(*gpGlobals);
-        cb += sizeof(struct semid_kernel) * seminfo.semmni;
+        cb += sizeof(struct semid_kernel) * si.semmni;
         cb += sizeof(struct sem) * si.semmns;
-        cb += seminfo.semmnu * seminfo.semusz;
+        cb += si.semmnu * si.semusz;
 
         /*
-         * Take the sem and allocate the memory.
+         * Retake the sem and allocate the memory.
          */
         rc = __libc_spmLock(&RegRec, &pSPMHdr);
@@ -321,5 +315,5 @@
             SLIST_INIT(&pGlobals->semu_list);
             pGlobals->semu       = (int *)pu8;
-            pGlobals->seminfo  = si;
+            pGlobals->seminfo    = si;
 
             /* Set globals. */
@@ -333,26 +327,23 @@
      */
     int i;
-    FS_VAR_SAVE_LOAD();
     if (!pGlobals->cUsers)
     {
         /* create */
-
-        rc = DosCreateMutexSemEx(NULL, &pGlobals->hmtx, DC_SEM_SHARED, FALSE);
+        rc = __libc_Back_safesemMtxCreate(&pGlobals->hmtx, 1);
         for (i = 0; i < pGlobals->seminfo.semmni && !rc; i++)
-            rc = DosCreateMutexSemEx(NULL, &pGlobals->sema[i].hmtx, DC_SEM_SHARED, FALSE);
+            rc = __libc_Back_safesemMtxCreate(&pGlobals->sema[i].hmtx, 1);
         for (i = 0; i < pGlobals->seminfo.semmni && !rc; i++)
-            rc = DosCreateEventSemEx(NULL, &pGlobals->sema[i].hev, DC_SEM_SHARED, FALSE);
+            rc = __libc_Back_safesemEvCreate(&pGlobals->sema[i].hev, 1);
     }
     else
     {
         /* open */
-        rc = DosOpenMutexSemEx(NULL, &pGlobals->hmtx);
+        rc = __libc_Back_safesemMtxOpen(pGlobals->hmtx);
         for (i = 0; i < pGlobals->seminfo.semmni && !rc; i++)
-            rc = DosOpenMutexSemEx(NULL, &pGlobals->sema[i].hmtx);
+            rc = __libc_Back_safesemMtxOpen(pGlobals->sema[i].hmtx);
         for (i = 0; i < pGlobals->seminfo.semmni && !rc; i++)
-            rc = DosOpenEventSemEx(NULL, &pGlobals->sema[i].hev);
+            rc = __libc_Back_safesemEvOpen(pGlobals->sema[i].hev);
     }
     __atomic_increment_u32(&pGlobals->cUsers);
-    FS_RESTORE();
 
     /*
@@ -369,223 +360,4 @@
     if (rc)
         rc = -__libc_native2errno(rc);
-    LIBCLOG_RETURN_INT(rc);
-}
-
-
-/**
- * This function checks that there is at least 2k of writable
- * stack available. If there isn't, a crash is usually the
- * result.
- * @internal
- */
-static int semMtxLockStackChecker(void)
-{
-    char volatile *pch = alloca(2048);
-    if (!pch)
-        return -1;
-    /* With any luck the compiler doesn't optimize this away. */
-    pch[0] = pch[1024] = pch[2044] = 0x7f;
-    return 0;
-}
-
-
-/**
- * Locks a mutex semaphore.
- *
- * @returns 0 on success.
- * @returns Negative errno on failure.
- * @param   hmtx    Handle to the mutex.
- */
-static int semMtxLock(HMTX hmtx)
-{
-    LIBCLOG_ENTER("hmtx=%#lx\n", hmtx);
-    ULONG       ul;
-    int         rc;
-    FS_VAR();
-
-    /*
-     * Check stack.
-     */
-    if (semMtxLockStackChecker())
-    {
-        LIBC_ASSERTM_FAILED("Too little stack left!\n");
-        LIBCLOG_RETURN_INT(-EFAULT);
-    }
-
-    /*
-     * Request semaphore and enter "must complete section" to avoid signal trouble.
-     */
-    FS_SAVE_LOAD();
-    rc = DosRequestMutexSem(hmtx, 30*1000);
-    DosEnterMustComplete(&ul);
-    if (!rc)
-    {
-        FS_RESTORE();
-        LIBCLOG_RETURN_INT(0);
-    }
-
-    /* failure out */
-    DosExitMustComplete(&ul);
-    LIBC_ASSERTM_FAILED("DosRequestMutexSem(%lu) failed with rc=%d!\n", hmtx, rc);
-    rc = -__libc_native2errno(rc);
-    FS_RESTORE();
-    LIBCLOG_RETURN_INT(rc);
-}
-
-
-/**
- * Unlocks a mutex semaphore.
- *
- * @returns 0 on success.
- * @returns Negative errno on failure.
- * @param   hmtx    Handle to the mutex.
- */
-static int semMtxUnlock(HMTX hmtx)
-{
-    LIBCLOG_ENTER("hmtx=%#lx\n", hmtx);
-    ULONG   ul = 0;
-    int     rc;
-    FS_VAR();
-
-    /*
-     * Release the semaphore.
-     */
-    FS_SAVE_LOAD();
-    rc = DosReleaseMutexSem(hmtx);
-    if (rc)
-    {
-        FS_RESTORE();
-        LIBC_ASSERTM_FAILED("DosReleaseMutexSem(%lu) -> %d\n", hmtx, rc);
-        rc = -__libc_native2errno(rc);
-        LIBCLOG_RETURN_INT(rc);
-    }
-
-    DosExitMustComplete(&ul);
-    FS_RESTORE();
-    LIBCLOG_RETURN_INT(0);
-}
-
-
-/**
- * Arguments to semEvSleepSignalCallback().
- */
-struct semEvSleepSignalCallback_args
-{
-    /** Set if pfnComplete have already been executed. */
-    volatile int            fDone;
-    /** Callback to execute. */
-    void                  (*pfnComplete)(int semid, struct semid_kernel *semaptr, uint16_t volatile *pu16);
-    /** Semaphore id. */
-    int	                    semid;
-    /** Semaphore id we was sleeping on. */
-    struct semid_kernel    *semaptr;
-    /** Pointer to the value to decrement. */
-    uint16_t volatile      *pu16;
-};
-
-/**
- * Signal notification callback.
- */
-static void semEvSleepSignalCallback(int iSignal, void *pvUser)
-{
-    struct semEvSleepSignalCallback_args *pArgs = (struct semEvSleepSignalCallback_args *)pvUser;
-    if (!pArgs->fDone)
-    {
-        pArgs->pfnComplete(pArgs->semid, pArgs->semaptr, pArgs->pu16);
-        pArgs->fDone = 1;
-    }
-}
-
-/**
- * Sleep on a semaphore.
- *
- * This is the most difficult thing we're doing in this file.
- *
- * @returns 0 on success.
- * @returns Negative error code (errno.h) on failure.
- * @param   semaptr     Semaphore to wakeup.
- * @param   pfnComplete Function to execute on signal and on wait completion.
- */
-static int semEvSleep(struct semid_kernel *semaptr, void (*pfnComplete)(int semid, struct semid_kernel *semaptr, uint16_t volatile *pu16), int semid, uint16_t volatile *pu16)
-{
-    LIBCLOG_ENTER("semaptr=%p pfnComplete=%p semid=%#x pu16=%p:{%d}\n", (void *)semaptr, (void *)pfnComplete, semid, (void *)pu16, *pu16);
-
-    /*
-     * Setup signal notification.
-     */
-    __LIBC_PTHREAD pThrd = __libc_threadCurrentNoAuto();
-    int rc;
-    if (pThrd)
-    {
-        struct semEvSleepSignalCallback_args Args;
-        Args.fDone               = 0;
-        Args.pfnComplete         = pfnComplete;
-        Args.semid               = semid;
-        Args.semaptr             = semaptr;
-        Args.pu16                = pu16;
-        pThrd->pvSigCallbackUser = &Args;
-        pThrd->pfnSigCallback    = semEvSleepSignalCallback;
-
-        /*
-         * Reset the event semaphore.
-         */
-        ULONG ulIgnore;
-        FS_VAR_SAVE_LOAD();
-        rc = DosResetEventSem(semaptr->hev, &ulIgnore);
-        if (!rc || rc == ERROR_ALREADY_RESET)
-        {
-            /*
-             * Release the sempahore and exit the must complete section.
-             */
-            rc = semMtxUnlock(semaptr->hev);
-            if (!rc)
-            {
-                /*
-                 * Now, lets wait.
-                 */
-                DosWaitEventSem(semaptr->hev, SEM_INDEFINITE_WAIT);
-
-                /*
-                 * Regain access to the semaphore and must complete section
-                 * before checking if we got an interrupt or not.
-                 */
-                rc = semMtxLock(semaptr->hmtx);
-                if (!Args.fDone)
-		    Args.pfnComplete(Args.semid, Args.semaptr, Args.pu16);
-                else if (!rc)
-                    rc = -EINTR;
-            }
-        }
-        else
-            rc = -__libc_native2errno(rc);
-        FS_RESTORE();
-    }
-    else
-        rc = -ENOSYS;
-
-    LIBCLOG_RETURN_INT(rc);
-}
-
-
-/**
- * Wakes up all threads sleeping on a given event semaphore.
- *
- * @returns 0 on success.
- * @returns Negative error code (errno.h) on failure.
- * @param   semaptr     Semaphore to wakeup.
- */
-static int semEvWakeup(struct semid_kernel *semaptr)
-{
-    LIBCLOG_ENTER("semaptr=%p\n", (void *)semaptr);
-    FS_VAR_SAVE_LOAD();
-    int rc = DosPostEventSem(semaptr->hev);
-    FS_RESTORE();
-    if (rc)
-    {
-        if (rc == ERROR_ALREADY_POSTED || rc == ERROR_TOO_MANY_POSTS)
-            rc = 0;
-        else
-            rc = -__libc_native2errno(rc);
-    }
     LIBCLOG_RETURN_INT(rc);
 }
@@ -789,5 +561,5 @@
 	u_short usval, count;
         uid_t uid;
-        HMTX hmtx;
+        uintptr_t hmtx;
 
 
@@ -814,12 +586,12 @@
 			LIBCLOG_RETURN_INT(-EINVAL);
 		semaptr = &sema[semid];
-                semMtxLock(hmtx = semaptr->hmtx);
+                __libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((semaptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
 			error = EINVAL;
 			goto done2;
 		}
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
-			goto done2;
-                semMtxUnlock(hmtx); hmtx = NULLHANDLE;
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
+			goto done2;
+                __libc_Back_safesemMtxUnlock(hmtx); hmtx = NULLHANDLE;
 		memcpy(real_arg.buf, &semaptr->u, sizeof(struct semid_ds));
 		rval = IXSEQ_TO_IPCID(semid, semaptr->u.sem_perm);
@@ -835,8 +607,8 @@
 	switch (cmd) {
 	case IPC_RMID:
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_M)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_M)))
 			goto done2;
                 uid = __libc_spmGetId(__LIBC_SPMID_EUID);
@@ -855,5 +627,5 @@
 		semundo_clear(semid, -1);
 		SEMUNDO_UNLOCK();
-		semEvWakeup(semaptr);
+		__libc_Back_safesemEvWakeup(semaptr->hev);
 		break;
 
@@ -861,8 +633,8 @@
 		if ((error = copyin(real_arg.buf, &sbuf, sizeof(sbuf))) != 0)
 			goto done2;
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_M)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_M)))
 			goto done2;
 		semaptr->u.sem_perm.uid = sbuf.sem_perm.uid;
@@ -874,11 +646,11 @@
 
 	case IPC_STAT:
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
 			goto done2;
 		sbuf = semaptr->u;
-		semMtxUnlock(hmtx); hmtx = NULLHANDLE;
+		__libc_Back_safesemMtxUnlock(hmtx); hmtx = NULLHANDLE;
 		error = copyout(semaptr, real_arg.buf,
 				sizeof(struct semid_ds));
@@ -886,8 +658,8 @@
 
 	case GETNCNT:
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
 			goto done2;
 		if (semnum < 0 || semnum >= semaptr->u.sem_nsems) {
@@ -899,8 +671,8 @@
 
 	case GETPID:
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
 			goto done2;
 		if (semnum < 0 || semnum >= semaptr->u.sem_nsems) {
@@ -912,8 +684,8 @@
 
 	case GETVAL:
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
 			goto done2;
 		if (semnum < 0 || semnum >= semaptr->u.sem_nsems) {
@@ -926,12 +698,12 @@
 	case GETALL:
 		array = _hmalloc(sizeof(*array) * semaptr->u.sem_nsems);
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
 			goto done2;
 		for (i = 0; i < semaptr->u.sem_nsems; i++)
 			array[i] = semaptr->u.sem_base[i].semval;
-		semMtxUnlock(hmtx); hmtx = NULLHANDLE;
+		__libc_Back_safesemMtxUnlock(hmtx); hmtx = NULLHANDLE;
 		error = copyout(array, real_arg.array,
 		    i * sizeof(real_arg.array[0]));
@@ -939,8 +711,8 @@
 
 	case GETZCNT:
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_R)))
 			goto done2;
 		if (semnum < 0 || semnum >= semaptr->u.sem_nsems) {
@@ -952,8 +724,8 @@
 
 	case SETVAL:
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_W)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_W)))
 			goto done2;
 		if (semnum < 0 || semnum >= semaptr->u.sem_nsems) {
@@ -969,19 +741,19 @@
 		semundo_clear(semid, semnum);
 		SEMUNDO_UNLOCK();
-		semEvWakeup(semaptr);
+		__libc_Back_safesemEvWakeup(semaptr->hev);
 		break;
 
 	case SETALL:
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 raced:
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
 		count = semaptr->u.sem_nsems;
-		semMtxUnlock(hmtx); hmtx = NULLHANDLE;
+		__libc_Back_safesemMtxUnlock(hmtx); hmtx = NULLHANDLE;
 		array = _hmalloc(sizeof(*array) * count);
 		error = copyin(real_arg.array, array, count * sizeof(*array));
 		if (error)
 			break;
-		semMtxLock(hmtx = semaptr->hmtx);
+		__libc_Back_safesemMtxLock(hmtx = semaptr->hmtx);
 		if ((error = semvalid(semid, semaptr)) != 0)
 			goto done2;
@@ -992,5 +764,5 @@
 			goto raced;
 		}
-		if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, IPC_W)))
+		if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, IPC_W)))
 			goto done2;
 		for (i = 0; i < semaptr->u.sem_nsems; i++) {
@@ -1005,5 +777,5 @@
 		semundo_clear(semid, -1);
 		SEMUNDO_UNLOCK();
-		semEvWakeup(semaptr);
+		__libc_Back_safesemEvWakeup(semaptr->hev);
 		break;
 
@@ -1015,5 +787,5 @@
 done2:
 	if (hmtx)
-		semMtxUnlock(hmtx);
+		__libc_Back_safesemMtxUnlock(hmtx);
 
 	if (array != NULL)
@@ -1046,5 +818,5 @@
 	struct semid_kernel * sema = gpGlobals->sema;
 
-	error = semMtxLock(gpGlobals->hmtx);
+	error = __libc_Back_safesemMtxLock(gpGlobals->hmtx);
         if (error)
             LIBCLOG_RETURN_INT(error);
@@ -1058,5 +830,5 @@
 		if (semid < seminfo.semmni) {
 			DPRINTF(("found public key\n"));
-			if ((error = __libc_spmCanIPC(&sema[semid].u.sem_perm,
+			if ((error = -__libc_spmCanIPC(&sema[semid].u.sem_perm,
 			    semflg & 0700))) {
 				goto done2;
@@ -1124,16 +896,30 @@
         errno = -IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm);
 done2:
-	semMtxUnlock(gpGlobals->hmtx);
+	__libc_Back_safesemMtxUnlock(gpGlobals->hmtx);
 	LIBCLOG_RETURN_INT(-error);
 }
 
-
-static void __libc_Back_sysvSemSleepDone(int semid, struct semid_kernel *semaptr, uint16_t volatile *pu16)
+/**
+ * Args to __libc_Back_sysvSemSleepDone.
+ */
+struct SleepDoneArgs
 {
+    int semid;
+    struct semid_kernel *semaptr;
+    uint16_t volatile *pu16;
+};
+
+/**
+ * Wakeup function, called before signals are delivered.
+ */
+static void SleepDone(void *pvUser)
+{
+    struct SleepDoneArgs *pArgs = (struct SleepDoneArgs *)pvUser;
+
     /*
      * Make sure that the semaphore still exists
      */
-    if ((semaptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
-	semaptr->u.sem_perm.seq != IPCID_TO_SEQ(semid)) {
+    if ((pArgs->semaptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
+	pArgs->semaptr->u.sem_perm.seq != IPCID_TO_SEQ(pArgs->semid)) {
 	    return;
     }
@@ -1143,5 +929,5 @@
      * waiting processes.
      */
-    __atomic_decrement_u16(pu16);
+    __atomic_decrement_u16(pArgs->pu16);
 }
 
@@ -1199,5 +985,5 @@
 
 	semaptr = &sema[semid];
-	error = semMtxLock(semaptr->hmtx);
+	error = __libc_Back_safesemMtxLock(semaptr->hmtx);
         if (error) {
                 if (sops != small_sops)
@@ -1232,5 +1018,5 @@
 	}
 
-	if ((error = __libc_spmCanIPC(&semaptr->u.sem_perm, j))) {
+	if ((error = -__libc_spmCanIPC(&semaptr->u.sem_perm, j))) {
 		DPRINTF(("error = %d from ipaccess\n", error));
 		goto done2;
@@ -1315,8 +1101,11 @@
 		}
 
-		uint16_t volatile *pu16 = sopptr->sem_op == 0 ? &semptr->semzcnt : &semptr->semncnt;
-		__atomic_increment_u16(pu16);
+                struct SleepDoneArgs Args;
+                Args.semaptr = semaptr;
+                Args.semid = semid;
+                Args.pu16 = sopptr->sem_op == 0 ? &semptr->semzcnt : &semptr->semncnt;
+		__atomic_increment_u16(Args.pu16);
 		DPRINTF(("semop:  good night (%d)!\n", sopptr->sem_op));
-		error = -semEvSleep(semaptr, __libc_Back_sysvSemSleepDone, semid, pu16);
+		error = -__libc_Back_safesemEvSleep(semaptr->hev, semaptr->hmtx, SleepDone, &Args);
 		DPRINTF(("semop:  good morning (error=%d)!\n", error));
 		/* return code is checked below, after sem[nz]cnt-- */
@@ -1413,10 +1202,10 @@
 	if (do_wakeup) {
 		DPRINTF(("semop:  doing wakeup\n"));
-		semEvWakeup(semaptr);
+		__libc_Back_safesemEvWakeup(semaptr->hev);
 		DPRINTF(("semop:  back from wakeup\n"));
 	}
 	DPRINTF(("semop:  done\n"));
 done2:
-	semMtxUnlock(semaptr->hmtx);
+	__libc_Back_safesemMtxUnlock(semaptr->hmtx);
 	if (sops != small_sops)
 		free(sops);
@@ -1473,5 +1262,5 @@
 			semaptr = &gpGlobals->sema[semid];
 			SEMUNDO_LOCK();
-			semMtxUnlock(semaptr->hmtx);
+			__libc_Back_safesemMtxUnlock(semaptr->hmtx);
 			if ((semaptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
 				panic("semexit - semid not allocated");
@@ -1499,8 +1288,8 @@
 				semaptr->u.sem_base[semnum].semval += adjval;
 
-			semEvWakeup(semaptr);
+			__libc_Back_safesemEvWakeup(semaptr->hev);
 			DPRINTF(("semexit:  back from wakeup\n"));
 		    skip:
-			semMtxUnlock(semaptr->hmtx);
+			__libc_Back_safesemMtxUnlock(semaptr->hmtx);
 			SEMUNDO_UNLOCK();
 		}
Index: trunk/src/emx/src/lib/sys/sysv_shm.c
===================================================================
--- trunk/src/emx/src/lib/sys/sysv_shm.c	(revision 1986)
+++ trunk/src/emx/src/lib/sys/sysv_shm.c	(revision 1986)
@@ -0,0 +1,965 @@
+/*	$NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $	*/
+/*-
+ * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Adam Glass and Charles
+ *	Hannum.
+ * 4. The names of the authors may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "libc-alias.h"
+#include <sys/cdefs.h>
+//__FBSDID("$FreeBSD: src/sys/kern/sysv_shm.c,v 1.96.2.3 2005/02/19 19:54:31 csjp Exp $");
+
+#include <sys/types.h>
+#define _KERNEL
+#include <sys/shm.h>
+#undef _KERNEL
+#include <sys/mman.h>
+#include <sys/stat.h>
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSEXCEPTIONS
+#define INCL_DOSMEMMGR
+#define INCL_DOSERRORS
+#define INCL_FSMACROS
+#define INCL_EXAPIS
+#include <os2emx.h>
+#include "syscalls.h"
+#include <string.h>
+#include <errno.h>
+#include <emx/umalloc.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <386/builtin.h>
+#include <InnoTekLIBC/sharedpm.h>
+#include <InnoTekLIBC/thread.h>
+#include <InnoTekLIBC/FastInfoBlocks.h>
+#include <InnoTekLIBC/libc.h>
+#include <InnoTekLIBC/fork.h>
+#include <InnoTekLIBC/backend.h>
+#define __LIBC_LOG_GROUP    __LIBC_LOG_GRP_BACK_FS
+#include <InnoTekLIBC/logstrict.h>
+
+/* debug printf */
+#define DPRINTF(a)	LIBCLOG_MSG a
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/**
+ * SysV Shared Memory globals residing in the shared process manager heap.
+ */
+struct __libc_SysV_Shm
+{
+    /** Structure version. */
+    unsigned            uVersion;
+    /** Number of users.
+     * This is primarily used for knowing when to re-create the semaphores.
+     */
+    volatile uint32_t	cUsers;
+    /** Mutex protecting everything. */
+    uintptr_t           hmtx;
+    /** Event semaphore which the daemon should sleep on.
+     * This is posted whenever a memory object is created or deleted. */
+    uintptr_t           hevDaemon;
+
+    int                 shm_last_free;
+    int                 shm_nused;
+    int                 shm_committed;
+    int                 shmalloced;
+    /** Pointer to array of shared memory ids. */
+    struct shmid_ds    *shmsegs;
+
+    /** SysV Semaphore info. (Contains all the array sizes and such.)
+     * Not changed after initialization. */
+    struct shminfo      shminfo;
+};
+
+/** Pointer to the globals. */
+static struct __libc_SysV_Shm *gpGlobals;
+
+//static int shm_last_free, shm_nused, shm_committed, shmalloced;
+//static struct shmid_ds	*shmsegs;
+
+struct shmmap_state {
+	vm_offset_t va;
+	int shmid;
+};
+
+/** Array of shared memory ids attached to this process.
+ * On BSD this is the vm_shm of the process vm. */
+static struct shmmap_state *g_vm_shm;
+
+
+static int shmget_allocate_segment(key_t key, size_t size, mode_t mode);
+static int shmget_existing(size_t size, mode_t mode, int segnum, int shmflg);
+
+#define	SHMSEG_FREE     	0x0200
+#define	SHMSEG_REMOVED  	0x0400
+#define	SHMSEG_ALLOCATED	0x0800
+//#define	SHMSEG_WANTED		0x1000 - cannot happen with our locking policy.
+
+static void shm_deallocate_segment(struct shmid_ds *);
+static int shm_find_segment_by_key(key_t);
+static struct shmid_ds *shm_find_segment_by_shmid(int);
+static struct shmid_ds *shm_find_segment_by_shmidx(int);
+static int shm_delete_mapping(struct shmmap_state *);
+static int shminit(void);
+static void shmexit_myhook(void);
+static int shmfork_myhook(__LIBC_PFORKHANDLE pForkHandle, __LIBC_FORKOP enmOperation);
+//static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS);
+
+/*
+ * Tuneable values.
+ */
+#ifndef SHMMAXPGS
+#define	SHMMAXPGS	8192	/* Note: sysv shared memory is swap backed. */
+#endif
+#ifndef SHMMAX
+#define	SHMMAX	(SHMMAXPGS*PAGE_SIZE)
+#endif
+#ifndef SHMMIN
+#define	SHMMIN	1
+#endif
+#ifndef SHMMNI
+#define	SHMMNI	192
+#endif
+#ifndef SHMSEG
+#define	SHMSEG	128
+#endif
+#ifndef SHMALL
+#define	SHMALL	(SHMMAXPGS)
+#endif
+
+static struct	shminfo shminfo = {
+	SHMMAX,                 /* max shared memory segment size (bytes) */
+	SHMMIN,                 /* min shared memory segment size (bytes) */
+	SHMMNI,                 /* max number of shared memory identifiers */
+	SHMSEG,                 /* max shared memory segments per process */
+	SHMALL                  /* max amount of shared memory (pages) */
+};
+
+//static int shm_use_phys;
+#define shm_use_phys 0
+//static int shm_allow_removed;
+#define shm_allow_removed 0
+
+#if 0
+SYSCTL_DECL(_kern_ipc);
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0,
+    "Maximum shared memory segment size");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0,
+    "Minimum shared memory segment size");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0,
+    "Number of shared memory identifiers");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0,
+    "Number of segments per process");
+SYSCTL_INT(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0,
+    "Maximum number of pages available for shared memory");
+//SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW,
+//    &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core");
+//SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW,
+//    &shm_allow_removed, 0,
+//    "Enable/Disable attachment to attached segments marked for removal");
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLFLAG_RD,
+    NULL, 0, sysctl_shmsegs, "",
+    "Current number of shared memory segments allocated");
+#endif
+
+/* wrappers */
+/* wrappers */
+/* wrappers */
+/* wrappers */
+/* wrappers */
+
+#define panic LIBC_ASSERTM_FAILED
+#undef copyout
+#define copyout(x,y,z)  !memcpy((y),(x),(z))
+#undef copyin
+#define copyin(x,y,z)   !memcpy((y),(x),(z))
+#define TUNABLE_INT_FETCH(path, var) _getenv_int("LIBC_" path, (var))
+#define GIANT_REQUIRED do {} while (0)
+
+/** @todo add these to param.h */
+/* clicks to bytes */
+#ifndef ctob
+#define ctob(x)	((x)<<PAGE_SHIFT)
+#endif
+
+/* bytes to clicks */
+#ifndef btoc
+#define btoc(x)	(((vm_offset_t)(x)+PAGE_MASK)>>PAGE_SHIFT)
+#endif
+
+
+
+static int
+shm_find_segment_by_key(key)
+	key_t key;
+{
+	int i;
+	const unsigned shmalloced = gpGlobals->shmalloced;
+        struct shmid_ds *shmsegs = gpGlobals->shmsegs;
+
+	for (i = 0; i < shmalloced; i++)
+		if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) &&
+		    shmsegs[i].shm_perm.key == key)
+			return (i);
+	return (-1);
+}
+
+static struct shmid_ds *
+shm_find_segment_by_shmid(int shmid)
+{
+	int segnum;
+	struct shmid_ds *shmseg;
+	const unsigned shmalloced = gpGlobals->shmalloced;
+        struct shmid_ds *shmsegs = gpGlobals->shmsegs;
+
+	segnum = IPCID_TO_IX(shmid);
+	if (segnum < 0 || segnum >= shmalloced)
+		return (NULL);
+	shmseg = &shmsegs[segnum];
+	if ((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
+	    (!shm_allow_removed &&
+	     (shmseg->shm_perm.mode & SHMSEG_REMOVED) != 0) ||
+	    shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid))
+		return (NULL);
+	return (shmseg);
+}
+
+static struct shmid_ds *
+shm_find_segment_by_shmidx(int segnum)
+{
+	struct shmid_ds *shmseg;
+	const unsigned shmalloced = gpGlobals->shmalloced;
+        struct shmid_ds *shmsegs = gpGlobals->shmsegs;
+
+	if (segnum < 0 || segnum >= shmalloced)
+		return (NULL);
+	shmseg = &shmsegs[segnum];
+	if ((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
+	    (!shm_allow_removed &&
+	     (shmseg->shm_perm.mode & SHMSEG_REMOVED) != 0))
+		return (NULL);
+	return (shmseg);
+}
+
+static void
+shm_deallocate_segment(shmseg)
+	struct shmid_ds *shmseg;
+{
+	struct __libc_SysV_Shm *pGlobals = gpGlobals;
+	size_t size;
+
+	GIANT_REQUIRED;
+
+        shmseg->shm_internal = NULL;
+	size = round_page(shmseg->shm_segsz);
+	pGlobals->shm_committed -= btoc(size);
+	pGlobals->shm_nused--;
+	shmseg->shm_perm.mode = SHMSEG_FREE;
+	__libc_Back_safesemEvWakeup(pGlobals->hevDaemon);
+}
+
+static int
+shm_delete_mapping(struct shmmap_state *shmmap_s)
+{
+	struct __libc_SysV_Shm *pGlobals = gpGlobals;
+        struct shmid_ds *shmsegs = pGlobals->shmsegs;
+	struct shmid_ds *shmseg;
+	int segnum, result;
+
+	GIANT_REQUIRED;
+
+	segnum = IPCID_TO_IX(shmmap_s->shmid);
+	shmseg = &shmsegs[segnum];
+	FS_VAR_SAVE_LOAD();
+	result = DosFreeMem((void *)shmmap_s->va);
+	FS_RESTORE();
+	if (result)
+		return (EINVAL);
+	shmmap_s->shmid = -1;
+	shmseg->shm_dtime = fibGetUnixSeconds();
+	if ((--shmseg->shm_nattch <= 0) &&
+	    (shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
+		shm_deallocate_segment(shmseg);
+		pGlobals->shm_last_free = segnum;
+	}
+        __libc_Back_safesemEvWakeup(pGlobals->hevDaemon);
+	return (0);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct shmdt_args {
+	const void *shmaddr;
+};
+#endif
+
+/**
+ * shmdt.
+ */
+int __libc_Back_sysvShmDt(const void *shmaddr)
+{
+	LIBCLOG_ENTER("shmaddr=%p\n", shmaddr);
+	struct shmmap_state *shmmap_s;
+	int i;
+	int error = 0;
+
+	/*
+	 * Lazy init.
+	 */
+	if (!gpGlobals)
+	{
+	    error = shminit();
+	    if (error)
+		LIBCLOG_RETURN_INT(error);
+	}
+	
+	error = __libc_Back_safesemMtxLock(gpGlobals->hmtx);
+	if (error)
+	    LIBCLOG_RETURN_INT(error);
+
+	shmmap_s = g_vm_shm;
+ 	if (shmmap_s == NULL) {
+		error = EINVAL;
+		goto done2;
+	}
+	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
+		if (shmmap_s->shmid != -1 &&
+		    shmmap_s->va == (vm_offset_t)shmaddr) {
+			break;
+		}
+	}
+	if (i == shminfo.shmseg) {
+		error = EINVAL;
+		goto done2;
+	}
+	error = shm_delete_mapping(shmmap_s);
+done2:
+	__libc_Back_safesemMtxUnlock(gpGlobals->hmtx);
+	return (-error);
+}
+
+
+/**
+ * shmat.
+ */
+int __libc_Back_sysvShmAt(int shmid, const void *shmaddr, int shmflg, void **ppvActual)
+{
+    	LIBCLOG_ENTER("shmid=%#x shmaddr=%p shmflg=%#x ppvActual=%p\n", shmid, shmaddr, shmflg, (void *)ppvActual);
+	int i;
+	struct shmid_ds *shmseg;
+	struct shmmap_state *shmmap_s = NULL;
+	vm_offset_t attach_va = 0;
+	vm_size_t size;
+	int error = 0;
+
+	/*
+	 * Lazy init.
+	 */
+	if (!gpGlobals)
+	{
+	    error = shminit();
+	    if (error)
+		LIBCLOG_RETURN_INT(error);
+	}
+	struct __libc_SysV_Shm *pGlobals = gpGlobals;
+	
+	error = __libc_Back_safesemMtxLock(pGlobals->hmtx);
+	if (error)
+	    LIBCLOG_RETURN_INT(error);
+
+	/*
+	 * Make sure we've got a g_vm_shm.
+	 */
+	shmmap_s = g_vm_shm;
+	if (shmmap_s == NULL) {
+		__libc_Back_safesemMtxUnlock(pGlobals->hmtx);
+		size = shminfo.shmseg * sizeof(struct shmmap_state);
+		shmmap_s = _hmalloc(size);
+		if (!shmmap_s)
+		    LIBCLOG_RETURN_INT(-ENOMEM);
+		for (i = 0; i < shminfo.shmseg; i++)
+			shmmap_s[i].shmid = -1;
+		__libc_Back_safesemMtxLock(pGlobals->hmtx);
+		if (!g_vm_shm)
+		    g_vm_shm = shmmap_s;
+		else
+		{
+		    free(shmmap_s);
+                    g_vm_shm = NULL;
+		}
+	}
+        shmseg = shm_find_segment_by_shmid(shmid);
+	if (shmseg == NULL) {
+		error = EINVAL;
+		goto done2;
+	}
+	error = -__libc_spmCanIPC(&shmseg->shm_perm,
+	    (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
+	if (error)
+		goto done2;
+	
+	/* Find free usage struct. */
+	for (i = 0; i < shminfo.shmseg; i++) {
+		if (shmmap_s->shmid == -1)
+			break;
+		shmmap_s++;
+	}
+	if (i >= shminfo.shmseg) {
+		error = EMFILE;
+		goto done2;
+	}
+
+	/*
+	 * Do the attaching.
+	 */
+	size = round_page(shmseg->shm_segsz);
+	ULONG flFlags = PAG_READ | PAG_EXECUTE;
+	if ((shmflg & SHM_RDONLY) == 0)
+		flFlags |= PAG_WRITE;
+	if (shmaddr) {
+                if (shmflg & SHM_RND) {
+			attach_va = (vm_offset_t)shmaddr & ~(SHMLBA-1);
+		} else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) {
+			attach_va = (vm_offset_t)shmaddr;
+		} else {
+			error = EINVAL;
+			goto done2;
+		}
+		if ((void *)attach_va != shmseg->shm_internal) {
+			error = EOPNOTSUPP;
+			goto done2;
+		}
+	} else {
+            attach_va = (vm_offset_t)shmseg->shm_internal;
+	}
+
+	FS_VAR_SAVE_LOAD();
+	error = DosGetSharedMem((PVOID)attach_va, flFlags);
+	FS_RESTORE();
+	if (error) {
+		error = __libc_native2errno(error);
+		goto done2;
+	}
+
+	shmmap_s->va = attach_va;
+	shmmap_s->shmid = shmid;
+	shmseg->shm_lpid = fibGetPid();
+	shmseg->shm_atime = fibGetUnixSeconds();
+	shmseg->shm_nattch++;
+	
+done2:
+	__libc_Back_safesemMtxUnlock(pGlobals->hmtx);
+        *ppvActual = (void *)attach_va;
+	LIBCLOG_RETURN_INT(-error);
+}
+
+
+
+#ifndef _SYS_SYSPROTO_H_
+struct shmctl_args {
+	int shmid;
+	int cmd;
+	struct shmid_ds *buf;
+};
+#endif
+
+/*
+ * MPSAFE
+ */
+static int kern_shmctl(int shmid, int cmd, void *buf, size_t *bufsz)
+{
+	int error = 0;
+	int rval = 0;
+	struct shmid_ds *shmseg;
+
+	/*
+	 * Lazy init.
+	 */
+	if (!gpGlobals)
+	{
+	    error = shminit();
+	    if (error)
+		return (error);
+	}
+	struct __libc_SysV_Shm *pGlobals = gpGlobals;
+	
+	error = __libc_Back_safesemMtxLock(pGlobals->hmtx);
+	if (error)
+	    return error;
+        const int shmalloced = pGlobals->shmalloced;
+        const int shm_nused = pGlobals->shm_nused;
+
+	/*
+	 * Execute the command.
+	 */
+	switch (cmd) {
+	case IPC_INFO:
+		memcpy(buf, &shminfo, sizeof(shminfo));
+		if (bufsz)
+			*bufsz = sizeof(shminfo);
+		rval = shmalloced;
+		goto done2;
+	case SHM_INFO: {
+		struct shm_info shm_info;
+		shm_info.used_ids = shm_nused;
+		shm_info.shm_rss = 0;	/*XXX where to get from ? */
+		shm_info.shm_tot = 0;	/*XXX where to get from ? */
+		shm_info.shm_swp = 0;	/*XXX where to get from ? */
+		shm_info.swap_attempts = 0;	/*XXX where to get from ? */
+		shm_info.swap_successes = 0;	/*XXX where to get from ? */
+		memcpy(buf, &shm_info, sizeof(shm_info));
+		if (bufsz)
+			*bufsz = sizeof(shm_info);
+		rval = shmalloced;
+		goto done2;
+	}
+	}
+	if (cmd == SHM_STAT)
+		shmseg = shm_find_segment_by_shmidx(shmid);
+	else
+		shmseg = shm_find_segment_by_shmid(shmid);
+	if (shmseg == NULL) {
+		error = EINVAL;
+		goto done2;
+	}
+	switch (cmd) {
+	case SHM_STAT:
+	case IPC_STAT:
+		error = -__libc_spmCanIPC(&shmseg->shm_perm, IPC_R);
+		if (error)
+			goto done2;
+		memcpy(buf, shmseg, sizeof(struct shmid_ds));
+		if (bufsz)
+			*bufsz = sizeof(struct shmid_ds);
+		if (cmd == SHM_STAT)
+			rval = IXSEQ_TO_IPCID(shmid, shmseg->shm_perm);
+		break;
+	case IPC_SET: {
+		struct shmid_ds *shmid;
+
+		shmid = (struct shmid_ds *)buf;
+		error = -__libc_spmCanIPC(&shmseg->shm_perm, IPC_M);
+		if (error)
+			goto done2;
+		shmseg->shm_perm.uid = shmid->shm_perm.uid;
+		shmseg->shm_perm.gid = shmid->shm_perm.gid;
+		shmseg->shm_perm.mode =
+		    (shmseg->shm_perm.mode & ~ACCESSPERMS) |
+		    (shmid->shm_perm.mode & ACCESSPERMS);
+		shmseg->shm_ctime = fibGetUnixSeconds();
+		break;
+	}
+	case IPC_RMID:
+		error = -__libc_spmCanIPC(&shmseg->shm_perm, IPC_M);
+		if (error)
+			goto done2;
+		shmseg->shm_perm.key = IPC_PRIVATE;
+		shmseg->shm_perm.mode |= SHMSEG_REMOVED;
+		if (shmseg->shm_nattch <= 0) {
+			shm_deallocate_segment(shmseg);
+			pGlobals->shm_last_free = IPCID_TO_IX(shmid);
+		}
+		break;
+#if 0
+	case SHM_LOCK:
+	case SHM_UNLOCK:
+#endif
+	default:
+		error = EINVAL;
+		break;
+	}
+done2:
+	__libc_Back_safesemMtxUnlock(pGlobals->hmtx);
+	if (error)
+	    rval = -error;
+	return (rval);
+}
+
+
+/**
+ * shmctl.
+ */
+int __libc_Back_sysvShmCtl(int shmid, int cmd, struct shmid_ds *bufptr)
+{
+    	LIBCLOG_ENTER("shmid=%#x cmd=%d bufptr=%p\n", shmid, cmd, (void *)bufptr);
+	int error = 0;
+	int rval = 0;
+	struct shmid_ds buf;
+	size_t bufsz;
+	
+	/* IPC_SET needs to copyin the buffer before calling kern_shmctl */
+	if (cmd == IPC_SET) {
+		if ((error = copyin(bufptr, &buf, sizeof(struct shmid_ds))))
+			goto done;
+	}
+	
+	rval = kern_shmctl(shmid, cmd, (void *)&buf, &bufsz);
+	if (rval < 0)
+		goto done;
+	
+	/* Cases in which we need to copyout */
+	switch (cmd) {
+	case IPC_INFO:
+	case SHM_INFO:
+	case SHM_STAT:
+	case IPC_STAT:
+		error = copyout(&buf, bufptr, bufsz);
+		break;
+	}
+
+done:
+	if (error)
+	    rval = -error;
+	LIBCLOG_RETURN_INT(rval);
+}
+
+
+
+static int
+shmget_existing(size_t size, mode_t mode, int segnum, int shmflg)
+{
+	struct shmid_ds *shmseg;
+	int error;
+
+	shmseg = &gpGlobals->shmsegs[segnum];
+	if (shmseg->shm_perm.mode & SHMSEG_REMOVED) {
+		return (-EAGAIN);
+	}
+	if ((shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
+		return (-EEXIST);
+	error = __libc_spmCanIPC(&shmseg->shm_perm, mode);
+	if (error)
+		return (error);
+	if (size && size > shmseg->shm_segsz)
+		return (-EINVAL);
+	return IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
+}
+
+static int
+shmget_allocate_segment(key_t key, size_t size_in, mode_t mode)
+{
+	int i, segnum, shmid, size;
+	struct shmid_ds *shmseg;
+	struct __libc_SysV_Shm *pGlobals = gpGlobals;
+        const int shmalloced = pGlobals->shmalloced;
+	struct shmid_ds *shmsegs = pGlobals->shmsegs;
+	void *shm_object;
+
+	GIANT_REQUIRED;
+
+	if (size_in < shminfo.shmmin || size_in > shminfo.shmmax)
+		return (-EINVAL);
+	if (pGlobals->shm_nused >= shminfo.shmmni) /* Any shmids left? */
+		return (-ENOSPC);
+	size = round_page(size_in);
+	if (pGlobals->shm_committed + btoc(size) > shminfo.shmall)
+		return (-ENOMEM);
+	if (pGlobals->shm_last_free < 0) {
+		for (i = 0; i < shmalloced; i++)
+			if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
+				break;
+		if (i == shmalloced)
+			return (-ENOSPC);
+		segnum = i;
+	} else  {
+		segnum = pGlobals->shm_last_free;
+		pGlobals->shm_last_free = -1;
+	}
+	shmseg = &shmsegs[segnum];
+
+	/*
+	 * Allocate shared memory object.
+	 * Unfortunately the creator will get it mapped in with full access.
+	 */
+	FS_VAR_SAVE_LOAD();
+	int error = DosAllocSharedMemEx(&shm_object, NULL, size, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_GETTABLE | OBJ_ANY);
+	if (error)
+	    error = DosAllocSharedMemEx(&shm_object, NULL, size, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_GETTABLE);
+	FS_RESTORE();
+	if (error)
+	    return -__libc_native2errno(error);
+
+	/*
+	 * Set up the segment.
+	 */
+	shmseg->shm_internal = shm_object;
+	shmseg->shm_perm.key = key;
+	shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
+	shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
+	shmseg->shm_perm.cuid = shmseg->shm_perm.uid = __libc_spmGetId(__LIBC_SPMID_EUID);
+	shmseg->shm_perm.cgid = shmseg->shm_perm.gid = __libc_spmGetId(__LIBC_SPMID_EGID);
+	shmseg->shm_perm.mode = (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
+	shmseg->shm_segsz = size;
+	shmseg->shm_cpid = fibGetPid();
+	shmseg->shm_lpid = shmseg->shm_nattch = 0;
+	shmseg->shm_atime = shmseg->shm_dtime = 0;
+	shmseg->shm_ctime = fibGetUnixSeconds();
+	pGlobals->shm_committed += btoc(size);
+	pGlobals->shm_nused++;
+	return shmid;
+}
+
+
+/**
+ * shmget.
+ */
+int __libc_Back_sysvShmGet(key_t key, size_t size, int shmflg)
+{
+    	LIBCLOG_ENTER("key=%#lx size=%#x shmflg=%#x\n", key, size, shmflg);
+	int segnum, mode;
+	int rval;
+
+	/*
+	 * Lazy init.
+	 */
+	if (!gpGlobals)
+	{
+	    rval = shminit();
+	    if (rval)
+		LIBCLOG_RETURN_INT(rval);
+	}
+	struct __libc_SysV_Shm *pGlobals = gpGlobals;
+	
+	rval = __libc_Back_safesemMtxLock(pGlobals->hmtx);
+	if (rval)
+	    LIBCLOG_RETURN_INT(rval);
+
+	/* mark that all subfunctions here return negative errno or return value. */
+	mode = shmflg & ACCESSPERMS;
+	if (key != IPC_PRIVATE) {
+	//again:
+		segnum = shm_find_segment_by_key(key);
+		if (segnum >= 0) {
+			rval = shmget_existing(size, mode, segnum, shmflg);
+			//I don't think this is right for us...
+			//if (rval == -EAGAIN)
+			//	goto again;
+			goto done2;
+		}
+		if ((shmflg & IPC_CREAT) == 0) {
+			rval = -ENOENT;
+			goto done2;
+		}
+	}
+	rval = shmget_allocate_segment(key, size, mode);
+done2:
+	__libc_Back_safesemMtxUnlock(pGlobals->hmtx);
+	LIBCLOG_RETURN_INT(rval);
+}
+
+
+_FORK_CHILD1(0xf0010000, shmfork_myhook)
+
+/**
+ * Callback function for registration using _FORK_PARENT1()
+ * or _FORK_CHILD1().
+ *
+ * @returns 0 on success.
+ * @returns positive errno on warning.
+ * @returns negative errno on failure. Fork will be aborted.
+ * @param   pForkHandle     Pointer to fork handle.
+ * @param   enmOperation    Callback operation.
+ */
+static int shmfork_myhook(__LIBC_PFORKHANDLE pForkHandle, __LIBC_FORKOP enmOperation)
+{
+    switch (enmOperation)
+    {
+	/*
+	 * We'll have to increment the shm_nattch counts of any attached segments.
+	 */
+	case __LIBC_FORK_OP_EXEC_CHILD:
+	{
+	    struct __libc_SysV_Shm *pGlobals = gpGlobals;
+	    if (pGlobals)
+	    {
+		__atomic_increment_u32(&pGlobals->cUsers);
+		struct shmmap_state *shm = g_vm_shm;
+		if (shm) {
+		    __libc_Back_safesemMtxLock(pGlobals->hmtx);
+		    int c = shminfo.shmseg;
+		    while (c-- > 0)
+		    {
+			if (shm->shmid != -1)
+			    pGlobals->shmsegs[IPCID_TO_IX(shm->shmid)].shm_nattch++;
+		    }
+		    __libc_Back_safesemMtxUnlock(pGlobals->hmtx);
+		}
+	    }
+	    break;
+	}
+
+	default:
+	    break;
+    }
+    return 0;
+}
+
+
+static void
+shmexit_myhook(void)
+{
+	struct __libc_SysV_Shm *pGlobals = gpGlobals;
+	if (pGlobals) {
+		gpGlobals = NULL;
+		struct shmmap_state *shm = g_vm_shm;
+		if (shm) {
+    			g_vm_shm = NULL;
+			__libc_Back_safesemMtxLock(pGlobals->hmtx);
+			int c = shminfo.shmseg;
+			while (c-- > 0) {
+				if (shm->shmid != -1)
+					shm_delete_mapping(shm);
+				shm++;
+			}
+			__libc_Back_safesemMtxUnlock(pGlobals->hmtx);
+		}
+		__atomic_decrement_u32(&pGlobals->cUsers);
+	}
+}
+
+static int shminit(void)
+{
+    LIBCLOG_ENTER("\n");
+
+    /*
+     * Try open it first.
+     */
+    __LIBC_SPMXCPTREGREC    RegRec;
+    __LIBC_PSPMHEADER       pSPMHdr;
+    int rc = __libc_spmLock(&RegRec, &pSPMHdr);
+    if (rc)
+        LIBCLOG_RETURN_INT(rc);
+    if (gpGlobals)
+    {
+        __libc_spmUnlock(&RegRec);
+        LIBCLOG_RETURN_INT(0);
+    }
+    struct __libc_SysV_Shm *pGlobals = gpGlobals = pSPMHdr->pSysVShm;
+    if (!pGlobals)
+    {
+        /*
+         * We will have to initialize the shared memory stuff.
+         * Since we're gonna parse environment first, release the SPM lock.
+         */
+        __libc_spmUnlock(&RegRec);
+
+	struct shminfo si = shminfo;
+	TUNABLE_INT_FETCH("kern.ipc.shmmin", &si.shmmin);
+	TUNABLE_INT_FETCH("kern.ipc.shmmni", &si.shmmni);
+	TUNABLE_INT_FETCH("kern.ipc.shmseg", &si.shmseg);
+	TUNABLE_INT_FETCH("kern.ipc.shmmaxpgs", &si.shmall);
+	si.shmmax = si.shmall * PAGE_SIZE;
+	if (si.shmmax < si.shmall)
+            si.shmmax = 0xc0000000;
+	//TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys);
+
+	/* calc size. */
+	size_t cb = sizeof(*pGlobals);
+	cb += si.shmmni * sizeof(struct shmid_ds);
+
+        /*
+         * Retake the sem and allocate the memory.
+         */
+        rc = __libc_spmLock(&RegRec, &pSPMHdr);
+        if (rc)
+            LIBCLOG_RETURN_INT(rc);
+        if (!pSPMHdr->pSysVSem)
+        {
+            pGlobals = (struct __libc_SysV_Shm *)__libc_spmAllocLocked(cb);
+            if (!pGlobals)
+            {
+                __libc_spmUnlock(&RegRec);
+                LIBCLOG_RETURN_INT(-ENOMEM);
+            }
+	
+            /* init globals */
+	    bzero(pGlobals, cb);
+	    pGlobals->uVersion = 1;
+	    pGlobals->cUsers = 0;
+	    //pGlobals->shm_last_free = 0;
+	    //pGlobals->shm_nused = 0;
+	    //pGlobals->shm_committed = 0;
+            pGlobals->shmalloced = si.shmmni;
+	    struct shmid_ds *shmsegs = pGlobals->shmsegs = (struct shmid_ds *)(pGlobals + 1);
+	    int i;
+	    for (i = 0; i < si.shmmni; i++) {
+		    shmsegs[i].shm_perm.mode = SHMSEG_FREE;
+		    //shmsegs[i].shm_perm.seq = 0;
+	    }
+	    pGlobals->shminfo = si;
+	
+	    /* Set globals. */
+            pSPMHdr->pSysVShm = pGlobals;
+            gpGlobals = pGlobals;
+	}
+    }
+
+    /*
+     * Open or create the semaphores.
+     */
+    if (!pGlobals->cUsers)
+    {
+        /* create */
+        rc = __libc_Back_safesemMtxCreate(&pGlobals->hmtx, 1);
+	if (!rc)
+            rc = __libc_Back_safesemEvCreate(&pGlobals->hevDaemon, 1);
+    }
+    else
+    {
+        /* open */
+        rc = __libc_Back_safesemMtxOpen(pGlobals->hmtx);
+	if (!rc)
+            rc = __libc_Back_safesemEvOpen(pGlobals->hevDaemon);
+    }
+    __atomic_increment_u32(&pGlobals->cUsers);
+
+    /*
+     * Register exit list handler and release the SPM lock.
+     */
+    __libc_spmRegTerm(shmexit_myhook);
+    __libc_spmUnlock(&RegRec);
+
+    /*
+     * Update seminfo and return.
+     */
+    shminfo = pGlobals->shminfo;
+    if (rc)
+        rc = -__libc_native2errno(rc);
+    LIBCLOG_RETURN_INT(rc);
+}
+
+#if 0
+static int
+sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
+{
+
+	return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])));
+}
+#endif
+
