Changeset: 191a49c4079b for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=191a49c4079b
Added Files:
gdk/gdk_interprocess.c
gdk/gdk_interprocess.h
Removed Files:
gdk/interprocess.c
gdk/interprocess.h
Modified Files:
gdk/Makefile.ag
monetdb5/extras/pyapi/connection.c
monetdb5/extras/pyapi/pyapi.c
Branch: default
Log Message:
Cleanup part one: clean up interprocess.h and replace semaphore functions.
diffs (truncated from 848 to 300 lines):
diff --git a/gdk/Makefile.ag b/gdk/Makefile.ag
--- a/gdk/Makefile.ag
+++ b/gdk/Makefile.ag
@@ -30,9 +30,10 @@ lib_gdk = {
gdk_imprints.c gdk_imprints.h \
gdk_join.c gdk_project.c \
gdk_unique.c \
+ gdk_interprocess.c gdk_interprocess.h \
gdk_firstn.c \
bat.feps bat1.feps bat2.feps \
- libbat.rc interprocess.c interprocess.h
+ libbat.rc
LIBS = ../common/options/libmoptions \
../common/stream/libstream \
../common/utils/libmutils \
diff --git a/gdk/gdk_interprocess.c b/gdk/gdk_interprocess.c
new file mode 100644
--- /dev/null
+++ b/gdk/gdk_interprocess.c
@@ -0,0 +1,345 @@
+
+#include "gdk_interprocess.h"
+
+#ifdef HAVE_FORK
+
+#include "gdk.h"
+#include "gdk_private.h"
+#include "../monetdb5/mal/mal_exception.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <errno.h>
+#include <sys/sem.h>
+#include <time.h>
+
+static size_t interprocess_unique_id = 1;
+static key_t base_key = 800000000;
+
+gdk_return interprocess_init_semaphore(int id, int count, int flags, int
*semid, str *msg);
+
+// Regular ftok produces too many collisions
+static gdk_return
+ftok_enhanced(int id, key_t *return_key) {
+ *return_key = base_key + id;
+ return GDK_SUCCEED;
+}
+
+#define interprocess_create_error(...) { \
+ *msg = (char*) GDKzalloc(500 * sizeof(char)); \
+ snprintf(*msg, 500, __VA_ARGS__); \
+ errno = 0; \
+}
+
+//! Obtain a set of unique identifiers that can be used to create memory
mapped files or semaphores
+/* offset: The amount of unique identifiers necessary
+ * return: The first unique identifier reserved. The consecutive [offset]
identifiers are also reserved.
+ * (ex. if offset = 5 and the return value is 10, then the identifiers 10-14
are reserved)
+*/
+size_t
+GDKuniqueid(size_t offset) {
+ // TODO: lock this here instead of in pyapi
+ size_t id;
+
+ id = interprocess_unique_id;
+ interprocess_unique_id += offset;
+ return id;
+}
+
+//! Create a memory mapped file if it does not exist and open it
+/* id: The unique identifier of the memory mapped file (use GDKuniquemmapid to
get a unique identifier)
+ * size: Minimum required size of the file
+ * return_ptr: Return value pointing into the file
+ * msg: Error message (only set if function returns GDK_FAIL)
+ * return: GDK_SUCCEED if successful, GDK_FAIL if not successful (with msg set
to error message)
+*/
+gdk_return
+GDKinitmmap(size_t id, size_t size, void **return_ptr, str *msg) {
+ char address[100];
+ void *ptr;
+ int fd;
+ int mod = MMAP_READ | MMAP_WRITE | MMAP_SEQUENTIAL | MMAP_SYNC |
MAP_SHARED;
+ char *path = NULL;
+ snprintf_mmap_file(address, 100, id);
+
+ /* round up to multiple of GDK_mmap_pagesize with a
+ * minimum of one
+ size = (maxsize + GDK_mmap_pagesize - 1) & ~(GDK_mmap_pagesize - 1);
+ if (size == 0)
+ size = GDK_mmap_pagesize; */
+ fd = GDKfdlocate(0, address, "wb", "tmp");
+ if (fd < 0) {
+ interprocess_create_error("Failure in GDKfdlocate: %s",
strerror(errno));
+ goto cleanup;
+ }
+ path = GDKfilepath(0, BATDIR, address, "tmp");
+ if (path == NULL) {
+ interprocess_create_error("Failure in GDKfilepath: %s",
strerror(errno));
+ goto cleanup;
+ }
+ close(fd);
+ if (GDKextend(path, size) != GDK_SUCCEED) {
+ interprocess_create_error("Failure in GDKextend: %s", strerror(errno));
+ goto cleanup;
+ }
+ ptr = GDKmmap(path, mod, size);
+ if (ptr == NULL) {
+ interprocess_create_error("Failure in GDKmmap: %s", strerror(errno));
+ goto cleanup;
+ }
+ GDKfree(path);
+ if (return_ptr != NULL) (*return_ptr) = ptr;
+ return GDK_SUCCEED;
+cleanup:
+ if (path) GDKfree(path);
+ return GDK_FAIL;
+}
+
+//! Release a memory mapped file that was created through GDKinitmmap
+/* ptr: Pointer to the file
+ * size: Size of the file
+ * id: Identifier of the file
+ * msg: Error message (only set if function returns GDK_FAIL)
+ * return: GDK_SUCCEED if successful, GDK_FAIL if not successful (with msg set
to error message)
+*/
+gdk_return
+GDKreleasemmap(void *ptr, size_t size, size_t id, str *msg) {
+ char address[100];
+ char *path;
+ int ret;
+ snprintf_mmap_file(address, 100, id);
+ if (GDKmunmap(ptr, size) != GDK_SUCCEED) {
+ interprocess_create_error("Failure in GDKmunmap: %s", strerror(errno));
+ return GDK_FAIL;
+ }
+ path = GDKfilepath(0, BATDIR, address, "tmp");
+ if (path == NULL) {
+ interprocess_create_error("Failure in GDKfilepath: %s",
strerror(errno));
+ return GDK_FAIL;
+ }
+ ret = remove(path);
+ GDKfree(path);
+ if (ret < 0) {
+ interprocess_create_error("Failure in GDKfree: %s", strerror(errno));
+ return GDK_FAIL;
+ }
+ return GDK_SUCCEED;
+}
+
+//! snprintf the file name of a memory mapped file (as created by GDKinitmmap)
+/* buffer: The buffer to write the name to
+ * max: The maxsize of the buffer (should be at least ~10 characters)
+ * id: Identifier of the file
+*/
+gdk_return
+GDKmmapfile(str buffer, size_t max, size_t id) {
+ snprintf(buffer, max, "pymmap%zu", id);
+ return GDK_SUCCEED;
+}
+
+gdk_return
+interprocess_init_semaphore(int id, int count, int flags, int *semid, str
*msg) {
+ key_t key;
+ if (ftok_enhanced(id, &key) != GDK_SUCCEED) {
+ interprocess_create_error("Failure in ftok_enhanced: %s",
strerror(errno));
+ return GDK_FAIL;
+ }
+ *semid = semget(key, count, flags | 0666);
+ if (*semid < 0) {
+ interprocess_create_error("Failure in semget: %s", strerror(errno));
+ return GDK_FAIL;
+ }
+ return GDK_SUCCEED;
+}
+
+//! Create an interprocess semaphore
+/* id: identifier (obtain from GDKuniqueid)
+ * count: amount of semaphores
+ * semid: identifier of the created semaphore (only set if function returns
GDK_SUCCEED)
+ * msg: Error message (only set if function returns GDK_FAIL)
+ */
+gdk_return
+GDKcreatesem(int id, int count, int *semid, str *msg) {
+ return interprocess_init_semaphore(id, count, IPC_CREAT, semid, msg);
+}
+
+//! Get an interprocess semaphore that was already created using GDKcreatesem
+/* id: identifier (obtain from GDKuniqueid)
+ * count: amount of semaphores
+ * semid: identifier of the semaphore (only set if function returns
GDK_SUCCEED)
+ * msg: Error message (only set if function returns GDK_FAIL)
+ */
+gdk_return
+GDKgetsem(int id, int count, int *semid, str *msg) {
+ return interprocess_init_semaphore(id, count, 0, semid, msg);
+}
+
+//! Gets the value of an interprocess semaphore
+/* sem_id: semaphore identifier (obtained from GDKcreatesem or GDKgetsem)
+ * number: the semaphore number (must be less than 'count' given when creating
the semaphore)
+ * semval: the value of the semaphore (only set if function returns
GDK_SUCCEED)
+ * msg: Error message (only set if function returns GDK_FAIL)
+ */
+gdk_return
+GDKgetsemval(int sem_id, int number, int *semval, str *msg) {
+ *semval = semctl(sem_id, number, GETVAL, 0);
+ if (*semval < 0) {
+ interprocess_create_error("Failure in semctl: %s", strerror(errno));
+ return GDK_FAIL;
+ }
+ return GDK_SUCCEED;
+}
+
+//! Change the value of an interprocess semaphore
+/* sem_id: semaphore identifier (obtained from GDKcreatesem or GDKgetsem)
+ * number: the semaphore number (must be less than 'count' given when creating
the semaphore)
+ * change: The change to apply to the semaphore value
+ * msg: Error message (only set if function returns GDK_FAIL)
+ */
+gdk_return
+GDKchangesemval(int sem_id, int number, int change, str *msg) {
+ struct sembuf buffer;
+ buffer.sem_num = number;
+ buffer.sem_op = change;
+ buffer.sem_flg = 0;
+
+ if (semop(sem_id, &buffer, 1) < 0) {
+ interprocess_create_error("Failure in semop: %s", strerror(errno));
+ return GDK_FAIL;
+ }
+ return GDK_SUCCEED;
+}
+
+//! Change the value of an interprocess semaphore with a timeout
+/* sem_id: semaphore identifier (obtained from GDKcreatesem or GDKgetsem)
+ * number: the semaphore number (must be less than 'count' given when creating
the semaphore)
+ * change: The change to apply to the semaphore value
+ * timeout_mseconds: The timeout in milliseconds
+ * succeed: Set to true if the value was successfully changed, or false if the
timeout was reached
+ * msg: Error message (only set if function returns GDK_FAIL)
+ */
+gdk_return
+GDKchangesemval_timeout(int sem_id, int number, int change, int
timeout_mseconds, bool *succeed, str *msg) {
+#ifdef HAVE_SEMTIMEDOP
+ // Some linux installations don't have semtimedop
+ // The easiest solution is to just call semop instead
+ // The only reason we use semtimedop is to prevent deadlocks when there
are segfaults in a subprocess, which really shouldn't happen anyway
+ // So having semtimedop is not vital to the functioning of the program
+ struct timespec timeout;
+ struct sembuf buffer;
+ buffer.sem_num = number;
+ buffer.sem_op = change;
+ buffer.sem_flg = 0;
+ *succeed = false;
+
+ timeout.tv_sec = (timeout_mseconds / 1000);
+ timeout.tv_nsec = (timeout_mseconds % 1000) * 1000;
+
+ if (semtimedop(sem_id, &buffer, 1, &timeout) < 0) {
+ if (errno == EAGAIN || errno == EINTR) {
+ // operation timed out; not an error
+ errno = 0;
+ return GDK_SUCCEED;
+ } else {
+ interprocess_create_error("Failure in semtimedop: %s",
strerror(errno));
+ return GDK_FAIL;
+ }
+ }
+ *succeed = true;
+ return GDK_SUCCEED;
+#else
+ (void) timeout_mseconds;
+ *succeed = true;
+ return GDKchangesemval(sem_id, number, change, msg);
+#endif
+}
+
+//! Destroy an interprocess semaphore
+/* sem_id: semaphore identifier (obtained from GDKcreatesem or GDKgetsem)
+ * msg: Error message (only set if function returns GDK_FAIL)
+ */
+gdk_return
+GDKreleasesem(int sem_id, str *msg) {
+ if (semctl(sem_id, 0, IPC_RMID) < 0) {
+ interprocess_create_error("Failure in semctl: %s", strerror(errno))
+ return GDK_FAIL;
+ }
+ return GDK_SUCCEED;
+}
+
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list