/* * 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; }