Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -137,10 +137,12 @@ OBJCFLAGS="$OBJCFLAGS -fno-constant-cfstrings"]) AC_SUBST(NO_CONST_CFSTRINGS) AC_CHECK_HEADER(objc/runtime.h, [AC_DEFINE(HAVE_OBJC_RUNTIME_H, 1, [Whether we have objc/runtime.h])]) + +AC_CHECK_FUNC(objc_sync_enter,, AC_SUBST(OBJC_SYNC_M, "objc_sync.m")) test x"$GCC" = x"yes" && CFLAGS="$CFLAGS -Werror" if test x"$GOBJC" = x"yes"; then old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -Werror" Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -1,6 +1,7 @@ ASPRINTF_C = @ASPRINTF_C@ +OBJC_SYNC_M = @OBJC_SYNC_M@ OFPLUGIN = @OFPLUGIN@ OFPLUGIN_M = @OFPLUGIN_M@ WS2_LIBS = @WS2_LIBS@ TESTS = @TESTS@ TEST_LAUNCHER = @TEST_LAUNCHER@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -27,16 +27,18 @@ OFThread.m \ OFURLEncoding.m \ OFXMLFactory.m \ ${ASPRINTF_C} -INCLUDESTMP = ${SRCS:.c=.h} -INCLUDES = ${INCLUDESTMP:.m=.h} \ +INCLUDESTMP := ${SRCS:.c=.h} +INCLUDES := ${INCLUDESTMP:.m=.h} \ OFMacros.h + +SRCS += ${OBJC_SYNC_M} include ../buildsys.mk CPPFLAGS += -I.. CFLAGS += ${LIB_CFLAGS} OBJCFLAGS += ${LIB_CFLAGS} LD = ${OBJC} LDFLAGS += ${LIB_LDFLAGS} ADDED src/objc_sync.m Index: src/objc_sync.m ================================================================== --- src/objc_sync.m +++ src/objc_sync.m @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#include "config.h" + +#include +#include + +#ifndef _WIN32 +#include +#else +#include +#endif + +struct locks_s { + id obj; + size_t count; + size_t recursion; +#ifndef _WIN32 + pthread_t thread; + pthread_mutex_t mutex; +#else + HANDLE thread; + HANDLE mutex; +#endif +}; + +static int initialized = 0; +#ifndef _WIN32 +static pthread_mutex_t mutex; +#else +static HANDLE mutex; +#endif +static struct locks_s *locks = NULL; +static size_t num_locks = 0; + +int +objc_sync_enter(id obj) +{ + size_t i; + + /* + * FIXME: + * Theoretically, it's possible to encounter a race condition during + * initialization. + */ + if (!initialized) { +#ifndef _WIN32 + if (pthread_mutex_init(&mutex, NULL)) +#else + if ((mutex = CreateMutex(NULL, FALSE, NULL)) == NULL) +#endif + return 1; + + initialized = 1; + } + +#ifndef _WIN32 + if (pthread_mutex_lock(&mutex)) +#else + if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) + return 1; +#endif + + for (i = 0; i < num_locks; i++) { + if (locks[i].obj == obj) { +#ifndef _WIN32 + if (pthread_equal(pthread_self(), locks[i].thread)) +#else + if (locks[i].thread == GetCurrentThread()) +#endif + locks[i].recursion++; + else +#ifndef _WIN32 + if (pthread_mutex_lock(&locks[i].mutex)) { + pthread_mutex_unlock(&mutex); + return 1; + } +#else + if (WaitForSingleObject(locks[i].mutex, + INFINITE) != WAIT_OBJECT_0) { + ReleaseMutex(mutex); + return 1; + } +#endif + + locks[i].count++; + +#ifndef _WIN32 + if (pthread_mutex_unlock(&locks[i].mutex)) +#else + if (!ReleaseMutex(mutex)) +#endif + return 1; + + return 0; + } + } + + if (locks == NULL) { + if ((locks = malloc(sizeof(struct locks_s))) == NULL) { +#ifndef _WIN32 + pthread_mutex_unlock(&mutex); +#else + ReleaseMutex(mutex); +#endif + return 1; + } + } else { + struct locks_s *new_locks; + + if ((new_locks = realloc(locks, (num_locks + 1) * + sizeof(struct locks_s))) == NULL) { +#ifndef _WIN32 + pthread_mutex_unlock(&mutex); +#else + ReleaseMutex(mutex); +#endif + return 1; + } + + locks = new_locks; + } + + locks[num_locks].obj = obj; + locks[num_locks].count = 1; + locks[num_locks].recursion = 0; + +#ifndef _WIN32 + locks[num_locks].thread = pthread_self(); + + if (pthread_mutex_init(&locks[num_locks].mutex, NULL)) { + pthread_mutex_unlock(&mutex); + return 1; + } + + if (pthread_mutex_lock(&locks[num_locks].mutex)) { + pthread_mutex_unlock(&mutex); + return 1; + } +#else + locks[num_locks].thread = GetCurrentThread(); + + if ((locks[num_locks].mutex = CreateMutex(NULL, TRUE, NULL)) == NULL) { + ReleaseMutex(mutex); + return 1; + } +#endif + + num_locks++; + +#ifndef _WIN32 + if (pthread_mutex_unlock(&mutex)) +#else + if (!ReleaseMutex(mutex)) +#endif + return 1; + + return 0; +} + +int +objc_sync_exit(id obj) +{ + size_t i; + +#ifndef _WIN32 + if (pthread_mutex_lock(&mutex)) +#else + if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) + return 1; +#endif + + for (i = 0; i < num_locks; i++) { + if (locks[i].obj == obj) { +#ifndef _WIN32 + if (pthread_equal(pthread_self(), locks[i].thread) && + locks[i].recursion) { + locks[i].recursion--; + + if (pthread_mutex_unlock(&mutex)) + return 1; + + return 0; + } +#else + if (locks[i].thread == GetCurrentThread() && + locks[i].recursion) { + locks[i].recursion--; + + if (!ReleaseMutex(mutex)) + return 1; + + return 0; + } +#endif + +#ifndef _WIN32 + if (pthread_mutex_unlock(&locks[i].mutex)) { + pthread_mutex_unlock(&mutex); + return 1; + } +#else + if (!ReleaseMutex(locks[i].mutex)) { + ReleaseMutex(mutex); + return 1; + } +#endif + + locks[i].count--; + + if (locks[i].count == 0) { + struct locks_s *new_locks; + +#ifndef _WIN32 + if (pthread_mutex_destroy(&locks[i].mutex)) { + pthread_mutex_unlock(&mutex); + return 1; + } +#else + if (!CloseHandle(locks[i].mutex)) { + ReleaseMutex(mutex); + return 1; + } +#endif + + num_locks--; + locks[i] = locks[num_locks]; + + if ((new_locks = realloc(locks, (num_locks) * + sizeof(struct locks_s))) == NULL) { +#ifndef _WIN32 + pthread_mutex_unlock(&mutex); +#else + ReleaseMutex(mutex); +#endif + return 1; + } + + locks = new_locks; + } + +#ifndef _WIN32 + if (pthread_mutex_unlock(&mutex)) +#else + if (!ReleaseMutex(mutex)) +#endif + return 1; + + return 0; + } + } + +#ifndef _WIN32 + pthread_mutex_unlock(&mutex); +#else + ReleaseMutex(mutex); +#endif + + return 1; +}