Hi,
I have attached a patch which adds a locking mechanism to Flashrom to
prevent multiple instances from running simultaneously. It may need some
modification to fit different Flashrom use cases better, but I think it's a
good start.
The size of the patch is somewhat misleading -- The only real changes to
Flashrom's current code are some of the exit points in cli_classic() and
some added stuff in the Makefile. Everything else is contained in new files.
The new files are:
csem.{c,h}: Low-level code that interfaces with semctl(), semget(), etc.
ipc_lock.{c,h}: Wrapper for csem stuff.
locks.h: A listing of locks that Flashrom cares about.
big_lock.{c,h}: An even higher-level wrapper around ipc_lock stuff, useful
for simple, coarse-grained locking.
util/use_big_lock.sh: Used by the Makefile to test for POSIX.1-2001
compliance.
The advantages of this approach are:
- The semaphore can be shared easily with other processes.
- The semaphore is cleaned automagically in case of abnormal program
termination.
- Semaphore info can be viewed and managed easily using standard utilities
like ipcs.
- On Linux at least, a second instance of Flashrom will automatically begin
immediately after the first instance is done. No busy waiting, no excessive
delays.
- We avoid errata with other locking mechanisms (there are known issues with
flock(), for example).
Disadvantages:
- The current patch is very coarse-grained, which could be problematic for
people who wish to flash multiple chips simultaneously.
- Requires >= POSIX.1-2001 compliance.
Please note that some files in this patch are BSD-licensed. Much of it is
based off code which was open-sourced by Sun Microsystems, after acquiring
it from Cobalt Networks.
Signed-off-by: David Hendricks <[email protected]>
--
David Hendricks (dhendrix)
Systems Software Engineer, Google Inc.
Index: big_lock.c
===================================================================
--- big_lock.c (revision 0)
+++ big_lock.c (revision 0)
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "big_lock.h"
+#include "locks.h"
+
+#include "ipc_lock.h"
+
+static struct ipc_lock big_lock = IPC_LOCK_INIT(BIGLOCK);
+
+int acquire_big_lock(int timeout_secs)
+{
+ return acquire_lock(&big_lock, timeout_secs * 1000);
+}
+
+int release_big_lock(void)
+{
+ return release_lock(&big_lock);
+}
Index: big_lock.h
===================================================================
--- big_lock.h (revision 0)
+++ big_lock.h (revision 0)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef BIG_LOCK_H__
+#define BIG_LOCK_H__
+
+/*
+ * acquire_big_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_big_lock(int timeout_secs);
+
+/*
+ * release_big_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_big_lock(void);
+
+#endif /* BIG_LOCK_H__ */
Index: Makefile
===================================================================
--- Makefile (revision 1257)
+++ Makefile (working copy)
@@ -88,6 +88,12 @@
LIB_OBJS = layout.o
+LOCK_OBJS = csem.o ipc_lock.o big_lock.o
+ifeq ($(shell ./util/use_big_lock.sh), 0)
+LIB_OBJS += $(LOCK_OBJS)
+FEATURE_CFLAGS += -D'USE_BIG_LOCK=1'
+endif
+
CLI_OBJS = flashrom.o cli_classic.o cli_output.o print.o
PROGRAMMER_OBJS = udelay.o programmer.o
Index: cli_classic.c
===================================================================
--- cli_classic.c (revision 1257)
+++ cli_classic.c (working copy)
@@ -27,10 +27,13 @@
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
+#include "big_lock.h"
#include "flash.h"
#include "flashchips.h"
#include "programmer.h"
+#define LOCK_TIMEOUT_SECS 30
+
static void cli_classic_usage(const char *name)
{
printf("Usage: flashrom [-n] [-V] [-f] [-h|-R|-L|"
@@ -112,7 +115,7 @@
int list_supported_wiki = 0;
#endif
int operation_specified = 0;
- int i;
+ int i, rc = 0;
static const char optstring[] = "r:Rw:v:nVEfc:m:l:i:p:Lzh";
static const struct option long_options[] = {
@@ -351,12 +354,24 @@
flash = NULL;
}
+#if USE_BIG_LOCK == 1
+ /* get lock before doing any work that touches hardware */
+ msg_gdbg("Acquiring lock (timeout=%d sec)...\n", LOCK_TIMEOUT_SECS);
+ if (acquire_big_lock(LOCK_TIMEOUT_SECS) < 0) {
+ msg_gerr("Could not acquire lock.\n");
+ rc = 1;
+ goto cli_exit;
+ }
+ msg_gdbg("Lock acquired.\n");
+#endif
+
/* FIXME: Delay calibration should happen in programmer code. */
myusec_calibrate_delay();
if (programmer_init(pparam)) {
fprintf(stderr, "Error: Programmer initialization failed.\n");
- exit(1);
+ rc = 1;
+ goto cli_exit;
}
/* FIXME: Delay calibration should happen in programmer code. */
@@ -374,7 +389,8 @@
printf(" %s", flashes[i]->name);
printf("\nPlease specify which chip to use with the -c <chipname> option.\n");
programmer_shutdown();
- exit(1);
+ rc = 1;
+ goto cli_exit;
} else if (!flashes[0]) {
printf("No EEPROM/flash device found.\n");
if (!force || !chip_to_probe) {
@@ -393,7 +409,8 @@
}
// FIXME: flash writes stay enabled!
programmer_shutdown();
- exit(1);
+ rc = 1;
+ goto cli_exit;
}
flash = flashes[0];
@@ -406,21 +423,24 @@
fprintf(stderr, "Chip is too big for this programmer "
"(-V gives details). Use --force to override.\n");
programmer_shutdown();
- return 1;
+ rc = 1;
+ goto cli_exit;
}
if (!(read_it | write_it | verify_it | erase_it)) {
printf("No operations were specified.\n");
// FIXME: flash writes stay enabled!
programmer_shutdown();
- exit(0);
+ rc = 0;
+ goto cli_exit;
}
if (!filename && !erase_it) {
printf("Error: No filename specified.\n");
// FIXME: flash writes stay enabled!
programmer_shutdown();
- exit(1);
+ rc = 1;
+ goto cli_exit;
}
/* Always verify write operations unless -n is used. */
@@ -432,5 +452,12 @@
* Give the chip time to settle.
*/
programmer_delay(100000);
- return doit(flash, force, filename, read_it, write_it, erase_it, verify_it);
+
+ rc = doit(flash, force, filename, read_it, write_it, erase_it, verify_it);
+
+cli_exit:
+#if USE_BIG_LOCK == 1
+ release_big_lock();
+#endif
+ return rc;
}
Index: locks.h
===================================================================
--- locks.h (revision 0)
+++ locks.h (revision 0)
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * locks.h: locks are used to preserve atomicity of operations.
+ */
+
+#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)
+
+#endif /* LOCKS_H__ */
Index: util/use_big_lock.sh
===================================================================
--- util/use_big_lock.sh (revision 0)
+++ util/use_big_lock.sh (revision 0)
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# Copyright (C) 2010 Google Inc.
+# Written by David Hendricks for Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# This script tests the availability of semctl() and similar functions by
+# checking that _POSIX_C_SOURCE indicates POSIX.1-2001 (or greaater) compliance.
+
+if [ -z $CC ]; then
+ CC=${CROSS_COMPILE}gcc
+fi
+
+echo "
+#include <stdlib.h>
+int main()\
+{
+#ifdef _POSIX_C_SOURCE
+ if ((long)_POSIX_C_SOURCE >= 200112)
+ exit(EXIT_SUCCESS);
+#endif
+ exit (EXIT_FAILURE);
+}
+" > .test.c
+
+${CC} -o .test .test.c && ./.test || exit 1
+rc=$?
+echo $rc
+
+rm -f .test
+exit $rc
Property changes on: util/use_big_lock.sh
___________________________________________________________________
Added: svn:executable
+ *
Index: ipc_lock.c
===================================================================
--- ipc_lock.c (revision 0)
+++ ipc_lock.c (revision 0)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <inttypes.h>
+#include <time.h>
+
+#include "csem.h"
+#include "flash.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) {
+ msg_gdbg("%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) {
+ msg_gdbg("%s(): failed to acquire lock 0x%08x",
+ __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;
+}
Index: csem.c
===================================================================
--- csem.c (revision 0)
+++ csem.c (revision 0)
@@ -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;
+}
Index: ipc_lock.h
===================================================================
--- ipc_lock.h (revision 0)
+++ ipc_lock.h (revision 0)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#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__ */
Index: csem.h
===================================================================
--- csem.h (revision 0)
+++ csem.h (revision 0)
@@ -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__ */
_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom