aboutsummaryrefslogtreecommitdiff
path: root/compat/darwin_compat.c
diff options
context:
space:
mode:
authorBenjamin Fleischer <fleiben@gmail.com>2013-01-08 14:53:09 +0100
committerBenjamin Fleischer <fleiben@gmail.com>2013-01-08 15:32:57 +0100
commit14581937282486ab7ce057ec79f226181ef1d45d (patch)
tree74dc8d75bcc78d1aae3f17d9975ebd9f0c60767c /compat/darwin_compat.c
parent66458931ddd09fc15244c5ddf3c1ec73e2fd08b9 (diff)
downloadsshfs-14581937282486ab7ce057ec79f226181ef1d45d.tar
sshfs-14581937282486ab7ce057ec79f226181ef1d45d.tar.gz
sshfs-14581937282486ab7ce057ec79f226181ef1d45d.tar.bz2
sshfs-14581937282486ab7ce057ec79f226181ef1d45d.zip
Add unnamed semaphore implementation for Mac OS X
In the past we relied on libosxfuse including a working unnamed semaphore implmentation for Mac OS X. This will not be the case in future releases of OSXFUSE, therefore we need to add our own implementation.
Diffstat (limited to 'compat/darwin_compat.c')
-rw-r--r--compat/darwin_compat.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/compat/darwin_compat.c b/compat/darwin_compat.c
new file mode 100644
index 0000000..3883ec6
--- /dev/null
+++ b/compat/darwin_compat.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2006-2008 Amit Singh/Google Inc.
+ * Copyright (c) 2012 Anatol Pomozov
+ * Copyright (c) 2011-2012 Benjamin Fleischer
+ */
+
+#include "darwin_compat.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+
+/*
+ * Semaphore implementation based on:
+ *
+ * Copyright (C) 2000,02 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ * Written by Ga<EB>l Le Mignot <address@hidden>
+ *
+ * The GNU C Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The GNU C Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU C Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Semaphores */
+
+#define __SEM_ID_NONE ((int)0x0)
+#define __SEM_ID_LOCAL ((int)0xcafef00d)
+
+/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_init.html */
+int
+darwin_sem_init(darwin_sem_t *sem, int pshared, unsigned int value)
+{
+ if (pshared) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ sem->id = __SEM_ID_NONE;
+
+ if (pthread_cond_init(&sem->__data.local.count_cond, NULL)) {
+ goto cond_init_fail;
+ }
+
+ if (pthread_mutex_init(&sem->__data.local.count_lock, NULL)) {
+ goto mutex_init_fail;
+ }
+
+ sem->__data.local.count = value;
+ sem->id = __SEM_ID_LOCAL;
+
+ return 0;
+
+mutex_init_fail:
+
+ pthread_cond_destroy(&sem->__data.local.count_cond);
+
+cond_init_fail:
+
+ return -1;
+}
+
+/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_destroy.html */
+int
+darwin_sem_destroy(darwin_sem_t *sem)
+{
+ int res = 0;
+
+ pthread_mutex_lock(&sem->__data.local.count_lock);
+
+ sem->id = __SEM_ID_NONE;
+ pthread_cond_broadcast(&sem->__data.local.count_cond);
+
+ if (pthread_cond_destroy(&sem->__data.local.count_cond)) {
+ res = -1;
+ }
+
+ pthread_mutex_unlock(&sem->__data.local.count_lock);
+
+ if (pthread_mutex_destroy(&sem->__data.local.count_lock)) {
+ res = -1;
+ }
+
+ return res;
+}
+
+int
+darwin_sem_getvalue(darwin_sem_t *sem, unsigned int *sval)
+{
+ int res = 0;
+
+ pthread_mutex_lock(&sem->__data.local.count_lock);
+
+ if (sem->id != __SEM_ID_LOCAL) {
+ res = -1;
+ errno = EINVAL;
+ } else {
+ *sval = sem->__data.local.count;
+ }
+
+ pthread_mutex_unlock(&sem->__data.local.count_lock);
+
+ return res;
+}
+
+/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_post.html */
+int
+darwin_sem_post(darwin_sem_t *sem)
+{
+ int res = 0;
+
+ pthread_mutex_lock(&sem->__data.local.count_lock);
+
+ if (sem->id != __SEM_ID_LOCAL) {
+ res = -1;
+ errno = EINVAL;
+ } else if (sem->__data.local.count < DARWIN_SEM_VALUE_MAX) {
+ sem->__data.local.count++;
+ if (sem->__data.local.count == 1) {
+ pthread_cond_signal(&sem->__data.local.count_cond);
+ }
+ } else {
+ errno = ERANGE;
+ res = -1;
+ }
+
+ pthread_mutex_unlock(&sem->__data.local.count_lock);
+
+ return res;
+}
+
+/* http://www.opengroup.org/onlinepubs/009695399/functions/sem_timedwait.html */
+int
+darwin_sem_timedwait(darwin_sem_t *sem, const struct timespec *abs_timeout)
+{
+ int res = 0;
+
+ if (abs_timeout &&
+ (abs_timeout->tv_nsec < 0 || abs_timeout->tv_nsec >= 1000000000)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ pthread_cleanup_push((void(*)(void*))&pthread_mutex_unlock,
+ &sem->__data.local.count_lock);
+
+ pthread_mutex_lock(&sem->__data.local.count_lock);
+
+ if (sem->id != __SEM_ID_LOCAL) {
+ errno = EINVAL;
+ res = -1;
+ } else {
+ if (!sem->__data.local.count) {
+ res = pthread_cond_timedwait(&sem->__data.local.count_cond,
+ &sem->__data.local.count_lock,
+ abs_timeout);
+ }
+ if (res) {
+ assert(res == ETIMEDOUT);
+ res = -1;
+ errno = ETIMEDOUT;
+ } else if (sem->id != __SEM_ID_LOCAL) {
+ res = -1;
+ errno = EINVAL;
+ } else {
+ sem->__data.local.count--;
+ }
+ }
+
+ pthread_cleanup_pop(1);
+
+ return res;
+}
+
+/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_trywait.html */
+int
+darwin_sem_trywait(darwin_sem_t *sem)
+{
+ int res = 0;
+
+ pthread_mutex_lock(&sem->__data.local.count_lock);
+
+ if (sem->id != __SEM_ID_LOCAL) {
+ res = -1;
+ errno = EINVAL;
+ } else if (sem->__data.local.count) {
+ sem->__data.local.count--;
+ } else {
+ res = -1;
+ errno = EAGAIN;
+ }
+
+ pthread_mutex_unlock (&sem->__data.local.count_lock);
+
+ return res;
+}
+
+/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_wait.html */
+int
+darwin_sem_wait(darwin_sem_t *sem)
+{
+ int res = 0;
+
+ pthread_cleanup_push((void(*)(void*))&pthread_mutex_unlock,
+ &sem->__data.local.count_lock);
+
+ pthread_mutex_lock(&sem->__data.local.count_lock);
+
+ if (sem->id != __SEM_ID_LOCAL) {
+ errno = EINVAL;
+ res = -1;
+ } else {
+ if (!sem->__data.local.count) {
+ pthread_cond_wait(&sem->__data.local.count_cond,
+ &sem->__data.local.count_lock);
+ if (!sem->__data.local.count) {
+ /* spurious wakeup, assume it is an interruption */
+ res = -1;
+ errno = EINTR;
+ goto out;
+ }
+ }
+ if (sem->id != __SEM_ID_LOCAL) {
+ res = -1;
+ errno = EINVAL;
+ } else {
+ sem->__data.local.count--;
+ }
+ }
+
+out:
+ pthread_cleanup_pop(1);
+
+ return res;
+}