2 Copyright (C) 2006-2023 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 Pwmd is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
28 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_FILE_H
37 #include <sys/select.h>
38 #include <sys/types.h>
45 #ifndef HAVE_PTHREAD_CANCEL
46 extern pthread_key_t signal_thread_key
;
48 #define TEST_CANCEL() do { \
49 int *cancel = (int *) pthread_getspecific (signal_thread_key); \
50 if (cancel && *cancel) \
51 pthread_exit (NULL); \
57 #define INIT_TIMESPEC(t, ts) do { \
58 long s = (t*100000000)/1000000000; \
59 long l = (t*100000000)%1000000000; \
60 clock_gettime(CLOCK_REALTIME, &ts); \
62 if (ts.tv_nsec + l >= 1000000000) { \
71 #define MUTEX_LOCK_DEBUG(m) do { \
72 log_write("%s(%i): %s(): LOCK %p", __FILE__, __LINE__, \
76 #define MUTEX_UNLOCK_DEBUG(m) do { \
77 log_write("%s(%i): %s(): UNLOCK %p", __FILE__, __LINE__, \
81 #define MUTEX_LOCK_DEBUG(m)
82 #define MUTEX_UNLOCK_DEBUG(m)
85 #define MUTEX_LOCK(m) do { \
86 MUTEX_LOCK_DEBUG(m); \
87 while (pthread_mutex_trylock (m) == EBUSY) { \
88 struct timeval tv = { 0, 3000 }; \
90 select (0, NULL, NULL, NULL, &tv); \
94 #define MUTEX_UNLOCK(m) do { \
95 MUTEX_UNLOCK_DEBUG(m); \
96 pthread_mutex_unlock(m); \
99 #define TIMED_LOCK_DURATION 100000
101 #define TRY_FLOCK(ctx, fd, type, rc) do { \
102 long ka = (long)config_get_integer ("global", "keepalive_interval");\
103 long to = config_get_long ("global", "lock_timeout"); \
104 for (long elapsed = 0; ; elapsed++) { \
105 struct timeval tv = { 0, TIMED_LOCK_DURATION }; \
106 int n = flock (fd, type|LOCK_NB); \
107 if (n == -1 && errno == EWOULDBLOCK) { \
108 if (to == -1 || elapsed >= to) { \
109 rc = GPG_ERR_LOCKED; \
112 select (0, NULL, NULL, NULL, &tv); \
113 if (ctx && ka && elapsed && !((elapsed+1*10) % (ka*10))) { \
114 rc = send_status (ctx, STATUS_KEEPALIVE, NULL); \
121 rc = gpg_error_from_errno (errno); \
127 #define TRY_FLOCK(ctx, fd, type, rc) do { \
132 #define MUTEX_TIMED_LOCK(ctx, m, timeout, rc) do { \
133 long ka = (long)config_get_integer ("global", "keepalive_interval");\
134 for (long elapsed = 0; ; elapsed++) { \
135 struct timeval tv = { 0, TIMED_LOCK_DURATION }; \
136 int n = pthread_mutex_trylock (m); \
138 if (timeout == -1 || elapsed >= timeout) { \
139 rc = GPG_ERR_LOCKED; \
142 select (0, NULL, NULL, NULL, &tv); \
143 if (ctx && ka && elapsed && !((elapsed+1*10) % (ka*10))) { \
144 rc = send_status (ctx, STATUS_KEEPALIVE, NULL); \
151 rc = gpg_error_from_errno (n); \
155 MUTEX_LOCK_DEBUG(m); \
161 #define MUTEX_TRYLOCK(ctx, m, rc, t) do { \
162 int err = pthread_mutex_trylock (m); \
164 if (err == EBUSY) { \
167 rc = send_status(ctx, STATUS_LOCKED, NULL); \
169 MUTEX_TIMED_LOCK(ctx, m, t, rc); \
171 rc = GPG_ERR_LOCKED; \
174 rc = GPG_ERR_LOCKED; \
177 rc = gpg_error_from_errno (err); \
179 MUTEX_LOCK_DEBUG(m); \
182 #define MUTEX_TIMED_RWLOCK(ctx, m, timeout, rc, w) do { \
183 long ka = (long)config_get_integer ("global", "keepalive_interval");\
184 for (long elapsed = 0; ; elapsed++) { \
185 struct timeval tv = { 0, TIMED_LOCK_DURATION }; \
188 err = pthread_rwlock_trywrlock(m); \
190 err = pthread_rwlock_tryrdlock(m); \
191 if (err == EBUSY) { \
192 if (timeout == -1 || elapsed >= timeout) { \
193 rc = GPG_ERR_LOCKED; \
196 select (0, NULL, NULL, NULL, &tv); \
197 if (ctx && ka && elapsed && !((elapsed+1*10) % (ka*10))) { \
198 rc = send_status (ctx, STATUS_KEEPALIVE, NULL); \
205 rc = gpg_error_from_errno (err); \
209 MUTEX_LOCK_DEBUG(m); \