summaryrefslogtreecommitdiffstats
path: root/src/test/system/cross_process_sem.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/system/cross_process_sem.cc')
-rw-r--r--src/test/system/cross_process_sem.cc122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/test/system/cross_process_sem.cc b/src/test/system/cross_process_sem.cc
new file mode 100644
index 000000000..d73259d25
--- /dev/null
+++ b/src/test/system/cross_process_sem.cc
@@ -0,0 +1,122 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+* Ceph - scalable distributed file system
+*
+* Copyright (C) 2011 New Dream Network
+*
+* This is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License version 2.1, as published by the Free Software
+* Foundation. See file COPYING.
+*
+*/
+
+#include "cross_process_sem.h"
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#ifndef _WIN32
+#include <sys/mman.h>
+#endif
+
+#include "include/ceph_assert.h"
+
+/* We put our cross-process semaphore into a page of memory mapped with mmap. */
+struct cross_process_sem_data_t
+{
+ sem_t sem;
+};
+
+/* A factory function is a good choice here because we want to be able to
+ * return an error code. It does force heap allocation, but that is the
+ * easiest way to use synchronization primitives anyway. Most programmers don't
+ * care about destroying semaphores before the process finishes. It's pretty
+ * difficult to get it right and there is usually no benefit.
+ */
+int CrossProcessSem::
+create(int initial_val, CrossProcessSem** res)
+{
+ #ifndef _WIN32
+ struct cross_process_sem_data_t *data = static_cast < cross_process_sem_data_t*> (
+ mmap(NULL, sizeof(struct cross_process_sem_data_t),
+ PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
+ if (data == MAP_FAILED) {
+ int err = errno;
+ return err;
+ }
+ int ret = sem_init(&data->sem, 1, initial_val);
+ #else
+ // We can't use multiple processes on Windows for the time being.
+ struct cross_process_sem_data_t *data = (cross_process_sem_data_t*)malloc(
+ sizeof(cross_process_sem_data_t));
+ int ret = sem_init(&data->sem, 0, initial_val);
+ #endif /* _WIN32 */
+ if (ret) {
+ return ret;
+ }
+ *res = new CrossProcessSem(data);
+ return 0;
+}
+
+CrossProcessSem::
+~CrossProcessSem()
+{
+ #ifndef _WIN32
+ munmap(m_data, sizeof(struct cross_process_sem_data_t));
+ #else
+ free(m_data);
+ #endif
+ m_data = NULL;
+}
+
+void CrossProcessSem::
+wait()
+{
+ while(true) {
+ int ret = sem_wait(&m_data->sem);
+ if (ret == 0)
+ return;
+ int err = errno;
+ if (err == -EINTR)
+ continue;
+ ceph_abort();
+ }
+}
+
+void CrossProcessSem::
+post()
+{
+ int ret = sem_post(&m_data->sem);
+ if (ret == -1) {
+ ceph_abort();
+ }
+}
+
+int CrossProcessSem::
+reinit(int dval)
+{
+ if (dval < 0)
+ return -EINVAL;
+ int cval;
+ if (sem_getvalue(&m_data->sem, &cval) == -1)
+ return errno;
+ if (cval < dval) {
+ int diff = dval - cval;
+ for (int i = 0; i < diff; ++i)
+ sem_post(&m_data->sem);
+ }
+ else {
+ int diff = cval - dval;
+ for (int i = 0; i < diff; ++i)
+ sem_wait(&m_data->sem);
+ }
+ return 0;
+}
+
+CrossProcessSem::
+CrossProcessSem(struct cross_process_sem_data_t *data)
+ : m_data(data)
+{
+}