1//
2// NamedMutex_UNIX.cpp
3//
4// Library: Foundation
5// Package: Processes
6// Module: NamedMutex
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/NamedMutex_UNIX.h"
16#include "Poco/Format.h"
17#include "Poco/Exception.h"
18#include <fcntl.h>
19#include <sys/stat.h>
20#include <errno.h>
21#if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(_AIX) || defined(__EMSCRIPTEN__)
22#include <semaphore.h>
23#else
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/ipc.h>
27#include <sys/sem.h>
28#endif
29
30
31namespace Poco {
32
33
34#if (POCO_OS == POCO_OS_LINUX) || (POCO_OS == POCO_OS_CYGWIN) || (POCO_OS == POCO_OS_FREE_BSD) || (POCO_OS == POCO_OS_NACL)
35 union semun
36 {
37 int val;
38 struct semid_ds* buf;
39 unsigned short int* array;
40 struct seminfo* __buf;
41 };
42#elif (POCO_OS == POCO_OS_HPUX)
43 union semun
44 {
45 int val;
46 struct semid_ds* buf;
47 ushort* array;
48 };
49#endif
50
51
52NamedMutexImpl::NamedMutexImpl(const std::string& name):
53 _name(name)
54{
55 std::string fileName = getFileName();
56#if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__)
57 _sem = sem_open(fileName.c_str(), O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO, 1);
58 if ((long) _sem == (long) SEM_FAILED)
59 throw SystemException(Poco::format("cannot create named mutex %s (sem_open() failed, errno=%d)", fileName, errno), _name);
60#else
61 int fd = open(fileName.c_str(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
62 if (fd != -1)
63 close(fd);
64 else
65 throw SystemException(Poco::format("cannot create named mutex %s (lockfile)", fileName), _name);
66 key_t key = ftok(fileName.c_str(), 'p');
67 if (key == -1)
68 throw SystemException(Poco::format("cannot create named mutex %s (ftok() failed, errno=%d)", fileName, errno), _name);
69 _semid = semget(key, 1, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | IPC_CREAT | IPC_EXCL);
70 if (_semid >= 0)
71 {
72 union semun arg;
73 arg.val = 1;
74 semctl(_semid, 0, SETVAL, arg);
75 _owned = true;
76 return;
77 }
78 else if (errno == EEXIST)
79 {
80 _semid = semget(key, 1, 0);
81 _owned = false;
82 if (_semid >= 0) return;
83 }
84
85 throw SystemException(Poco::format("cannot create named mutex %s (semget() failed, errno=%d)", fileName, errno), _name);
86#endif // defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__)
87}
88
89
90NamedMutexImpl::~NamedMutexImpl()
91{
92#if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__)
93 sem_close(_sem);
94#else
95 if (_owned) semctl(_semid, 0, IPC_RMID, 0);
96#endif
97}
98
99
100void NamedMutexImpl::lockImpl()
101{
102#if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__)
103 int err;
104 do
105 {
106 err = sem_wait(_sem);
107 }
108 while (err && errno == EINTR);
109 if (err) throw SystemException("cannot lock named mutex", _name);
110#else
111 struct sembuf op;
112 op.sem_num = 0;
113 op.sem_op = -1;
114 op.sem_flg = SEM_UNDO;
115 int err;
116 do
117 {
118 err = semop(_semid, &op, 1);
119 }
120 while (err && errno == EINTR);
121 if (err) throw SystemException("cannot lock named mutex", _name);
122#endif
123}
124
125
126bool NamedMutexImpl::tryLockImpl()
127{
128#if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__)
129 return sem_trywait(_sem) == 0;
130#else
131 struct sembuf op;
132 op.sem_num = 0;
133 op.sem_op = -1;
134 op.sem_flg = SEM_UNDO | IPC_NOWAIT;
135 return semop(_semid, &op, 1) == 0;
136#endif
137}
138
139
140void NamedMutexImpl::unlockImpl()
141{
142#if defined(sun) || defined(__APPLE__) || defined(__osf__) || defined(__QNX__) || defined(_AIX) || defined(__EMSCRIPTEN__)
143 if (sem_post(_sem) != 0)
144 throw SystemException("cannot unlock named mutex", _name);
145#else
146 struct sembuf op;
147 op.sem_num = 0;
148 op.sem_op = 1;
149 op.sem_flg = SEM_UNDO;
150 if (semop(_semid, &op, 1) != 0)
151 throw SystemException("cannot unlock named mutex", _name);
152#endif
153}
154
155
156std::string NamedMutexImpl::getFileName()
157{
158#if defined(sun) || defined(__APPLE__) || defined(__QNX__)
159 std::string fn = "/";
160#else
161 std::string fn = "/tmp/";
162#endif
163 fn.append(_name);
164 fn.append(".mutex");
165 return fn;
166}
167
168
169} // namespace Poco
170
171