/* GNU Objective C Runtime Thread Interface
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2009 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify it under the
+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.
+Foundation; either version 3, or (at your option) any later version.
-GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+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
-GNU CC; see the file COPYING. If not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
-/* 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 <stdlib.h>
-#include "runtime.h"
+#include "objc/runtime.h"
/* Global exit status. */
int __objc_thread_exit_status = 0;
it can be informed; for example, the GNUstep Base Library sets it
so it can implement the NSBecomingMultiThreaded notification.
*/
-objc_thread_callback objc_set_thread_callback(objc_thread_callback func)
+objc_thread_callback objc_set_thread_callback (objc_thread_callback func)
{
objc_thread_callback temp = _objc_became_multi_threaded;
_objc_became_multi_threaded = func;
id argument;
};
-static volatile void
-__objc_thread_detach_function(struct __objc_thread_start_state *istate)
+static void __attribute__((noreturn))
+__objc_thread_detach_function (struct __objc_thread_start_state *istate)
{
/* Valid state? */
if (istate) {
- id (*imp)(id,SEL,id);
+ id (*imp) (id, SEL, id);
SEL selector = istate->selector;
id object = istate->object;
id argument = istate->argument;
/* Don't need anymore so free it */
- objc_free(istate);
+ objc_free (istate);
/* Clear out the thread local storage */
- objc_thread_set_data(NULL);
+ objc_thread_set_data (NULL);
/* Check to see if we just became multi threaded */
- if (!__objc_is_multi_threaded)
+ if (! __objc_is_multi_threaded)
{
__objc_is_multi_threaded = 1;
/* Call the hook function */
if (_objc_became_multi_threaded != NULL)
- (*_objc_became_multi_threaded)();
+ (*_objc_became_multi_threaded) ();
}
/* Call the method */
- if ((imp = (id(*)(id, SEL, id))objc_msg_lookup(object, selector)))
- (*imp)(object, selector, argument);
+ if ((imp = (id (*) (id, SEL, id))objc_msg_lookup (object, selector)))
+ (*imp) (object, selector, argument);
else
- objc_error(object, OBJC_ERR_UNIMPLEMENTED,
- "objc_thread_detach called with bad selector.\n");
+ objc_error (object, OBJC_ERR_UNIMPLEMENTED,
+ "objc_thread_detach called with bad selector.\n");
}
else
- objc_error(nil, OBJC_ERR_BAD_STATE,
- "objc_thread_detach called with NULL state.\n");
+ objc_error (nil, OBJC_ERR_BAD_STATE,
+ "objc_thread_detach called with NULL state.\n");
/* Exit the thread */
- objc_thread_exit();
+ objc_thread_exit ();
+
+ /* Make sure compiler detects no return. */
+ __builtin_trap ();
}
/*
takes a single argument.
*/
objc_thread_t
-objc_thread_detach(SEL selector, id object, id argument)
+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))))
+ if (! (istate = (struct __objc_thread_start_state *)
+ objc_malloc (sizeof (*istate))))
return NULL;
/* Initialize the state structure */
istate->argument = argument;
/* lock access */
- objc_mutex_lock(__objc_runtime_mutex);
+ 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)
+ if ((thread_id = __objc_thread_detach ((void *)__objc_thread_detach_function,
+ istate)) == NULL)
{
/* failed! */
- objc_mutex_unlock(__objc_runtime_mutex);
- objc_free(istate);
+ 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);
+ objc_mutex_unlock (__objc_runtime_mutex);
return thread_id;
}
/* Set the current thread's priority. */
int
-objc_thread_set_priority(int priority)
+objc_thread_set_priority (int priority)
{
/* Call the backend */
- return __objc_thread_set_priority(priority);
+ return __objc_thread_set_priority (priority);
}
/* Return the current thread's priority. */
int
-objc_thread_get_priority(void)
+objc_thread_get_priority (void)
{
/* Call the backend */
- return __objc_thread_get_priority();
+ return __objc_thread_get_priority ();
}
/*
make progress even on a lazy uniprocessor system.
*/
void
-objc_thread_yield(void)
+objc_thread_yield (void)
{
/* Call the backend */
- __objc_thread_yield();
+ __objc_thread_yield ();
}
/*
Actually, if it failed returns -1.
*/
int
-objc_thread_exit(void)
+objc_thread_exit (void)
{
/* Decrement our counter of the number of threads alive */
- objc_mutex_lock(__objc_runtime_mutex);
+ objc_mutex_lock (__objc_runtime_mutex);
__objc_runtime_threads_alive--;
- objc_mutex_unlock(__objc_runtime_mutex);
+ objc_mutex_unlock (__objc_runtime_mutex);
/* Call the backend to terminate the thread */
- return __objc_thread_exit();
+ return __objc_thread_exit ();
}
/*
NULL which is reserved as a marker for "no thread".
*/
objc_thread_t
-objc_thread_id(void)
+objc_thread_id (void)
{
/* Call the backend */
- return __objc_thread_id();
+ return __objc_thread_id ();
}
/*
Returns 0 if successful or -1 if failed.
*/
int
-objc_thread_set_data(void *value)
+objc_thread_set_data (void *value)
{
/* Call the backend */
- return __objc_thread_set_data(value);
+ return __objc_thread_set_data (value);
}
/*
Returns the thread's local storage pointer. Returns NULL on failure.
*/
void *
-objc_thread_get_data(void)
+objc_thread_get_data (void)
{
/* Call the backend */
- return __objc_thread_get_data();
+ return __objc_thread_get_data ();
}
/* Frontend mutex functions */
allocation failed for any reason.
*/
objc_mutex_t
-objc_mutex_allocate(void)
+objc_mutex_allocate (void)
{
objc_mutex_t mutex;
/* Allocate the mutex structure */
- if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
+ if (! (mutex = (objc_mutex_t)objc_malloc (sizeof (struct objc_mutex))))
return NULL;
/* Call backend to create the mutex */
- if (__objc_mutex_allocate(mutex))
+ if (__objc_mutex_allocate (mutex))
{
/* failed! */
- objc_free(mutex);
+ objc_free (mutex);
return NULL;
}
Returns the number of locks on the thread. (1 for deallocate).
*/
int
-objc_mutex_deallocate(objc_mutex_t mutex)
+objc_mutex_deallocate (objc_mutex_t mutex)
{
int depth;
/* Valid mutex? */
- if (!mutex)
+ if (! mutex)
return -1;
/* Acquire lock on mutex */
- depth = objc_mutex_lock(mutex);
+ depth = objc_mutex_lock (mutex);
/* Call backend to destroy mutex */
- if (__objc_mutex_deallocate(mutex))
+ if (__objc_mutex_deallocate (mutex))
return -1;
/* Free the mutex structure */
- objc_free(mutex);
+ objc_free (mutex);
/* Return last depth */
return depth;
Returns the lock count on the mutex held by this thread.
*/
int
-objc_mutex_lock(objc_mutex_t mutex)
+objc_mutex_lock (objc_mutex_t mutex)
{
objc_thread_t thread_id;
int status;
/* Valid mutex? */
- if (!mutex)
+ if (! mutex)
return -1;
/* If we already own the lock then increment depth */
- thread_id = objc_thread_id();
+ thread_id = __objc_thread_id ();
if (mutex->owner == thread_id)
return ++mutex->depth;
/* Call the backend to lock the mutex */
- status = __objc_mutex_lock(mutex);
+ status = __objc_mutex_lock (mutex);
/* Failed? */
if (status)
thread has a lock on the mutex returns -1.
*/
int
-objc_mutex_trylock(objc_mutex_t mutex)
+objc_mutex_trylock (objc_mutex_t mutex)
{
objc_thread_t thread_id;
int status;
/* Valid mutex? */
- if (!mutex)
+ if (! mutex)
return -1;
/* If we already own the lock then increment depth */
- thread_id = objc_thread_id();
+ thread_id = __objc_thread_id ();
if (mutex->owner == thread_id)
return ++mutex->depth;
/* Call the backend to try to lock the mutex */
- status = __objc_mutex_trylock(mutex);
+ status = __objc_mutex_trylock (mutex);
/* Failed? */
if (status)
doesn't hold in which case return -1 and the mutex is unaffected.
*/
int
-objc_mutex_unlock(objc_mutex_t mutex)
+objc_mutex_unlock (objc_mutex_t mutex)
{
objc_thread_t thread_id;
int status;
/* Valid mutex? */
- if (!mutex)
+ if (! mutex)
return -1;
/* If another thread owns the lock then abort */
- thread_id = objc_thread_id();
+ thread_id = __objc_thread_id ();
if (mutex->owner != thread_id)
return -1;
mutex->owner = NULL;
/* Have the backend unlock the mutex */
- status = __objc_mutex_unlock(mutex);
+ status = __objc_mutex_unlock (mutex);
/* Failed? */
if (status)
if the allocation failed for any reason.
*/
objc_condition_t
-objc_condition_allocate(void)
+objc_condition_allocate (void)
{
objc_condition_t condition;
/* Allocate the condition mutex structure */
- if (!(condition =
- (objc_condition_t)objc_malloc(sizeof(struct objc_condition))))
+ if (! (condition =
+ (objc_condition_t) objc_malloc (sizeof (struct objc_condition))))
return NULL;
/* Call the backend to create the condition mutex */
- if (__objc_condition_allocate(condition))
+ if (__objc_condition_allocate (condition))
{
/* failed! */
- objc_free(condition);
+ objc_free (condition);
return NULL;
}
waiting but just wake them up.
*/
int
-objc_condition_deallocate(objc_condition_t condition)
+objc_condition_deallocate (objc_condition_t condition)
{
/* Broadcast the condition */
- if (objc_condition_broadcast(condition))
+ if (objc_condition_broadcast (condition))
return -1;
/* Call the backend to destroy */
- if (__objc_condition_deallocate(condition))
+ if (__objc_condition_deallocate (condition))
return -1;
/* Free the condition mutex structure */
- objc_free(condition);
+ objc_free (condition);
return 0;
}
/*
- Wait on the condition unlocking the mutex until objc_condition_signal()
- or objc_condition_broadcast() are called for the same condition. The
+ Wait on the condition unlocking the mutex until objc_condition_signal ()
+ or objc_condition_broadcast () are called for the same condition. The
given mutex *must* have the depth set to 1 so that it can be unlocked
here, so that someone else can lock it and signal/broadcast the condition.
The mutex is used to lock access to the shared data that make up the
"condition" predicate.
*/
int
-objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
+objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
{
objc_thread_t thread_id;
/* Valid arguments? */
- if (!mutex || !condition)
+ if (! mutex || ! condition)
return -1;
/* Make sure we are owner of mutex */
- thread_id = objc_thread_id();
+ thread_id = __objc_thread_id ();
if (mutex->owner != thread_id)
return -1;
mutex->owner = (objc_thread_t)NULL;
/* Call the backend to wait */
- __objc_condition_wait(condition, mutex);
+ __objc_condition_wait (condition, mutex);
/* Make ourselves owner of the mutex */
mutex->owner = thread_id;
right away after this call.
*/
int
-objc_condition_broadcast(objc_condition_t condition)
+objc_condition_broadcast (objc_condition_t condition)
{
/* Valid condition mutex? */
- if (!condition)
+ if (! condition)
return -1;
- return __objc_condition_broadcast(condition);
+ return __objc_condition_broadcast (condition);
}
/*
right away after this call.
*/
int
-objc_condition_signal(objc_condition_t condition)
+objc_condition_signal (objc_condition_t condition)
{
/* Valid condition mutex? */
- if (!condition)
+ if (! condition)
return -1;
- return __objc_condition_signal(condition);
+ return __objc_condition_signal (condition);
+}
+
+/* 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);
+}
+
+/* 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);
}
/* End of File */