summaryrefslogtreecommitdiff
path: root/3rdparty/plibsys/src/pshm-os2.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/plibsys/src/pshm-os2.c')
-rw-r--r--3rdparty/plibsys/src/pshm-os2.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/3rdparty/plibsys/src/pshm-os2.c b/3rdparty/plibsys/src/pshm-os2.c
new file mode 100644
index 0000000..92e0779
--- /dev/null
+++ b/3rdparty/plibsys/src/pshm-os2.c
@@ -0,0 +1,350 @@
+/*
+ * The MIT License
+ *
+ * Copyright (C) 2017 Alexander Saprykin <saprykin.spb@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * 'Software'), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "perror.h"
+#include "pmem.h"
+#include "pshm.h"
+#include "perror-private.h"
+#include "pipc-private.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#define INCL_DOSMEMMGR
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#define P_SHM_MEM_PREFIX "\\SHAREMEM\\"
+#define P_SHM_SEM_PREFIX "\\SEM32\\"
+#define P_SHM_SUFFIX "_p_shm_object"
+
+struct PShm_ {
+ pchar *platform_key;
+ ppointer addr;
+ psize size;
+ HMTX sem;
+ PShmAccessPerms perms;
+};
+
+static pboolean pp_shm_create_handle (PShm *shm, PError **error);
+static void pp_shm_clean_handle (PShm *shm);
+
+static pboolean
+pp_shm_create_handle (PShm *shm,
+ PError **error)
+{
+ pchar *mem_name;
+ pchar *sem_name;
+ APIRET ulrc;
+ ULONG flags;
+
+ if (P_UNLIKELY (shm == NULL || shm->platform_key == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IPC_INVALID_ARGUMENT,
+ 0,
+ "Invalid input argument");
+ return FALSE;
+ }
+
+ flags = PAG_COMMIT | PAG_READ;
+
+ if (shm->perms != P_SHM_ACCESS_READONLY)
+ flags |= PAG_WRITE;
+
+ if (P_UNLIKELY ((mem_name = p_malloc0 (strlen (shm->platform_key) +
+ strlen (P_SHM_MEM_PREFIX) + 1)) == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IPC_NO_RESOURCES,
+ 0,
+ "Failed to allocate memory for shared memory name");
+ return FALSE;
+ }
+
+ strcpy (mem_name, P_SHM_MEM_PREFIX);
+ strcat (mem_name, shm->platform_key);
+
+ while ((ulrc = DosAllocSharedMem ((PPVOID) &shm->addr,
+ (PSZ) mem_name,
+ shm->size,
+ flags)) == ERROR_INTERRUPT)
+ ;
+
+ if (P_UNLIKELY (ulrc != NO_ERROR && ulrc != ERROR_ALREADY_EXISTS)) {
+ p_error_set_error_p (error,
+ (pint) p_error_get_ipc_from_system ((pint) ulrc),
+ (pint) ulrc,
+ "Failed to call DosAllocSharedMem() to allocate shared memory");
+ p_free (mem_name);
+ pp_shm_clean_handle (shm);
+ return FALSE;
+ }
+
+ if (ulrc == ERROR_ALREADY_EXISTS) {
+ ULONG real_size;
+ ULONG real_flags;
+
+ flags = (shm->perms == P_SHM_ACCESS_READONLY) ? PAG_READ : (PAG_WRITE | PAG_READ);
+
+ while ((ulrc = DosGetNamedSharedMem ((PPVOID) &shm->addr,
+ (PSZ) mem_name,
+ flags)) == ERROR_INTERRUPT)
+ ;
+
+ p_free (mem_name);
+
+ if (P_UNLIKELY (ulrc != NO_ERROR)) {
+ p_error_set_error_p (error,
+ (pint) p_error_get_ipc_from_system ((pint) ulrc),
+ (pint) ulrc,
+ "Failed to call DosGetNamedSharedMem() to get shared memory");
+ pp_shm_clean_handle (shm);
+ return FALSE;
+ }
+
+ real_size = (ULONG) shm->size;
+
+ while ((ulrc = DosQueryMem ((PVOID) shm->addr,
+ &real_size,
+ &real_flags)) == ERROR_INTERRUPT)
+ ;
+
+ if (P_UNLIKELY (ulrc != NO_ERROR)) {
+ p_error_set_error_p (error,
+ (pint) p_error_get_ipc_from_system ((pint) ulrc),
+ (pint) ulrc,
+ "Failed to call DosQueryMem() to get memory info");
+ pp_shm_clean_handle (shm);
+ return FALSE;
+ }
+
+ shm->size = (psize) real_size;
+ } else
+ p_free (mem_name);
+
+ if (P_UNLIKELY ((sem_name = p_malloc0 (strlen (shm->platform_key) +
+ strlen (P_SHM_SEM_PREFIX) + 1)) == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IPC_NO_RESOURCES,
+ 0,
+ "Failed to allocate memory for shared memory name");
+ pp_shm_clean_handle (shm);
+ return FALSE;
+ }
+
+ strcpy (sem_name, P_SHM_SEM_PREFIX);
+ strcat (sem_name, shm->platform_key);
+
+ ulrc = DosCreateMutexSem ((PSZ) sem_name, &shm->sem, 0, FALSE);
+
+ if (ulrc == ERROR_DUPLICATE_NAME)
+ ulrc = DosOpenMutexSem ((PSZ) sem_name, &shm->sem);
+
+ p_free (sem_name);
+
+ if (P_UNLIKELY (ulrc != NO_ERROR)) {
+ p_error_set_error_p (error,
+ (pint) p_error_get_ipc_from_system ((pint) ulrc),
+ (pint) ulrc,
+ "Failed to call DosCreateMutexSem() to create a lock");
+ pp_shm_clean_handle (shm);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+pp_shm_clean_handle (PShm *shm)
+{
+ APIRET ulrc;
+
+ if (P_UNLIKELY (shm->addr != NULL)) {
+ while ((ulrc = DosFreeMem ((PVOID) shm->addr)) == ERROR_INTERRUPT)
+ ;
+
+ if (P_UNLIKELY (ulrc != NO_ERROR))
+ P_ERROR ("PShm::pp_shm_clean_handle: DosFreeMem() failed");
+
+ shm->addr = NULL;
+ }
+
+ if (P_LIKELY (shm->sem != NULLHANDLE)) {
+ if (P_UNLIKELY (DosCloseMutexSem (shm->sem) != NO_ERROR))
+ P_ERROR ("PShm::pp_shm_clean_handle: DosCloseMutexSem() failed");
+
+ shm->sem = NULLHANDLE;
+ }
+
+ shm->size = 0;
+}
+
+P_LIB_API PShm *
+p_shm_new (const pchar *name,
+ psize size,
+ PShmAccessPerms perms,
+ PError **error)
+{
+ PShm *ret;
+ pchar *new_name;
+
+ if (P_UNLIKELY (name == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IPC_INVALID_ARGUMENT,
+ 0,
+ "Invalid input argument");
+ return NULL;
+ }
+
+ if (P_UNLIKELY ((ret = p_malloc0 (sizeof (PShm))) == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IPC_NO_RESOURCES,
+ 0,
+ "Failed to allocate memory for shared segment");
+ return NULL;
+ }
+
+ if (P_UNLIKELY ((new_name = p_malloc0 (strlen (name) + strlen (P_SHM_SUFFIX) + 1)) == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IPC_NO_RESOURCES,
+ 0,
+ "Failed to allocate memory for segment name");
+ p_shm_free (ret);
+ return NULL;
+ }
+
+ strcpy (new_name, name);
+ strcat (new_name, P_SHM_SUFFIX);
+
+ ret->platform_key = p_ipc_get_platform_key (new_name, FALSE);
+ ret->perms = perms;
+ ret->size = size;
+
+ p_free (new_name);
+
+ if (P_UNLIKELY (pp_shm_create_handle (ret, error) == FALSE)) {
+ p_shm_free (ret);
+ return NULL;
+ }
+
+ if (P_LIKELY (ret->size > size && size != 0))
+ ret->size = size;
+
+ return ret;
+}
+
+P_LIB_API void
+p_shm_take_ownership (PShm *shm)
+{
+ P_UNUSED (shm);
+}
+
+P_LIB_API void
+p_shm_free (PShm *shm)
+{
+ if (P_UNLIKELY (shm == NULL))
+ return;
+
+ pp_shm_clean_handle (shm);
+
+ if (P_LIKELY (shm->platform_key != NULL))
+ p_free (shm->platform_key);
+
+ p_free (shm);
+}
+
+P_LIB_API pboolean
+p_shm_lock (PShm *shm,
+ PError **error)
+{
+ APIRET ulrc;
+
+ if (P_UNLIKELY (shm == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IPC_INVALID_ARGUMENT,
+ 0,
+ "Invalid input argument");
+ return FALSE;
+ }
+
+ while ((ulrc = DosRequestMutexSem (shm->sem,
+ (ULONG) SEM_INDEFINITE_WAIT)) == ERROR_INTERRUPT)
+ ;
+
+ if (P_UNLIKELY (ulrc != NO_ERROR)) {
+ p_error_set_error_p (error,
+ (pint) p_error_get_ipc_from_system ((pint) ulrc),
+ (pint) ulrc,
+ "Failed to lock memory segment");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+P_LIB_API pboolean
+p_shm_unlock (PShm *shm,
+ PError **error)
+{
+ APIRET ulrc;
+
+ if (P_UNLIKELY (shm == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IPC_INVALID_ARGUMENT,
+ 0,
+ "Invalid input argument");
+ return FALSE;
+ }
+
+ ulrc = DosReleaseMutexSem (shm->sem);
+
+ if (P_UNLIKELY (ulrc != NO_ERROR)) {
+ p_error_set_error_p (error,
+ (pint) p_error_get_ipc_from_system ((pint) ulrc),
+ (pint) ulrc,
+ "Failed to unlock memory segment");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+P_LIB_API ppointer
+p_shm_get_address (const PShm *shm)
+{
+ if (P_UNLIKELY (shm == NULL))
+ return NULL;
+
+ return shm->addr;
+}
+
+P_LIB_API psize
+p_shm_get_size (const PShm *shm)
+{
+ if (P_UNLIKELY (shm == NULL))
+ return 0;
+
+ return shm->size;
+}