Пример #1
0
/* Insert a class in the table (used when a new class is
   registered).  */
static void 
class_table_insert (const char *class_name, Class class_pointer)
{
  int hash, length;
  class_node_ptr new_node;

  /* Find out the class name's hash and length.  */
  CLASS_TABLE_HASH (length, hash, class_name);
  
  /* Prepare the new node holding the class.  */
  new_node = objc_malloc (sizeof (struct class_node));
  new_node->name = class_name;
  new_node->length = length;
  new_node->pointer = class_pointer;

  /* Lock the table for modifications.  */
  objc_mutex_lock (__class_table_lock);
  
  /* Insert the new node in the table at the beginning of the table at
     class_table_array[hash].  */
  new_node->next = class_table_array[hash];
  class_table_array[hash] = new_node;
  
  objc_mutex_unlock (__class_table_lock);
}
Пример #2
0
Файл: thr.c Проект: aosm/gcc3
/*
  Detach a new thread of execution and return its id.  Returns NULL if fails.
  Thread is started by sending message with selector to object.  Message
  takes a single argument.
  */
objc_thread_t
objc_thread_detach(SEL selector, id object, id argument)
{
  struct __objc_thread_start_state *istate;
  objc_thread_t        thread_id = NULL;

  /* Allocate the state structure */
  if (!(istate = (struct __objc_thread_start_state *)
	objc_malloc(sizeof(*istate))))
    return NULL;

  /* Initialize the state structure */
  istate->selector = selector;
  istate->object = object;
  istate->argument = argument;

  /* lock access */
  objc_mutex_lock(__objc_runtime_mutex);

  /* Call the backend to spawn the thread */
  if ((thread_id = __objc_thread_detach((void *)__objc_thread_detach_function,
					istate)) == NULL)
    {
      /* failed! */
      objc_mutex_unlock(__objc_runtime_mutex);
      objc_free(istate);
      return NULL;
    }

  /* Increment our thread counter */
  __objc_runtime_threads_alive++;
  objc_mutex_unlock(__objc_runtime_mutex);

  return thread_id;
}
Пример #3
0
void
method_exchangeImplementations (struct objc_method * method_a, struct objc_method * method_b)
{
  IMP old_implementation_a;
  IMP old_implementation_b;

  if (method_a == NULL  ||  method_b == NULL)
    return;

  /* We lock the runtime mutex so that concurrent calls to exchange
     similar methods won't conflict with each other.  Each of them
     should be atomic.  */
  objc_mutex_lock (__objc_runtime_mutex);

  old_implementation_a = method_a->method_imp;
  old_implementation_b = method_b->method_imp;

  method_a->method_imp = old_implementation_b;
  method_b->method_imp = old_implementation_a;

  /* That was easy :-).  But now we need to find all classes that use
     these methods, and update the IMP in the dispatch tables.  */
  __objc_update_classes_with_methods (method_a, method_b);

  objc_mutex_unlock (__objc_runtime_mutex);
}
Пример #4
0
Файл: class.c Проект: aosm/gcc3
/* Replace a class in the table (used only by poseAs:).  */
static void 
class_table_replace (Class old_class_pointer, Class new_class_pointer)
{
  int hash;
  class_node_ptr node;

  objc_mutex_lock (__class_table_lock);
  
  hash = 0;
  node = class_table_array[hash];
  
  while (hash < CLASS_TABLE_SIZE)
    {
      if (node == NULL)
        {
          hash++;
          if (hash < CLASS_TABLE_SIZE)
            {
              node = class_table_array[hash];
            }
        }
      else
        {
          Class class1 = node->pointer;

          if (class1 == old_class_pointer)
            {
              node->pointer = new_class_pointer;
            }
          node = node->next;
        }
    }

  objc_mutex_unlock (__class_table_lock);
}
Пример #5
0
BOOL 
class_addProtocol (Class class_, Protocol *protocol)
{
  struct objc_protocol_list *protocols;

  if (class_ == Nil  ||  protocol == NULL)
    return NO;

  if (class_conformsToProtocol (class_, protocol))
    return NO;

  /* Check that it is a Protocol object before casting it to (struct
     objc_protocol *).  */
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
    return NO;

  objc_mutex_lock (__objc_runtime_mutex);

  /* Create the objc_protocol_list.  */
  protocols = malloc (sizeof (struct objc_protocol_list));
  protocols->count = 1;
  protocols->list[0] = (struct objc_protocol *)protocol;

  /* Attach it to the list of class protocols.  */
  protocols->next = class_->protocols;
  class_->protocols = protocols;

  objc_mutex_unlock (__objc_runtime_mutex);

  return YES;
}
Пример #6
0
Файл: thr.c Проект: aosm/gcc3
/* Make the objc thread system aware that a thread managed (started,
   stopped) by some external code will no longer access objc and thus
   can be forgotten by the objc thread system.  Call
   objc_thread_remove() when your alien thread is done with making
   calls to Objective-C. */
void
objc_thread_remove(void)
{
  objc_mutex_lock(__objc_runtime_mutex);
  __objc_runtime_threads_alive--;
  objc_mutex_unlock(__objc_runtime_mutex);  
}
Пример #7
0
Файл: thr.c Проект: aosm/gcc3
/* Make the objc thread system aware that a thread which is managed
   (started, stopped) by external code could access objc facilities
   from now on.  This is used when you are interfacing with some
   external non-objc-based environment/system - you must call
   objc_thread_add() before an alien thread makes any calls to
   Objective-C.  Do not cause the _objc_became_multi_threaded hook to
   be executed. */
void 
objc_thread_add(void)
{
  objc_mutex_lock(__objc_runtime_mutex);
  __objc_is_multi_threaded = 1;
  __objc_runtime_threads_alive++;
  objc_mutex_unlock(__objc_runtime_mutex);  
}
Пример #8
0
Файл: thr.c Проект: aosm/gcc3
/*
  Terminate the current tread.  Doesn't return.
  Actually, if it failed returns -1.
  */
int
objc_thread_exit(void)
{
  /* Decrement our counter of the number of threads alive */
  objc_mutex_lock(__objc_runtime_mutex);
  __objc_runtime_threads_alive--;
  objc_mutex_unlock(__objc_runtime_mutex);

  /* Call the backend to terminate the thread */
  return __objc_thread_exit();
}
Пример #9
0
Файл: class.c Проект: aosm/gcc3
void __objc_init_class_tables()
{
  /* Allocate the class hash table.  */
  
  if(__class_table_lock)
    return;
  
  objc_mutex_lock(__objc_runtime_mutex);
  
  class_table_setup ();

  objc_mutex_unlock(__objc_runtime_mutex);
}  
Пример #10
0
Protocol *
objc_getProtocol (const char *name)
{
  Protocol *protocol;

  if (name == NULL)
    return NULL;

  objc_mutex_lock (__protocols_hashtable_lock);
  protocol = (Protocol *)(objc_hash_value_for_key (__protocols_hashtable, name));
  objc_mutex_unlock (__protocols_hashtable_lock);

  return protocol;
}
Пример #11
0
void __objc_init_class_tables()
{
  /* Allocate the class hash table */

  if(__objc_class_hash)
    return;

  objc_mutex_lock(__objc_runtime_mutex);

  __objc_class_hash
    =  hash_new (CLASS_HASH_SIZE,
		 (hash_func_type) hash_string,
		 (compare_func_type) compare_strings);

  objc_mutex_unlock(__objc_runtime_mutex);
}  
Пример #12
0
static void
sarray_free_garbage (void *vp)
{
  objc_mutex_lock (__objc_runtime_mutex);
  
  if (__objc_runtime_threads_alive == 1) {
    objc_free (vp);
    if (first_free_data)
      sarray_remove_garbage ();
  }
  else {
    *(void **)vp = first_free_data;
    first_free_data = vp;
  }
      
  objc_mutex_unlock (__objc_runtime_mutex);
}
Пример #13
0
/* This function removes any structures left over from free operations
   that were not safe in a multi-threaded environment. */
void
sarray_remove_garbage (void)
{
  void **vp;
  void *np;
  
  objc_mutex_lock (__objc_runtime_mutex);

  vp = first_free_data;
  first_free_data = NULL;

  while (vp) {
    np = *vp;
    objc_free (vp);
    vp = np;
  }
  
  objc_mutex_unlock (__objc_runtime_mutex);
}
Пример #14
0
/* Add a protocol to the hashtable.  */
void
__objc_protocols_add_protocol (const char *name, struct objc_protocol *object)
{
  objc_mutex_lock (__protocols_hashtable_lock);

  /* If we find a protocol with the same name already in the
     hashtable, we do not need to add the new one, because it will be
     identical to it.  This in the reasonable assumption that two
     protocols with the same name are identical, which is expected in
     any sane program.  If we are really paranoid, we would compare
     the protocols and abort if they are not identical.
     Unfortunately, this would slow down the startup of all
     Objective-C programs while trying to catch a problem that has
     never been seen in practice, so we don't do it.  */
  if (! objc_hash_is_key_in_hash (__protocols_hashtable, name))
    objc_hash_add (&__protocols_hashtable, name, object);

  objc_mutex_unlock (__protocols_hashtable_lock);
}
Пример #15
0
BOOL 
class_conformsToProtocol (Class class_, Protocol *protocol)
{
  struct objc_protocol_list* proto_list;

  if (class_ == Nil  ||  protocol == NULL)
    return NO;

  /* Check that it is a Protocol object before casting it to (struct
     objc_protocol *).  */
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
    return NO;

  /* Acquire the runtime lock because the list of protocols for a
     class may be modified concurrently, for example if another thread
     calls class_addProtocol(), or dynamically loads from a file a
     category of the class.  */
  objc_mutex_lock (__objc_runtime_mutex);
  proto_list = class_->protocols;

  while (proto_list)
    {
      size_t i;
      for (i = 0; i < proto_list->count; i++)
	{
	  if (proto_list->list[i] == (struct objc_protocol *)protocol
	      || protocol_conformsToProtocol ((Protocol *)proto_list->list[i],
					      protocol))
	    {
	      objc_mutex_unlock (__objc_runtime_mutex);
	      return YES;
	    }
	}
      proto_list = proto_list->next;
    }
  
  objc_mutex_unlock (__objc_runtime_mutex);
  return NO;
}
Пример #16
0
Файл: thr.c Проект: aosm/gcc3
/*
  Deallocate a mutex.  Note that this includes an implicit mutex_lock to
  insure that no one else is using the lock.  It is legal to deallocate
  a lock if we have a lock on it, but illegal to deallocate a lock held
  by anyone else.
  Returns the number of locks on the thread.  (1 for deallocate).
  */
int
objc_mutex_deallocate(objc_mutex_t mutex)
{
  int depth;

  /* Valid mutex? */
  if (!mutex)
    return -1;

  /* Acquire lock on mutex */
  depth = objc_mutex_lock(mutex);

  /* Call backend to destroy mutex */
  if (__objc_mutex_deallocate(mutex))
    return -1;

  /* Free the mutex structure */
  objc_free(mutex);

  /* Return last depth */
  return depth;
}
Пример #17
0
IMP
method_setImplementation (struct objc_method * method, IMP implementation)
{
  IMP old_implementation;

  if (method == NULL  ||  implementation == NULL)
    return NULL;

  /* We lock the runtime mutex so that concurrent calls to change the
     same method won't conflict with each other.  */
  objc_mutex_lock (__objc_runtime_mutex);

  old_implementation = method->method_imp;
  method->method_imp = implementation;

  /* That was easy :-).  But now we need to find all classes that use
     this method, and update the IMP in the dispatch tables.  */
  __objc_update_classes_with_methods (method, NULL);

  objc_mutex_unlock (__objc_runtime_mutex);

  return old_implementation;
}
Пример #18
0
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;
    }
}
Пример #19
0
int
objc_sync_exit (id object)
{
  int hash;
  lock_node_ptr node;

  if (object == nil)
    return OBJC_SYNC_SUCCESS;
  
#ifndef SYNC_CACHE_DISABLE
  if (lock_cache != NULL)
    {
      int i;
    
      /* Find the lock in the cache.  */
      node = NULL;
      for (i = 0; i < SYNC_CACHE_SIZE; i++)
	{
	  lock_node_ptr locked_node = lock_cache[i];
	  
	  if (locked_node != NULL  &&  locked_node->object == object)
	    {
	      node = locked_node;
	      break;
	    }
	}
      /* Note that, if a node was found in the cache, the variable i
	 now holds the index where it was found, which will be used to
	 remove it from the cache.  */
      if (node != NULL)
	{
	  if (node->recursive_usage_count > 0)
	    {
	      node->recursive_usage_count--;
	      return OBJC_SYNC_SUCCESS;
	    }
	  else
	    {
	      /* We need to do a real unlock.  */
	      hash = SYNC_OBJECT_HASH(object);
	      
	      /* TODO: If we had atomic increase/decrease operations
		 with memory barriers, we could avoid the lock
		 here!  */
	      objc_mutex_lock (sync_pool_protection_locks[hash]);
	      node->usage_count--;
	      /* Normally, we do not reset object to nil here.  We'll
		 leave the lock associated with that object, at zero
		 usage count.  This makes it slightly more efficient to
		 provide a lock for that object if (as likely)
		 requested again.  If the object is deallocated, we
		 don't care.  It will never match a new lock that is
		 requested, and the node will be reused at some point.

		 But, if garbage collection is enabled, leaving a
		 pointer to the object in memory might prevent the
		 object from being released.  In that case, we remove
		 it (TODO: maybe we should avoid using the garbage
		 collector at all ?  Nothing is ever deallocated in
		 this file).  */
#if OBJC_WITH_GC
	      node->object = nil;
#endif
	      objc_mutex_unlock (sync_pool_protection_locks[hash]);
	    
	      /* PS: Between objc_mutex_unlock
		 (sync_pool_protection_locks[hash]) and
		 objc_mutex_unlock (node->lock), the pool is unlocked
		 so other threads may allocate this same lock to
		 another object (!).  This is not a problem, but it is
		 curious.  */
	      objc_mutex_unlock (node->lock);
	      
	      /* Remove the node from the cache.  */
	      lock_cache[i] = NULL;
	      
	      return OBJC_SYNC_SUCCESS;
	    }
	}
    }
#endif	  

  /* The cache either wasn't there, or didn't work (eg, we overflowed
     it at some point and stopped recording new locks in the cache).
     Proceed with a full search of the lock pool.  */
  hash = SYNC_OBJECT_HASH(object);

  objc_mutex_lock (sync_pool_protection_locks[hash]);

  /* Search for an existing lock for 'object'.  */
  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]);

	  objc_mutex_unlock (node->lock);

	  /* No need to remove the node from the cache, since it
	     wasn't found in the cache when we looked for it!  */
	  return OBJC_SYNC_SUCCESS;
	}
      
      node = node->next;
    }

  objc_mutex_unlock (sync_pool_protection_locks[hash]);

  /* A lock for 'object' to unlock could not be found (!!).  */
  return OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
}