static OBJCObjectFile *OBJCObjectFileWithPath(const char *path) { OBJCObjectFile *result = objc_calloc(1, sizeof(OBJCObjectFile)); result->path = objc_calloc(strlen(path) + 1, sizeof(char)); strcpy(result->path, path); result->moduleArray = OBJCArrayNew(); return result; }
int objc_sync_enter (id object) { #ifndef SYNC_CACHE_DISABLE int free_cache_slot; #endif int hash; lock_node_ptr node; lock_node_ptr unused_node; if (object == nil) return OBJC_SYNC_SUCCESS; #ifndef SYNC_CACHE_DISABLE if (lock_cache == NULL) { /* Note that this calloc only happen only once per thread, the very first time a thread does a objc_sync_enter(). */ lock_cache = objc_calloc (SYNC_CACHE_SIZE, sizeof (lock_node_ptr)); } /* Check the cache to see if we have a record of having already locked the lock corresponding to this object. While doing so, keep track of the first free cache node in case we need it later. */ node = NULL; free_cache_slot = -1; { int i; for (i = 0; i < SYNC_CACHE_SIZE; i++) { lock_node_ptr locked_node = lock_cache[i]; if (locked_node == NULL) { if (free_cache_slot == -1) free_cache_slot = i; } else if (locked_node->object == object) { node = locked_node; break; } } } if (node != NULL) { /* We found the lock. Increase recursive_usage_count, which is protected by node->lock, which we already hold. */ node->recursive_usage_count++; /* There is no need to actually lock anything, since we already hold the lock. Correspondingly, objc_sync_exit() will just decrease recursive_usage_count and do nothing to unlock. */ return OBJC_SYNC_SUCCESS; } #endif /* SYNC_CACHE_DISABLE */ /* The following is the standard lookup for the lock in the standard pool lock. It requires a pool protection lock. */ hash = SYNC_OBJECT_HASH(object); /* Search for an existing lock for 'object'. While searching, make note of any unused lock if we find any. */ unused_node = NULL; objc_mutex_lock (sync_pool_protection_locks[hash]); node = sync_pool_array[hash]; while (node != NULL) { if (node->object == object) { /* We found the lock. */ node->usage_count++; objc_mutex_unlock (sync_pool_protection_locks[hash]); #ifndef SYNC_CACHE_DISABLE /* Put it in the cache. */ if (free_cache_slot != -1) lock_cache[free_cache_slot] = node; #endif /* Lock it. */ objc_mutex_lock (node->lock); return OBJC_SYNC_SUCCESS; } if (unused_node == NULL && node->usage_count == 0) { /* We found the first unused node. Record it. */ unused_node = node; } node = node->next; } /* An existing lock for 'object' could not be found. */ if (unused_node != NULL) { /* But we found a unused lock; use it. */ unused_node->object = object; unused_node->usage_count = 1; unused_node->recursive_usage_count = 0; objc_mutex_unlock (sync_pool_protection_locks[hash]); #ifndef SYNC_CACHE_DISABLE if (free_cache_slot != -1) lock_cache[free_cache_slot] = unused_node; #endif objc_mutex_lock (unused_node->lock); return OBJC_SYNC_SUCCESS; } else { /* There are no unused nodes; allocate a new node. */ lock_node_ptr new_node; /* Create the node. */ new_node = objc_malloc (sizeof (struct lock_node)); new_node->lock = objc_mutex_allocate (); new_node->object = object; new_node->usage_count = 1; new_node->recursive_usage_count = 0; /* Attach it at the beginning of the pool. */ new_node->next = sync_pool_array[hash]; sync_pool_array[hash] = new_node; objc_mutex_unlock (sync_pool_protection_locks[hash]); #ifndef SYNC_CACHE_DISABLE if (free_cache_slot != -1) lock_cache[free_cache_slot] = new_node; #endif objc_mutex_lock (new_node->lock); return OBJC_SYNC_SUCCESS; } }