1/* 2 The implementation of synchronization primitives for Objective-C. 3 Copyright (C) 2008 Free Software Foundation, Inc. 4 5 Gregory Casamento <greg.casamento@gmail.com> 6 7 This file is part of the GNUstep Base Library. 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Library General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with this library; if not, write to the Free 21 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 Boston, MA 02111 USA. 23*/ 24 25#include <stdlib.h> 26#include "objc/objc.h" 27#include "objc/objc-api.h" 28#include "objc/thr.h" 29 30/* 31 * Node structure... 32 */ 33typedef struct lock_node { 34 id obj; 35 objc_mutex_t lock; 36 struct lock_node *next; 37 struct lock_node *prev; 38} lock_node_t; 39 40/* 41 * Return types for the locks... 42 */ 43typedef enum { 44 OBJC_SYNC_SUCCESS = 0, 45 OBJC_SYNC_NOT_OWNING_THREAD_ERROR = -1, 46 OBJC_SYNC_TIMED_OUT = -2, 47 OBJC_SYNC_NOT_INITIALIZED = -3 48} sync_return_t; 49 50static lock_node_t *lock_list = NULL; 51static objc_mutex_t table_lock = NULL; 52 53/** 54 * Initialize the table lock. 55 */ 56static void 57sync_lock_init() 58{ 59 if (table_lock == NULL) 60 { 61 table_lock = objc_mutex_allocate(); 62 } 63} 64 65/** 66 * Find the node in the list. 67 */ 68static lock_node_t* 69sync_find_node(id obj) 70{ 71 lock_node_t *current = lock_list; 72 73 if (lock_list != NULL) 74 { 75 // iterate over the list looking for the end... 76 while (current != NULL) 77 { 78 // if the current object is the one, breal and 79 // return that node. 80 if (current->obj == obj) 81 { 82 break; 83 } 84 85 // get the next one... 86 current = current->next; 87 } 88 } 89 return current; 90} 91 92/** 93 * Add a node for the object, if one doesn't already exist. 94 */ 95static lock_node_t* 96sync_add_node(id obj) 97{ 98 lock_node_t *current = NULL; 99 100 // get the lock... 101 sync_lock_init(); 102 103 // if the list hasn't been initialized, initialize it. 104 if (lock_list == NULL) 105 { 106 // instantiate the new node and set the list... 107 lock_list = malloc(sizeof(lock_node_t)); 108 109 // set the current node to the last in the list... 110 current = lock_list; 111 112 // set next and prev... 113 current->prev = NULL; 114 current->next = NULL; 115 } 116 else 117 { 118 lock_node_t *new_node = NULL; 119 current = lock_list; 120 121 // look for the end of the list. 122 while (current->next) 123 { 124 current = current->next; 125 } 126 127 // instantiate the new node... 128 new_node = malloc(sizeof(lock_node_t)); 129 130 if (new_node != NULL) 131 { 132 // set next and prev... 133 current->next = new_node; 134 new_node->prev = current; 135 new_node->next = NULL; 136 137 // set the current node to the last in the list... 138 current = new_node; 139 } 140 } 141 142 if (current != NULL) 143 { 144 // add the object and it's lock 145 current->obj = obj; 146 current->lock = objc_mutex_allocate(); 147 } 148 149 return current; 150} 151 152/** 153 * Add a lock for the object. 154 */ 155int 156objc_sync_enter(id obj) 157{ 158 lock_node_t *node = NULL; 159 int status = 0; 160 161 // lock access to the table until we're done.... 162 sync_lock_init(); 163 objc_mutex_lock(table_lock); 164 165 node = sync_find_node(obj); 166 if (node == NULL) 167 { 168 node = sync_add_node(obj); 169 if (node == NULL) 170 { 171 // unlock the table.... 172 objc_mutex_unlock(table_lock); 173 return OBJC_SYNC_NOT_INITIALIZED; 174 } 175 } 176 177 // unlock the table.... 178 objc_mutex_unlock(table_lock); 179 180 status = objc_mutex_lock(node->lock); 181 182 // if the status is more than one, then another thread 183 // has this section locked, so we abort. A status of -1 184 // indicates that an error occurred. 185 if (status > 1 || status == -1) 186 { 187 return OBJC_SYNC_NOT_OWNING_THREAD_ERROR; 188 } 189 190 return OBJC_SYNC_SUCCESS; 191} 192 193/** 194 * Remove a lock for the object. 195 */ 196int 197objc_sync_exit(id obj) 198{ 199 lock_node_t *node = NULL; 200 int status = 0; 201 202 // lock access to the table until we're done.... 203 sync_lock_init(); 204 objc_mutex_lock(table_lock); 205 206 node = sync_find_node(obj); 207 if (node == NULL) 208 { 209 // unlock the table.... 210 objc_mutex_unlock(table_lock); 211 return OBJC_SYNC_NOT_INITIALIZED; 212 } 213 214 status = objc_mutex_unlock(node->lock); 215 216 // unlock the table.... 217 objc_mutex_unlock(table_lock); 218 219 // if the status is not zero, then we are not the sole 220 // owner of this node. Also if -1 is returned, this indicates and error 221 // condition. 222 if (status > 0 || status == -1) 223 { 224 return OBJC_SYNC_NOT_OWNING_THREAD_ERROR; 225 } 226 227 return OBJC_SYNC_SUCCESS; 228} 229 230