diff --git a/ChangeLog b/ChangeLog index d8775e6..4569cdf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-08-31 11:13-EDT Gregory John Casamento + + * GNUmakefile + * synchronization.m: Added objc_sync_exit and objc_sync_enter. Support for + @synchronize. + 2007-04-21 Andrew Ruder * sendmsg.c (__objc_get_forward_imp): Call diff --git a/GNUmakefile b/GNUmakefile index 3544eb2..758285a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -85,6 +85,7 @@ libobjc_HEADER_FILES = \ libobjc_OBJC_FILES = \ Object.m \ Protocol.m \ + synchronization.m \ linking.m ifeq ($(GNUSTEP_TARGET_OS), cygwin) diff --git a/synchronization.m b/synchronization.m new file mode 100644 index 0000000..d9dbbef --- /dev/null +++ b/synchronization.m @@ -0,0 +1,243 @@ +/* + The implementation of synchronization primitives for Objective-C. + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GCC. + + Gregory Casamento + + GCC 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, or (at your option) any + later version. + + GCC 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 GCC; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/* + As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. +*/ + +#include +#include "objc/objc.h" +#include "objc/objc-api.h" +#include "objc/thr.h" + +/* + * Node structure... + */ +typedef struct lock_node { + id obj; + objc_mutex_t lock; + struct lock_node *next; + struct lock_node *prev; +} lock_node_t; + +/* + * Return types for the locks... + */ +typedef enum { + OBJC_SYNC_SUCCESS = 0, + OBJC_SYNC_NOT_OWNING_THREAD_ERROR = -1, + OBJC_SYNC_TIMED_OUT = -2, + OBJC_SYNC_NOT_INITIALIZED = -3 +} sync_return_t; + +static lock_node_t *lock_list = NULL; +static objc_mutex_t table_lock = NULL; + +/** + * Initialize the table lock. + */ +static void sync_lock_init() +{ + if(table_lock == NULL) + { + table_lock = objc_mutex_allocate(); + } +} + +/** + * Find the node in the list. + */ +lock_node_t* objc_sync_find_node(id obj) +{ + lock_node_t *current = NULL; + + if(lock_list != NULL) + { + // iterate over the list looking for the end... + while(current != NULL) + { + // if the current object is the one, breal and + // return that node. + if(current->obj == obj) + { + break; + } + + // get the next one... + current = current->next; + } + } + return current; +} + +/** + * Add a node for the object, if one doesn't already exist. + */ +lock_node_t* objc_sync_add_node(id obj) +{ + lock_node_t *current = NULL; + + // get the lock... + sync_lock_init(); + + // restrict access to the table.... + objc_mutex_lock(table_lock); + + // if the list hasn't been initialized, initialize it. + if(lock_list == NULL) + { + // instantiate the new node and set the list... + lock_list = malloc(sizeof(lock_node_t)); + + // set the current node to the last in the list... + current = lock_list; + + // set next and prev... + current->prev = NULL; + current->next = NULL; + } + else + { + lock_node_t *new_node = NULL; + current = lock_list; + + // look for the end of the list. + while(current->next) + { + current = current->next; + } + + // instantiate the new node... + new_node = malloc(sizeof(lock_node_t)); + + if(new_node != NULL) + { + // set next and prev... + current->next = new_node; + new_node->prev = current; + new_node->next = NULL; + + // set the current node to the last in the list... + current = new_node; + } + } + + if(current != NULL) + { + // add the object and it's lock + current->obj = obj; + current->lock = objc_mutex_allocate(); + } + + // release access to the table... + objc_mutex_unlock(table_lock); + + return current; +} + +/** + * Remove the node for the object if one does exist. + */ +lock_node_t* objc_sync_remove_node(id obj) +{ + lock_node_t *curr = NULL; + + // find the node... + curr = objc_sync_find_node(obj); + + // if the node is not null, proceed... + if(curr != NULL) + { + // skip the current node in + // the list and remove it from the + // prev and next nodes. + lock_node_t *prev = NULL; + lock_node_t *next = NULL; + + prev = curr->prev; + next = curr->next; + + next->prev = prev; + prev->next = next; + } + + // return the removed node... + return curr; +} + +/** + * Add a lock for the object. + */ +int objc_sync_enter(id obj) +{ + lock_node_t *node = NULL; + int status = 0; + + node = objc_sync_find_node(obj); + if(node == NULL) + { + node = objc_sync_add_node(obj); + if(node == NULL) + { + return OBJC_SYNC_NOT_INITIALIZED; + } + } + + status = objc_mutex_lock(node->lock); + if(status < 1) + { + return OBJC_SYNC_NOT_OWNING_THREAD_ERROR; + } + + return OBJC_SYNC_SUCCESS; +} + +/** + * Remove a lock for the object. + */ +int objc_sync_exit(id obj) +{ + lock_node_t *node = NULL; + int status = 0; + + node = objc_sync_remove_node(obj); + if(node == NULL) + { + return OBJC_SYNC_NOT_INITIALIZED; + } + + status = objc_mutex_unlock(node->lock); + if(status < 1) + { + return OBJC_SYNC_NOT_OWNING_THREAD_ERROR; + } + + // dealloc the node and return success. + free(node); + return OBJC_SYNC_SUCCESS; +}