summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Yung-Chieh Lo <yjlou@chromium.org>2012-08-09 22:55:51 +0800
committerYung-Chieh Lo <yjlou@chromium.org>2012-08-21 23:36:56 -0700
commit8cecc9278d7aba8c8d04bc7d518b8a9bc6ae8d79 (patch)
treef56a82c775c9233268324d31bfdc143630dd07bc
parentb383d4c6b8218300c14c6f853853cc09ea761c9d (diff)
downloadchrome-ec-8cecc9278d7aba8c8d04bc7d518b8a9bc6ae8d79.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> Original-Change-Id: I11d5824f46810c6f5a04a564a81387cdea081697 Reviewed-on: https://gerrit.chromium.org/gerrit/29763 Reviewed-by: Randall Spangler <rspangler@chromium.org> (cherry picked from commit 03d4ed278de2a27a9c2c580ad4d68e30dbcc7630) Change-Id: Id38ea63e9dc36f13455af5c55f5aeb40571ce00c Reviewed-on: https://gerrit.chromium.org/gerrit/31092 Reviewed-by: Yung-Chieh Lo <yjlou@chromium.org> Tested-by: Yung-Chieh Lo <yjlou@chromium.org>
-rw-r--r--Makefile1
-rw-r--r--Makefile.rules3
-rw-r--r--util/ectool.c20
-rw-r--r--util/lock/build.mk9
-rw-r--r--util/lock/csem.c279
-rw-r--r--util/lock/csem.h154
-rw-r--r--util/lock/gec_lock.c45
-rw-r--r--util/lock/gec_lock.h51
-rw-r--r--util/lock/ipc_lock.c106
-rw-r--r--util/lock/ipc_lock.h71
-rw-r--r--util/lock/locks.h47
11 files changed, 782 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 80566276e2..bf96bbe9be 100644
--- a/Makefile
+++ b/Makefile
@@ -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 e15bd8a0ec..3acedb0d5c 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"
#include "vboot.h"
/* Handy tricks */
@@ -22,6 +23,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"
@@ -2151,6 +2153,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);
BUILD_ASSERT(ARRAY_SIZE(vb_command_paramcount) == VBOOT_NUM_CMDS);
@@ -2161,17 +2164,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__ */