--- a
+++ b/src/sysvshm.cpp
@@ -0,0 +1,225 @@
+/* Copyright (C) 2017-2018 J.F.Dockes
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "sysvshm.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#include "log.h"
+#include "smallut.h"
+
+using namespace std;
+
+#ifndef LOGSYSERR
+#include <string.h>
+#if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
+#define LOGSYSERR(who, what, arg) { \
+ char buf[200]; buf[0] = 0; strerror_r(errno, buf, 200); \
+ LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
+ ": " << buf << std::endl); \
+ }
+#else
+#define LOGSYSERR(who, what, arg) { \
+ char buf[200]; buf[0] = 0; \
+ LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
+ ": " << strerror_r(errno, buf, 200) << std::endl); \
+ }
+#endif
+#endif
+
+class ShmSeg::Internal {
+ friend class LockableShmSeg;
+public:
+ int shmid{-1};
+ key_t key{IPC_PRIVATE};
+ void *seg{nullptr};
+ size_t bytes{0};
+ // Delete seg or leave it behind.
+ bool removeondelete{true};
+ bool ok{false};
+ bool mycreation{false};
+};
+
+void ShmSeg::setremove(bool onoff)
+{
+ m->removeondelete = onoff;
+}
+
+void *ShmSeg::getseg()
+{
+ return m->seg;
+}
+
+size_t ShmSeg::getsize()
+{
+ return m->bytes;
+}
+
+bool ShmSeg::ok()
+{
+ return m->ok;
+}
+
+ShmSeg::ShmSeg(key_t ky, size_t size, bool create, int perms)
+ : m(new Internal)
+{
+ // SHMDEB "ShmSeg::ShmSeg: ky %d size %d\n", ky, size ENDLOG;
+
+ if (ky == 0 || ky == IPC_PRIVATE) {
+ m->key = IPC_PRIVATE;
+ m->removeondelete = true;
+ } else {
+ m->key = ky;
+ m->removeondelete = false;
+ }
+ int flags = 0;
+ if (create) {
+ flags = IPC_CREAT|IPC_EXCL;
+ } else {
+ perms = 0;
+ }
+ if ((m->shmid = shmget(m->key, size, flags|perms)) >= 0) {
+ if (create) {
+ m->mycreation = true;
+ }
+ } else {
+ if (errno != EEXIST) {
+ LOGSYSERR("ShmSeg::ShmSeg", "shmget", size);
+ return;
+ }
+ if ((m->shmid = shmget(m->key, size, 0)) < 0) {
+ LOGSYSERR("ShmSeg::ShmSeg", "shmget", size);
+ return;
+ }
+ }
+ m->bytes = size;
+ // Attach it
+ if ((m->seg = shmat(m->shmid, 0, 0)) == (void *)-1) {
+ LOGSYSERR("ShmSeg::ShmSeg", "shmat", m->shmid);
+ shmctl(m->shmid, IPC_RMID, 0);
+ return;
+ }
+ m->ok = true;
+}
+
+ShmSeg::ShmSeg(const char*pathname, int proj_id, size_t size, bool create, int perms)
+ : ShmSeg(ftok(pathname, proj_id), size, create, perms)
+{
+}
+
+ShmSeg::~ShmSeg()
+{
+ if (m->seg && (shmdt(m->seg) < 0)) {
+ LOGSYSERR("ShmSeg::~ShmSeg", "shmdt", "");
+ }
+ if (m->shmid != -1 && m->removeondelete) {
+ LOGDEB0("ShmSeg::~ShmSeg: removing seg\n");
+ if (shmctl(m->shmid, IPC_RMID, 0) < 0) {
+ LOGSYSERR("ShmSeg::~ShmSeg", "shmctl RMID", m->shmid);
+ }
+ }
+ // just in case
+ m->seg = nullptr;
+ m->bytes = 0;
+ m->shmid = -1;
+ m->ok = false;
+}
+
+#define LOCKAREASIZE (((sizeof(pthread_mutex_t)+7)/8)*8)
+
+LockableShmSeg::LockableShmSeg(key_t ky, size_t size, bool create, int perms)
+ : ShmSeg(ky, size+LOCKAREASIZE, create, perms)
+{
+ if (m && m->mycreation && m->seg) {
+ memset(m->seg, 0, LOCKAREASIZE);
+ int err{0};
+ pthread_mutexattr_t attr;
+ pthread_mutex_t *mutex = (pthread_mutex_t*)m->seg;
+ err = pthread_mutexattr_init(&attr);if (err) goto done;
+ err = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ if (err) goto done;
+ err = pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
+ if (err) goto done;
+ err = pthread_mutex_init(mutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+ done:
+ if (err) {
+ LOGERR("LockableShmSeg: pthread mutex init failed errno " << errno
+ << " return value " << err << endl);
+ m->ok = false;
+ }
+ }
+}
+
+LockableShmSeg::LockableShmSeg(const char*pathname, int proj_id, size_t size,
+ bool create, int perms)
+ : LockableShmSeg(ftok(pathname, proj_id), size, create, perms)
+{
+}
+
+LockableShmSeg::~LockableShmSeg()
+{
+ if (nullptr == m || !m->ok) {
+ return;
+ }
+ if (m->removeondelete) {
+ pthread_mutex_t *mutex = (pthread_mutex_t*)m->seg;
+ pthread_mutex_destroy(mutex);
+ }
+}
+
+void *LockableShmSeg::getseg()
+{
+ return ShmSeg::getseg();
+}
+
+LockableShmSeg::Accessor::Accessor(LockableShmSeg& _lss)
+ : lss(_lss)
+{
+ if (!lss.ok())
+ return;
+ void *seg = lss.getseg();
+ pthread_mutex_t *mutex = (pthread_mutex_t*)seg;
+ int err = pthread_mutex_lock(mutex);
+ if (err != 0) {
+ LOGSYSERR("LockableShmSeg::Accessor", "pthread_mutex_lock", "");
+ }
+}
+
+LockableShmSeg::Accessor::~Accessor()
+{
+ if (!lss.ok())
+ return;
+ void *seg = lss.getseg();
+ pthread_mutex_t *mutex = (pthread_mutex_t*)seg;
+ int err = pthread_mutex_unlock(mutex);
+ if (err != 0) {
+ LOGSYSERR("LockableShmSeg::Accessor", "pthread_mutex_unlock", "");
+ }
+}
+
+void *LockableShmSeg::Accessor::getseg()
+{
+ if (!lss.ok())
+ return nullptr;
+ char *seg = (char*)(lss.getseg());
+ return seg + LOCKAREASIZE;
+}