From 14581937282486ab7ce057ec79f226181ef1d45d Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Tue, 8 Jan 2013 14:53:09 +0100 Subject: 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. --- Makefile.am | 3 + compat/darwin_compat.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++ compat/darwin_compat.h | 51 ++++++++++ configure.ac | 12 ++- sshfs.c | 3 +- 5 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 compat/darwin_compat.c create mode 100644 compat/darwin_compat.h diff --git a/Makefile.am b/Makefile.am index b43956c..078b2b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,6 +6,9 @@ sshfs_SOURCES = sshfs.c cache.c cache.h if FUSE_OPT_COMPAT sshfs_SOURCES += compat/fuse_opt.c compat/fuse_opt.h endif +if DARWIN_COMPAT +sshfs_SOURCES += compat/darwin_compat.c compat/darwin_compat.h +endif sshfs_LDADD = $(SSHFS_LIBS) sshfs_CFLAGS = $(SSHFS_CFLAGS) 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 +#include +#include + +/* + * Semaphore implementation based on: + * + * Copyright (C) 2000,02 Free Software Foundation, Inc. + * This file is part of the GNU C Library. + * Written by Gal Le Mignot + * + * 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; +} diff --git a/compat/darwin_compat.h b/compat/darwin_compat.h new file mode 100644 index 0000000..1cdbcce --- /dev/null +++ b/compat/darwin_compat.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006-2008 Amit Singh/Google Inc. + * Copyright (c) 2011-2012 Benjamin Fleischer + */ + +#ifndef _DARWIN_COMPAT_ +#define _DARWIN_COMPAT_ + +#include + +/* Semaphores */ + +struct __local_sem_t +{ + unsigned int count; + pthread_mutex_t count_lock; + pthread_cond_t count_cond; +}; + +typedef struct fuse_sem { + int id; + union { + struct __local_sem_t local; + } __data; +} darwin_sem_t; + +#define DARWIN_SEM_VALUE_MAX ((int32_t)32767) + +int darwin_sem_init(darwin_sem_t *sem, int pshared, unsigned int value); +int darwin_sem_destroy(darwin_sem_t *sem); +int darwin_sem_getvalue(darwin_sem_t *sem, unsigned int *value); +int darwin_sem_post(darwin_sem_t *sem); +int darwin_sem_timedwait(darwin_sem_t *sem, const struct timespec *abs_timeout); +int darwin_sem_trywait(darwin_sem_t *sem); +int darwin_sem_wait(darwin_sem_t *sem); + +/* Caller must not include */ + +typedef darwin_sem_t sem_t; + +#define sem_init(s, p, v) darwin_sem_init(s, p, v) +#define sem_destroy(s) darwin_sem_destroy(s) +#define sem_getvalue(s, v) darwin_sem_getvalue(s, v) +#define sem_post(s) darwin_sem_post(s) +#define sem_timedwait(s, t) darwin_sem_timedwait(s, t) +#define sem_trywait(s) darwin_sem_trywait(s) +#define sem_wait(s) darwin_sem_wait(s) + +#define SEM_VALUE_MAX DARWIN_SEM_VALUE_MAX + +#endif /* _DARWIN_COMPAT_ */ diff --git a/configure.ac b/configure.ac index d433038..b2556f2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,5 @@ AC_INIT(sshfs-fuse, 2.4) +AC_CANONICAL_TARGET AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) @@ -11,6 +12,14 @@ sshnodelay_libs=$LIBS AC_SUBST(sshnodelay_libs) LIBS= +case $target_os in + *linux*) arch=linux;; + *netbsd*) arch=netbsd;; + *bsd*) arch=bsd;; + *darwin*) arch=darwin;; + *) arch=unknown;; +esac + AC_ARG_ENABLE(sshnodelay, [ --disable-sshnodelay Don't compile NODELAY workaround for ssh]) @@ -43,10 +52,11 @@ oldlibs="$LIBS" LIBS="$LIBS $SSHFS_LIBS" AC_CHECK_FUNC([fuse_opt_parse], [have_fuse_opt_parse=yes]) LIBS="$oldlibs" -if test "$have_fuse_opt_parse" = no; then +if test "$have_fuse_opt_parse" = no -o "$arch" = darwin; then CFLAGS="$CFLAGS -Icompat" fi AM_CONDITIONAL(FUSE_OPT_COMPAT, test "$have_fuse_opt_parse" = no) +AM_CONDITIONAL(DARWIN_COMPAT, test "$arch" = darwin) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/sshfs.c b/sshfs.c index bf65aea..5658412 100644 --- a/sshfs.c +++ b/sshfs.c @@ -23,7 +23,7 @@ #include #include #include -#if !__APPLE__ +#ifndef __APPLE__ # include #endif #include @@ -46,6 +46,7 @@ #ifdef __APPLE__ # include # include +# include #endif #include "cache.h" -- cgit v1.2.3