diff options
author | David Hendricks <dhendrix@chromium.org> | 2016-02-25 16:30:41 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-03-01 14:53:50 -0800 |
commit | d89301b0360365306ea7b24751490847858e3646 (patch) | |
tree | b83165c2305ec593a7f8bed71800efd16b181863 /util | |
parent | afc76f1adf97d3a4039663e13afc457139d200fc (diff) | |
download | chrome-ec-d89301b0360365306ea7b24751490847858e3646.tar.gz |
Replace SysV semaphore lock with file lock
Some systems, such as Android, do not support SysV semaphore locks.
This implements an alternative file lock mechanism using flock().
flock() was chosen because it's pretty straight forward. It's known to
be broken when using NFS, but I doubt we'll ever store our lock on an
NFS volume.
CQ-DEPEND=CL:327407,CL:325609
BUG=chrome-os-partner:49527
BRANCH=none
TEST=tested on Smaug by running mosys and ectool while reading
firmware ROM with flashrom, all three utilities eventually
ran successfully.
Change-Id: Ic73fe0281fbc1dfaae1bb03e5683774a0c04ae5b
Signed-off-by: David Hendricks <dhendrix@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/329430
Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'util')
-rw-r--r-- | util/lock/build.mk | 2 | ||||
-rw-r--r-- | util/lock/csem.c | 275 | ||||
-rw-r--r-- | util/lock/csem.h | 154 | ||||
-rw-r--r-- | util/lock/file_lock.c | 251 | ||||
-rw-r--r-- | util/lock/gec_lock.c | 2 | ||||
-rw-r--r-- | util/lock/ipc_lock.c | 105 | ||||
-rw-r--r-- | util/lock/ipc_lock.h | 16 | ||||
-rw-r--r-- | util/lock/locks.h | 15 |
8 files changed, 263 insertions, 557 deletions
diff --git a/util/lock/build.mk b/util/lock/build.mk index 6cf595b995..48c152d830 100644 --- a/util/lock/build.mk +++ b/util/lock/build.mk @@ -6,5 +6,5 @@ # Lock library # -util-lock-objs=csem.o ipc_lock.o gec_lock.o +util-lock-objs=file_lock.o gec_lock.o util-lock-objs+=android.o diff --git a/util/lock/csem.c b/util/lock/csem.c deleted file mode 100644 index 2ad3d5d873..0000000000 --- a/util/lock/csem.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright 2003 Sun Microsystems, Inc. - * Copyright 2010 Google, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Developer's note: This was open sourced by Sun Microsystems, which got it - * via Cobalt Networks. It has been fairly extensively modified since then. - */ - -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif -#include <sys/types.h> -#include <sys/ipc.h> -#include <sys/sem.h> -#include <sys/stat.h> -#include <time.h> -#include <errno.h> -#include <sched.h> - -#include "csem.h" - -#if (defined(__BIONIC__) || defined(__GNU_LIBRARY__)) && !defined(_SEM_SEMUN_UNDEFINED) -/* union semun is defined by including <sys/sem.h> */ -#else -/* according to X/OPEN we have to define it ourselves */ -union semun { - int val; /* value for SETVAL */ - struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ - unsigned short int *array; /* array for GETALL, SETALL */ - struct seminfo *__buf; /* buffer for IPC_INFO */ -}; -#endif - -/* - * On some platforms semctl(SETVAL) sets sem_otime, on other platforms it - * does not. Figure out what this platform does. - * - * Returns 0 if semctl(SETVAL) does not set sem_otime - * Returns 1 if semctl(SETVAL) does set sem_otime - * Returns -1 on error - */ -static int does_semctl_set_otime(void) -{ - int sem_id; - int ret; - - /* create a test semaphore */ - sem_id = semget(IPC_PRIVATE, 1, S_IRUSR|S_IWUSR); - if (sem_id < 0) - return -1; - - /* set the value */ - if (csem_setval(sem_id, 1) < 0) { - csem_destroy(sem_id); - return -1; - } - - /* read sem_otime */ - ret = (csem_get_otime(sem_id) > 0) ? 1 : 0; - - /* clean up */ - csem_destroy(sem_id); - - return ret; -} - -int csem_create(key_t key, unsigned val) -{ - static int need_otime_hack = -1; - int sem_id; - - /* see if we need to trigger a semop to set sem_otime */ - if (need_otime_hack < 0) { - int ret = does_semctl_set_otime(); - if (ret < 0) - return -1; - - need_otime_hack = !ret; - } - - /* create it or fail */ - sem_id = semget(key, 1, IPC_CREAT|IPC_EXCL | S_IRUSR|S_IWUSR); - if (sem_id < 0) - return -1; - - /* initalize the value */ - if (need_otime_hack) - val++; - - if (csem_setval(sem_id, val) < 0) { - csem_destroy(sem_id); - return -1; - } - - if (need_otime_hack) { - /* force sem_otime to change */ - csem_down(sem_id); - } - - return sem_id; -} - -/* how many times to loop, waiting for sem_otime */ -#define MAX_OTIME_LOOPS 1000 - -int csem_get(key_t key) -{ - int sem_id; - int i; - - /* CSEM_PRIVATE needs to go through csem_create() to get an - * initial value */ - if (key == CSEM_PRIVATE) { - errno = EINVAL; - return -1; - } - - /* get the (assumed existing) semaphore */ - sem_id = semget(key, 1, S_IRUSR|S_IWUSR); - if (sem_id < 0) - return -1; - - /* loop until sem_otime != 0, which means it has been initialized */ - for (i = 0; i < MAX_OTIME_LOOPS; i++) { - time_t otime = csem_get_otime(sem_id); - if (otime < 0) { - /* error */ - return -1; - } - if (otime > 0) { - /* success */ - return sem_id; - } - /* retry */ - sched_yield(); - } - - /* fell through - error */ - return -1; -} - -int csem_get_or_create(key_t key, unsigned val) -{ - int sem_id; - - /* try to create the semaphore */ - sem_id = csem_create(key, val); - if (sem_id >= 0 || errno != EEXIST) { - /* it either succeeded or got an error */ - return sem_id; - } - - /* it must exist already - get it */ - sem_id = csem_get(key); - if (sem_id < 0) - return -1; - - return sem_id; -} - -int csem_destroy(int sem_id) -{ - return semctl(sem_id, 0, IPC_RMID); -} - -int csem_getval(int sem_id) -{ - return semctl(sem_id, 0, GETVAL); -} - -int csem_setval(int sem_id, unsigned val) -{ - union semun arg; - arg.val = val; - if (semctl(sem_id, 0, SETVAL, arg) < 0) - return -1; - - return 0; -} - -static int csem_up_undoflag(int sem_id, int undoflag) -{ - struct sembuf sops; - sops.sem_num = 0; - sops.sem_op = 1; - sops.sem_flg = undoflag; - return semop(sem_id, &sops, 1); -} - -int csem_up(int sem_id) -{ - return csem_up_undoflag(sem_id, 0); -} - -int csem_up_undo(int sem_id) -{ - return csem_up_undoflag(sem_id, SEM_UNDO); -} - -static int csem_down_undoflag(int sem_id, int undoflag) -{ - struct sembuf sops; - sops.sem_num = 0; - sops.sem_op = -1; - sops.sem_flg = undoflag; - return semop(sem_id, &sops, 1); -} - -int csem_down(int sem_id) -{ - return csem_down_undoflag(sem_id, 0); -} - -int csem_down_undo(int sem_id) -{ - return csem_down_undoflag(sem_id, SEM_UNDO); -} - -static int csem_down_timeout_undoflag(int sem_id, - struct timespec *timeout, - int undoflag) -{ - struct sembuf sops; - sops.sem_num = 0; - sops.sem_op = -1; - sops.sem_flg = undoflag; - return semtimedop(sem_id, &sops, 1, timeout); -} - -int csem_down_timeout(int sem_id, struct timespec *timeout) -{ - return csem_down_timeout_undoflag(sem_id, timeout, 0); -} - -int csem_down_timeout_undo(int sem_id, struct timespec *timeout) -{ - return csem_down_timeout_undoflag(sem_id, timeout, SEM_UNDO); -} - -time_t csem_get_otime(int sem_id) -{ - union semun arg; - struct semid_ds ds; - arg.buf = &ds; - if (semctl(sem_id, 0, IPC_STAT, arg) < 0) - return -1; - - return ds.sem_otime; -} diff --git a/util/lock/csem.h b/util/lock/csem.h deleted file mode 100644 index 469a824259..0000000000 --- a/util/lock/csem.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2003 Sun Microsystems, Inc. - * Copyright 2010 Google, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Developer's note: This was open sourced by Sun Microsystems, which got it - * via Cobalt Networks. It has been fairly extensively modified since then. - */ - -#ifndef __UTIL_CSEM_H -#define __UTIL_CSEM_H - -#include <sys/ipc.h> -#include <time.h> - -/* create a private key */ -#define CSEM_PRIVATE IPC_PRIVATE - -/* - * Create a new semaphore with the specified key, initialized to the - * specified value. If the key is CSEM_PRIVATE, a new private semaphore - * is allocated. - * - * Returns the sempahore ID (>= 0) on success. - * Returns < 0 on error, or if the key already exists. - */ -extern int csem_create(key_t key, unsigned val); - -/* - * Fetch an existing semaphore with the specified key. - * - * Returns the sempahore ID (>= 0) on success. - * Returns < 0 on error, or if the key does not exist. - */ -extern int csem_get(key_t key); - -/* - * Fetch or create a semaphore with the specified key. If the semaphore - * did not exist, it will be created with the specified value. - * - * Returns the sempahore ID (>= 0) on success. - * Returns < 0 on error. - */ -extern int csem_get_or_create(key_t key, unsigned val); - -/* - * Destroy the semaphore. - * - * Returns 0 on success. - * Returns < 0 on error. - */ -extern int csem_destroy(int sem_id); - -/* - * Get the value of the semaphore. - * - * Returns the value (>= 0) on success. - * Returns < 0 on error. - */ -extern int csem_getval(int sem_id); - -/* - * Set the value of the semaphore. - * - * Returns 0 on success. - * Returns < 0 on error. - */ -extern int csem_setval(int sem_id, unsigned val); - -/* - * Increment the semaphore. - * - * Returns 0 on success. - * Returns < 0 on error. - */ -extern int csem_up(int sem_id); - -/* - * Increment the semaphore. This operation will be undone when the - * process terminates. - * - * Returns 0 on success. - * Returns < 0 on error. - */ -extern int csem_up_undo(int sem_id); - -/* - * Decrement the semaphore, or block if sem == 0. - * - * Returns 0 on success. - * Returns < 0 on error. - */ -extern int csem_down(int sem_id); - -/* - * Decrement the semaphore, or block if sem == 0. This operation will be - * undone when the process terminates. - * - * Returns 0 on success. - * Returns < 0 on error. - */ -extern int csem_down_undo(int sem_id); - -/* - * Decrement the semaphore, or block with a timeout if sem == 0. - * - * Returns 0 on success. - * Returns < 0 on error. - */ -extern int csem_down_timeout(int sem_id, struct timespec *timeout); - -/* - * Decrement the semaphore, or block with a timeout if sem == 0. This - * operation will be undone when the process terminates. - * - * Returns 0 on success. - * Returns < 0 on error. - */ -extern int csem_down_timeout_undo(int sem_id, struct timespec *timeout); - -/* - * Get the timestamp of the last csem_up()/csem_down() call. - * - * Returns sem_otime on success. - * Returns < 0 on error - */ -extern time_t csem_get_otime(int sem_id); - -#endif /* __UTIL_CSEM_H */ diff --git a/util/lock/file_lock.c b/util/lock/file_lock.c new file mode 100644 index 0000000000..94f5991172 --- /dev/null +++ b/util/lock/file_lock.c @@ -0,0 +1,251 @@ +/* Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * file_lock.c: Implementation for a binary semaphore using a file lock. + * + * Warning: This relies on flock() which is known to be broken on NFS. + * + * The file will remain persistent once the lock has been used. Unfortunately, + * unlinking the file can introduce a race condition so we leave the file + * in place. + * + * The current process's PID will be written to the file for debug purposes. + */ + +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "android.h" +#include "ipc_lock.h" +#include "locks.h" + +#define SLEEP_INTERVAL_MS 50 + +static void msecs_to_timespec(int msecs, struct timespec *tmspec) +{ + tmspec->tv_sec = msecs / 1000; + tmspec->tv_nsec = (msecs % 1000) * 1000 * 1000; +} + +static int lock_is_held(struct ipc_lock *lock) +{ + return lock->is_held; +} + +static int file_lock_open_or_create(struct ipc_lock *lock) +{ + struct stat s; + char path[PATH_MAX]; + + if (in_android()) { + char *tmpdir; + + tmpdir = android_tmpdir_path(); + if (!tmpdir) + return -1; + + if (snprintf(path, sizeof(path), "%s/%s", + tmpdir, lock->filename) < 0) { + return -1; + } + } else { + if (snprintf(path, sizeof(path), "%s", SYSTEM_LOCKFILE_DIR) < 0) + return -1; + + if (lstat(path, &s) < 0) { + fprintf(stderr, "Cannot stat %s", path); + return -1; + } + + if (!S_ISDIR(s.st_mode)) { + fprintf(stderr, "%s is not a directory.\n", path); + return -1; + } + + if (strlen(path) + strlen(lock->filename) + 2 > PATH_MAX) { + fprintf(stderr, "Lockfile path too long.\n"); + return -1; + } + strcat(path, "/"); + strcat(path, lock->filename); + } + + lock->fd = open(path, O_RDWR | O_CREAT, 0600); + if (lock->fd < 0) { + fprintf(stderr, "Cannot open lockfile %s", path); + return -1; + } + + return 0; +} + +static int file_lock_get(struct ipc_lock *lock, int timeout_msecs) +{ + int msecs_remaining = timeout_msecs; + struct timespec sleep_interval, rem; + int ret = -1; + + if (timeout_msecs == 0) + return flock(lock->fd, LOCK_EX | LOCK_NB); + + msecs_to_timespec(SLEEP_INTERVAL_MS, &sleep_interval); + + while ((ret = flock(lock->fd, LOCK_EX | LOCK_NB)) != 0) { + if (errno != EWOULDBLOCK) { + fprintf(stderr, "Error obtaining lock"); + return -1; + } + + if (msecs_remaining < SLEEP_INTERVAL_MS) + msecs_to_timespec(msecs_remaining, &sleep_interval); + + while (nanosleep(&sleep_interval, &rem) != 0) { + if (errno == EINTR) { + sleep_interval = rem; + continue; + } else { + fprintf(stderr, "nanosleep() failed"); + return ret; + } + } + + if (timeout_msecs < 0) + continue; + + msecs_remaining -= SLEEP_INTERVAL_MS; + if (msecs_remaining < 0) + break; + } + + if (ret != 0) { + fprintf(stderr, "Timed out waiting for file lock.\n"); + return -1; + } + + return 0; +} + +static int file_lock_write_pid(struct ipc_lock *lock) +{ + ssize_t len; + /* + * PIDs are usually 5 digits, but we'll reserve enough room for + * a value of 2^32 (10 digits) out of paranoia. + */ + char pid_str[11]; + + if (ftruncate(lock->fd, 0) < 0) { + fprintf(stderr, "Cannot truncate lockfile"); + return -1; + } + + snprintf(pid_str, sizeof(pid_str), "%lu", (unsigned long)getpid()); + len = write(lock->fd, pid_str, strlen(pid_str)); + if (len < 0) { + fprintf(stderr, "Cannot write PID to lockfile"); + return -1; + } + + return 0; +} + +static void file_lock_release(struct ipc_lock *lock) +{ + if (flock(lock->fd, LOCK_UN) < 0) + fprintf(stderr, "Cannot release lock"); + + if (close(lock->fd) < 0) + fprintf(stderr, "Cannot close lockfile"); +} + +/* + * timeout <0 = no timeout (try forever) + * timeout 0 = do not wait (return immediately) + * timeout >0 = wait up to $timeout milliseconds + * + * returns 0 to indicate lock acquired + * returns >0 to indicate lock was already held + * returns <0 to indicate failed to acquire lock + */ +int acquire_lock(struct ipc_lock *lock, int timeout_msecs) +{ + /* check if it is already held */ + if (lock_is_held(lock)) + return 1; + + if (file_lock_open_or_create(lock)) + return -1; + + if (file_lock_get(lock, timeout_msecs)) { + lock->is_held = 0; + close(lock->fd); + return -1; + } else { + lock->is_held = 1; + } + + /* + * Write PID to lockfile for debug purposes. Failure to write to + * the file should not be considered fatal. There might be something + * bad happening with the filesystem, but the lock has already been + * obtained and we may need our tools for diagnostics and repairs + * so we should continue anyway. + */ + file_lock_write_pid(lock); + return 0; +} + +/* + * returns 0 if lock was released successfully + * returns -1 if lock had not been held before the call + */ +int release_lock(struct ipc_lock *lock) +{ + if (lock_is_held(lock)) { + file_lock_release(lock); + lock->is_held = 0; + return 0; + } + + return -1; +} diff --git a/util/lock/gec_lock.c b/util/lock/gec_lock.c index 4df231af3e..d354ea08f3 100644 --- a/util/lock/gec_lock.c +++ b/util/lock/gec_lock.c @@ -32,7 +32,7 @@ #include "ipc_lock.h" #include "locks.h" -static struct ipc_lock gec_lock = IPC_LOCK_INIT(GECLOCK); +static struct ipc_lock gec_lock = LOCKFILE_INIT(CROS_EC_LOCKFILE_NAME); int acquire_gec_lock(int timeout_secs) { diff --git a/util/lock/ipc_lock.c b/util/lock/ipc_lock.c deleted file mode 100644 index 790014e67b..0000000000 --- a/util/lock/ipc_lock.c +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright 2012, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <inttypes.h> -#include <stdio.h> -#include <time.h> - -#include "csem.h" -#include "ipc_lock.h" - -static int lock_init(struct ipc_lock *lock) -{ - if (lock->sem < 0) { - /* get or create the semaphore, init to 1 if needed */ - int sem = csem_get_or_create(lock->key, 1); - if (sem < 0) - return -1; - - lock->sem = sem; - } - return 0; -} - -static void msecs_to_timespec(int msecs, struct timespec *tmspec) -{ - tmspec->tv_sec = msecs / 1000; - tmspec->tv_nsec = (msecs % 1000) * 1000 * 1000; -} - -int acquire_lock(struct ipc_lock *lock, int timeout_msecs) -{ - int ret; - struct timespec timeout; - struct timespec *timeout_ptr; - - /* initialize the lock */ - if (lock_init(lock) < 0) { - fprintf(stderr, "%s(): failed to init lock 0x%08x\n", - __func__, (uint32_t)lock->key); - return -1; - } - - /* check if it is already held */ - if (lock->is_held) - return 1; - - /* calculate the timeout */ - if (timeout_msecs >= 0) { - timeout_ptr = &timeout; - msecs_to_timespec(timeout_msecs, timeout_ptr); - } else { - timeout_ptr = NULL; - } - - /* try to get the lock */ - ret = csem_down_timeout_undo(lock->sem, timeout_ptr); - if (ret < 0) { - fprintf(stderr, "%s(): failed to acquire lock 0x%08x\n", - __func__, (uint32_t)lock->key); - return -1; - } - - /* success */ - lock->is_held = 1; - return 0; -} - -int release_lock(struct ipc_lock *lock) -{ - if (lock->is_held) { - lock->is_held = 0; - csem_up_undo(lock->sem); - /* NOTE: do not destroy the semaphore, we want it to persist */ - return 0; - } - /* did not hold the lock */ - return -1; -} diff --git a/util/lock/ipc_lock.h b/util/lock/ipc_lock.h index 39ae277a7e..ca739ac04e 100644 --- a/util/lock/ipc_lock.h +++ b/util/lock/ipc_lock.h @@ -31,20 +31,18 @@ #ifndef __UTIL_IPC_LOCK_H #define __UTIL_IPC_LOCK_H -#include <sys/ipc.h> - struct ipc_lock { - key_t key; /* provided by the developer */ - int sem; /* internal */ - int is_held; /* internal */ + int is_held; /* internal */ + char *filename; /* provided by the developer */ + int fd; /* internal */ }; /* don't use C99 initializers here, so this can be used in C++ code */ -#define IPC_LOCK_INIT(key) \ +#define LOCKFILE_INIT(lockfile) \ { \ - key, /* name */ \ - -1, /* sem */ \ - 0, /* is_held */ \ + 0, /* is_held */ \ + lockfile, /* filename */ \ + -1, /* fd */ \ } /* diff --git a/util/lock/locks.h b/util/lock/locks.h index 74360883fd..e87c36d73b 100644 --- a/util/lock/locks.h +++ b/util/lock/locks.h @@ -31,17 +31,8 @@ #ifndef __UTIL_LOCKS_H #define __UTIL_LOCKS_H -/* this is the base key, since we have to pick something global */ -#define IPC_LOCK_KEY (0x67736c00 & 0xfffffc00) /* 22 bits "gsl" */ - -/* The ordering of the following keys matters a lot. We don't want to reorder - * keys and have a new binary dependent on deployed/used because it will break - * atomicity of existing users and binaries. In other words, DO NOT REORDER. */ - -/* this is the "big lock". */ -#define BIGLOCK (IPC_LOCK_KEY + 0) - -/* for Google EC */ -#define GECLOCK (IPC_LOCK_KEY + 1) +#define SYSTEM_LOCKFILE_DIR "/var/run/lock" +#define LOCKFILE_NAME "firmware_utility_lock" +#define CROS_EC_LOCKFILE_NAME "cros_ec_lock" #endif /* __UTIL_LOCKS_H */ |