diff options
author | Louis Yung-Chieh Lo <yjlou@chromium.org> | 2012-08-09 22:55:51 +0800 |
---|---|---|
committer | David Hendricks <dhendrix@chromium.org> | 2012-08-29 21:15:21 -0700 |
commit | 8c5acc23dc30cb8a38f3b6ee9e6c2227828eb4c9 (patch) | |
tree | 7ce622016fc3a0f0a023d1be28b8f80a62b5659f | |
parent | e96682c57994e9f42b8df71ae264610afa8a9aef (diff) | |
download | chrome-ec-8c5acc23dc30cb8a38f3b6ee9e6c2227828eb4c9.tar.gz |
Add GEC lock mechanism.
Basically re-use the gec lock code from flashrom package.
BUG=chrome-os-partner:12319
TEST=Build and run on link. Only build on snow.
while true; do ectool hello; done & ; run 10 instances.
; expect all instances runs okay.
Signed-off-by: Louis Yung-Chieh Lo <yjlou@chromium.org>
Change-Id: I11d5824f46810c6f5a04a564a81387cdea081697
Reviewed-on: https://gerrit.chromium.org/gerrit/29763
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/31787
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Tested-by: David Hendricks <dhendrix@chromium.org>
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | Makefile.rules | 3 | ||||
-rw-r--r-- | util/ectool.c | 20 | ||||
-rw-r--r-- | util/lock/build.mk | 9 | ||||
-rw-r--r-- | util/lock/csem.c | 279 | ||||
-rw-r--r-- | util/lock/csem.h | 154 | ||||
-rw-r--r-- | util/lock/gec_lock.c | 45 | ||||
-rw-r--r-- | util/lock/gec_lock.h | 51 | ||||
-rw-r--r-- | util/lock/ipc_lock.c | 106 | ||||
-rw-r--r-- | util/lock/ipc_lock.h | 71 | ||||
-rw-r--r-- | util/lock/locks.h | 47 |
11 files changed, 782 insertions, 4 deletions
@@ -37,6 +37,7 @@ include core/$(CORE)/build.mk include common/build.mk include test/build.mk include util/build.mk +include util/lock/build.mk includes+=$(includes-y) diff --git a/Makefile.rules b/Makefile.rules index 27d527f115..98adb101a7 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -119,7 +119,8 @@ $(out)/ec_version.h: $(filter-out $(out)/common/version.o,$(objs)) $(build-utils): $(out)/%:%.c $(call quiet,c_to_build,BUILDCC) -$(host-utils): $(out)/%:%.c $(foreach u,$(host-util-common),util/$(u).c) +$(host-utils): $(out)/%:%.c $(foreach u,$(host-util-common),util/$(u).c) \ + $(foreach u,$(util-lock-objs),util/lock/$(u).c) $(call quiet,c_to_host,HOSTCC ) $(out)/util/burn_my_ec: $(out)/$(PROJECT).bin diff --git a/util/ectool.c b/util/ectool.c index cdb5613794..a12bf2d9e7 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -14,6 +14,7 @@ #include "battery.h" #include "comm-host.h" #include "lightbar.h" +#include "lock/gec_lock.h" /* Handy tricks */ #define BUILD_ASSERT(cond) ((void)sizeof(char[1 - 2*!(cond)])) @@ -21,6 +22,7 @@ /* Don't use a macro where an inline will do... */ static inline int MIN(int a, int b) { return a < b ? a : b; } +#define GEC_LOCK_TIMEOUT_SECS 30 /* 30 secs */ const char help_str[] = "Commands:\n" @@ -2119,6 +2121,7 @@ const struct command commands[] = { int main(int argc, char *argv[]) { const struct command *cmd; + int rv; BUILD_ASSERT(ARRAY_SIZE(lb_command_paramcount) == LIGHTBAR_NUM_CMDS); @@ -2128,17 +2131,28 @@ int main(int argc, char *argv[]) return -2; } + if (acquire_gec_lock(GEC_LOCK_TIMEOUT_SECS) < 0) { + fprintf(stderr, "Could not acquire GEC lock.\n"); + return 1; + } + if (comm_init() < 0) return -3; /* Handle commands */ for (cmd = commands; cmd->name; cmd++) { - if (!strcasecmp(argv[1], cmd->name)) - return cmd->handler(argc - 1, argv + 1); + if (!strcasecmp(argv[1], cmd->name)) { + rv = cmd->handler(argc - 1, argv + 1); + goto out; + } } /* If we're still here, command was unknown */ fprintf(stderr, "Unknown command '%s'\n\n", argv[1]); print_help(argv[0]); - return -2; + rv = -2; + +out: + release_gec_lock(); + return rv; } diff --git a/util/lock/build.mk b/util/lock/build.mk new file mode 100644 index 0000000000..1b74bc4cea --- /dev/null +++ b/util/lock/build.mk @@ -0,0 +1,9 @@ +# -*- makefile -*- +# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Lock library +# + +util-lock-objs=csem ipc_lock gec_lock diff --git a/util/lock/csem.c b/util/lock/csem.c new file mode 100644 index 0000000000..a84cbbb2b1 --- /dev/null +++ b/util/lock/csem.c @@ -0,0 +1,279 @@ +/* + * 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(__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 new file mode 100644 index 0000000000..10a5c5ff94 --- /dev/null +++ b/util/lock/csem.h @@ -0,0 +1,154 @@ +/* + * 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 CSEM_H__ +#define 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 /* CSEM_H__ */ diff --git a/util/lock/gec_lock.c b/util/lock/gec_lock.c new file mode 100644 index 0000000000..4df231af3e --- /dev/null +++ b/util/lock/gec_lock.c @@ -0,0 +1,45 @@ +/* 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 "gec_lock.h" +#include "ipc_lock.h" +#include "locks.h" + +static struct ipc_lock gec_lock = IPC_LOCK_INIT(GECLOCK); + +int acquire_gec_lock(int timeout_secs) +{ + return acquire_lock(&gec_lock, timeout_secs * 1000); +} + +int release_gec_lock(void) +{ + return release_lock(&gec_lock); +} diff --git a/util/lock/gec_lock.h b/util/lock/gec_lock.h new file mode 100644 index 0000000000..13b0f9d92c --- /dev/null +++ b/util/lock/gec_lock.h @@ -0,0 +1,51 @@ +/* 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. + */ + +#ifndef GEC_LOCK_H__ +#define GEC_LOCK_H__ + +/* + * acquire_gec_lock - acquire global lock + * + * returns 0 to indicate lock acquired + * returns >0 to indicate lock was already held + * returns <0 to indicate failed to acquire lock + */ +extern int acquire_gec_lock(int timeout_secs); + +/* + * release_gec_lock - release global lock + * + * returns 0 if lock was released successfully + * returns -1 if lock had not been held before the call + */ +extern int release_gec_lock(void); + +#endif /* GEC_LOCK_H__ */ diff --git a/util/lock/ipc_lock.c b/util/lock/ipc_lock.c new file mode 100644 index 0000000000..5bc816c894 --- /dev/null +++ b/util/lock/ipc_lock.c @@ -0,0 +1,106 @@ +/* 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 new file mode 100644 index 0000000000..b85de286b7 --- /dev/null +++ b/util/lock/ipc_lock.h @@ -0,0 +1,71 @@ +/* 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. + */ + +#ifndef IPC_LOCK_H__ +#define IPC_LOCK_H__ + +#include <sys/ipc.h> + +struct ipc_lock { + key_t key; /* provided by the developer */ + int sem; /* internal */ + int is_held; /* internal */ +}; + +/* don't use C99 initializers here, so this can be used in C++ code */ +#define IPC_LOCK_INIT(key) \ + { \ + key, /* name */ \ + -1, /* sem */ \ + 0, /* is_held */ \ + } + +/* + * acquire_lock: acquire a lock + * + * timeout <0 = no timeout (try forever) + * timeout 0 = do not wait (return immediately) + * timeout >0 = wait up to $timeout milliseconds (subject to kernel scheduling) + * + * return 0 = lock acquired + * return >0 = lock was already held + * return <0 = failed to acquire lock + */ +extern int acquire_lock(struct ipc_lock *lock, int timeout_msecs); + +/* + * release_lock: release a lock + * + * returns 0 if lock was released successfully + * returns -1 if lock had not been held before the call + */ +extern int release_lock(struct ipc_lock *lock); + +#endif /* IPC_LOCK_H__ */ diff --git a/util/lock/locks.h b/util/lock/locks.h new file mode 100644 index 0000000000..39dfc933f3 --- /dev/null +++ b/util/lock/locks.h @@ -0,0 +1,47 @@ +/* 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. + */ + +#ifndef LOCKS_H__ +#define 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) + +#endif /* LOCKS_H__ */ |