misc: a few portability tweaks
[rb-79.git] / locks.c
blob1199754a91f162f3fe9108d0d1e69f446cbc4f0d
1 /*
2 * Copyright (c) 2017-2018, De Rais <derais@cock.li>
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <time.h>
25 #include <unistd.h>
27 #include "macros.h"
28 #include "rb79.h"
30 static int *lock_table = 0;
31 static size_t lock_table_len = 0;
32 static int lock_recent;
35 * Set up the lock files and make sure we can connect to them.
37 * Preconditions:
39 * - setup_locks() was not invoked more recently than clean_locks().
41 * Postconditions (success):
43 * - Any other function in this file may be safely called.
45 int setup_locks(const struct configuration *conf)
47 int ret = -1;
48 char *path = 0;
49 size_t len = 0;
51 if (lock_table) {
52 return 0;
55 if (!(lock_table = calloc(conf->boards_num, sizeof *lock_table))) {
56 PERROR_MESSAGE("malloc");
57 ERROR_MESSAGE("Cannot set up locks");
58 goto done;
61 for (size_t j = 0; j < conf->boards_num; ++j) {
62 lock_table[j] = -1;
65 /* Locks for each board */
66 for (size_t j = 0; j < conf->boards_num; ++j) {
67 len = snprintf(0, 0, "%s/lock_board_%s", conf->work_path,
68 conf->boards[j].name);
70 if (len + 1 < len) {
71 ERROR_MESSAGE("overflow");
72 goto done;
75 if (!(path = malloc(len + 1))) {
76 PERROR_MESSAGE("malloc");
77 goto done;
80 sprintf(path, "%s/lock_board_%s", conf->work_path,
81 conf->boards[j].name);
83 if (!(lock_table[j] = open(path, O_RDWR | O_CREAT, 0700))) {
84 PERROR_MESSAGE("open");
85 ERROR_MESSAGE("Cannot open or create lock file %s",
86 path);
87 goto done;
90 free(path);
91 path = 0;
94 lock_table_len = conf->boards_num;
96 /* Lock for the recent page */
97 len = snprintf(0, 0, "%s/lock_recent", conf->work_path);
99 if (len + 1 < len) {
100 ERROR_MESSAGE("overflow");
101 goto done;
104 if (!(path = malloc(len + 1))) {
105 PERROR_MESSAGE("malloc");
106 goto done;
109 sprintf(path, "%s/lock_recent", conf->work_path);
111 if (!(lock_recent = open(path, O_RDWR | O_CREAT, 0700))) {
112 PERROR_MESSAGE("open");
113 ERROR_MESSAGE("Cannot open or create lock file %s", path);
114 goto done;
117 free(path);
118 path = 0;
120 /* Now we've got all the locks */
121 ret = 0;
122 done:
123 free(path);
125 return ret;
129 * Get a lock for a board
131 * Preconditions:
133 * - board_idx represents a board.
135 * - The lock for board_idx is not held in this program.
137 * Postconditions (success):
139 * - The lock for board_idx is now held by this program.
141 int lock_acquire(size_t board_idx)
143 int ret = -1;
145 if (!lock_table ||
146 lock_table[board_idx] < 0) {
147 ERROR_MESSAGE("lock_table isn't set up yet");
148 goto done;
151 if (lockf(lock_table[board_idx], F_LOCK, 0) < 0) {
152 PERROR_MESSAGE("lockf");
153 ERROR_MESSAGE("Cannot lock board %zu", board_idx);
154 goto done;
157 ret = 0;
158 done:
160 return ret;
164 * Get a lock for the recent page
166 * Preconditions:
168 * - The lock for the recent page is not held in this program.
170 * Postconditions (success):
172 * - The lock for the recent page is now held by this program.
174 int lock_acquire_recent(void)
176 int ret = -1;
178 if (lock_recent < 0) {
179 ERROR_MESSAGE("lock_recent isn't set up yet");
180 goto done;
183 if (lockf(lock_recent, F_LOCK, 0) < 0) {
184 PERROR_MESSAGE("lockf");
185 ERROR_MESSAGE("Cannot lock recent page");
186 goto done;
189 ret = 0;
190 done:
192 return ret;
196 * Release a lock for a board
198 * Preconditions:
200 * - board_idx represents a board.
202 * - The lock for board_idx is held in this program.
204 * Postconditions (success):
206 * - The lock for board_idx is now not held by this program.
208 int lock_release(size_t board_idx)
210 if (!lock_table ||
211 lock_table[board_idx] < 0) {
212 return 0;
215 if (lockf(lock_table[board_idx], F_ULOCK, 0) < 0) {
216 PERROR_MESSAGE("lockf");
217 ERROR_MESSAGE("Cannot release lock for board %zu", board_idx);
219 return -1;
222 return 0;
226 * Release a lock for a board
228 * Preconditions:
230 * - The lock for the recent page is held in this program.
232 * Postconditions (success):
234 * - The lock for the recent page is now not held by this program.
236 int lock_release_recent(void)
238 if (lock_recent < 0) {
239 return 0;
242 if (lockf(lock_recent, F_ULOCK, 0) < 0) {
243 PERROR_MESSAGE("lockf");
244 ERROR_MESSAGE("Cannot release lock for recent page");
246 return -1;
249 return 0;
253 * Clean up any memory from this file
255 * Postconditions (success):
257 * - Valgrind won't report any memory leaks from this file.
259 * - setup_locks() can be safely called again.
261 int clean_locks(void)
263 if (!lock_table) {
264 return 0;
267 for (size_t j = 0; j < lock_table_len; ++j) {
268 lock_release(j);
269 close(lock_table[j]);
272 free(lock_table);
273 lock_table = 0;
274 lock_release_recent();
275 close(lock_recent);
277 return 0;