Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
2024f9e4
Commit
2024f9e4
authored
Jun 25, 1997
by
Richard Kenner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Completely rework according to new interface.
From-SVN: r14310
parent
f15e9e7e
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1632 additions
and
2198 deletions
+1632
-2198
gcc/objc/thr-decosf1.c
+170
-215
gcc/objc/thr-irix.c
+137
-216
gcc/objc/thr-mach.c
+170
-322
gcc/objc/thr-os2.c
+116
-190
gcc/objc/thr-posix.c
+114
-226
gcc/objc/thr-pthreads.c
+77
-277
gcc/objc/thr-single.c
+118
-166
gcc/objc/thr-solaris.c
+128
-300
gcc/objc/thr-win32.c
+159
-224
gcc/objc/thr.c
+443
-62
No files found.
gcc/objc/thr-decosf1.c
View file @
2024f9e4
...
...
@@ -28,299 +28,254 @@ Boston, MA 02111-1307, USA. */
#include <objc/thr.h>
#include "runtime.h"
/********
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct
objc_mutex
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
pthread_mutex_t
lock
;
/* pthread mutex. */
};
/*****************************************************************************
* Static variables.
*/
static
pthread_key_t
__objc_thread_data_key
;
/* Data key for thread data.*/
/* Key structure for maintiain thread specific storage */
static
pthread_key_t
_objc_thread_storage
;
/* Backend initialization functions */
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
printf
(
"__objc_init_thread_system
\n
"
);
if
(
pthread_keycreate
(
&
__objc_thread_data_key
,
NULL
)
==
0
)
return
0
;
/* Yes, return success. */
return
-
1
;
/* Failed. */
/* Initialize the thread storage key */
return
pthread_keycreate
(
&
_objc_thread_storage
,
NULL
);
}
/* Close the threads subsystem. */
int
__objc_
fini
_thread_system
(
void
)
__objc_
close
_thread_system
(
void
)
{
/* Destroy the thread storage key */
/* Not implemented yet */
/* return pthread_key_delete(&_objc_thread_storage); */
return
0
;
}
/********
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
objc_thread_t
thread_id
=
NULL
;
/* Detached thread id. */
pthread_t
new_thread_handle
;
/* DCE thread handle. */
objc_mutex_lock
(
__objc_runtime_mutex
);
if
(
pthread_create
(
&
new_thread_handle
,
pthread_attr_default
,
(
void
*
)
func
,
arg
)
==
0
)
{
/* ??? May not work! (64bit)*/
thread_id
=
*
(
objc_thread_t
*
)
&
new_thread_handle
;
pthread_detach
(
&
new_thread_handle
);
/* Fully detach thread. */
__objc_runtime_threads_alive
++
;
objc_thread_t
thread_id
;
pthread_t
new_thread_handle
;
if
(
pthread_create
(
&
new_thread_handle
,
pthread_attr_default
,
(
void
*
)
func
,
arg
)
==
0
)
{
/* ??? May not work! (64bit) */
thread_id
=
*
(
objc_thread_t
*
)
&
new_thread_handle
;
pthread_detach
(
&
new_thread_handle
);
/* Fully detach thread. */
}
objc_mutex_unlock
(
__objc_runtime_mutex
);
return
thread_id
;
else
thread_id
=
NULL
;
return
thread_id
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
int
sys_priority
=
0
;
int
sys_priority
=
0
;
switch
(
priority
)
{
switch
(
priority
)
{
case
OBJC_THREAD_INTERACTIVE_PRIORITY
:
sys_priority
=
(
PRI_FG_MIN_NP
+
PRI_FG_MAX_NP
)
/
2
;
break
;
sys_priority
=
(
PRI_FG_MIN_NP
+
PRI_FG_MAX_NP
)
/
2
;
break
;
default:
case
OBJC_THREAD_BACKGROUND_PRIORITY
:
sys_priority
=
(
PRI_BG_MIN_NP
+
PRI_BG_MAX_NP
)
/
2
;
break
;
sys_priority
=
(
PRI_BG_MIN_NP
+
PRI_BG_MAX_NP
)
/
2
;
break
;
case
OBJC_THREAD_LOW_PRIORITY
:
sys_priority
=
(
PRI_BG_MIN_NP
+
PRI_BG_MAX_NP
)
/
2
;
break
;
sys_priority
=
(
PRI_BG_MIN_NP
+
PRI_BG_MAX_NP
)
/
2
;
break
;
}
if
(
pthread_setprio
(
pthread_self
(),
sys_priority
)
>=
0
)
return
0
;
/* Changed priority. End. */
return
-
1
;
/* Failed. */
/* Change the priority. */
if
(
pthread_setprio
(
pthread_self
(),
sys_priority
)
>=
0
)
return
0
;
else
/* Failed */
return
-
1
;
}
/********
* Return the current thread's priority.
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
int
sys_priority
;
/* DCE thread priority. */
int
sys_priority
;
if
((
sys_priority
=
pthread_getprio
(
pthread_self
()))
>=
0
)
{
if
(
sys_priority
>=
PRI_FG_MIN_NP
&&
sys_priority
<=
PRI_FG_MAX_NP
)
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
if
(
sys_priority
>=
PRI_BG_MIN_NP
&&
sys_priority
<=
PRI_BG_MAX_NP
)
return
OBJC_THREAD_BACKGROUND_PRIORITY
;
return
OBJC_THREAD_LOW_PRIORITY
;
}
return
-
1
;
/* Couldn't get priority. */
if
((
sys_priority
=
pthread_getprio
(
pthread_self
()))
>=
0
)
{
if
(
sys_priority
>=
PRI_FG_MIN_NP
&&
sys_priority
<=
PRI_FG_MAX_NP
)
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
if
(
sys_priority
>=
PRI_BG_MIN_NP
&&
sys_priority
<=
PRI_BG_MAX_NP
)
return
OBJC_THREAD_BACKGROUND_PRIORITY
;
return
OBJC_THREAD_LOW_PRIORITY
;
}
/* Failed */
return
-
1
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
pthread_yield
();
/* Yield to equal thread. */
pthread_yield
();
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
objc_mutex_lock
(
__objc_runtime_mutex
);
__objc_runtime_threads_alive
--
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
pthread_exit
(
&
__objc_thread_exit_status
);
/* Terminate thread. */
/* exit the thread */
pthread_exit
(
&
__objc_thread_exit_status
);
/* Failed if we reached here */
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* -1 which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
pthread_t
self
=
pthread_self
();
return
(
objc_thread_t
)
pthread_getuniqe_np
(
&
self
);
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
if
(
pthread_setspecific
(
__objc_thread_data_key
,
(
void
*
)
value
)
==
0
)
return
0
;
/* Return thread data. */
return
-
1
;
return
pthread_setspecific
(
_objc_thread_storage
,
value
);
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__
objc_thread_get_data
(
void
)
{
void
*
value
=
NULL
;
if
(
pthread_getspecific
(
__objc_thread_data_key
,
(
void
*
)
&
value
)
==
0
)
return
value
;
/* Return thread data. */
return
NULL
;
void
*
value
=
NULL
;
if
(
!
(
pthread_getspecific
(
_objc_thread_storage
,
&
value
))
)
return
value
;
return
NULL
;
}
/********
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate
(
objc_mutex_t
mutex
)
{
objc_mutex_t
mutex
;
int
err
=
0
;
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
err
=
pthread_mutex_init
(
&
mutex
->
lock
,
pthread_mutexattr_default
);
if
(
err
!=
0
)
{
/* System init failed? */
objc_free
(
mutex
);
/* Yes, free local memory. */
return
NULL
;
/* Abort. */
}
mutex
->
owner
=
(
objc_thread_t
)
-
1
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
if
(
pthread_mutex_init
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)),
pthread_mutexattr_default
))
return
-
1
;
else
return
0
;
}
/********
* 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 deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
/* Deallocate a mutex. */
int
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
__
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
int
depth
;
/* # of locks on mutex. */
if
(
pthread_mutex_destroy
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
))))
return
-
1
;
else
return
0
;
}
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
pthread_mutex_unlock
(
&
mutex
->
lock
);
/* Must unlock system mutex.*/
pthread_mutex_destroy
(
&
mutex
->
lock
);
/* Free system mutex. */
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
/* Grab a lock on a mutex. */
int
__objc_mutex_lock
(
objc_mutex_t
mutex
)
{
return
pthread_mutex_lock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
/* Try to grab a lock on a mutex. */
int
objc_mutex_
lock
(
objc_mutex_t
mutex
)
__objc_mutex_try
lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
pthread_mutex_trylock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)))
!=
1
)
return
-
1
;
else
return
0
;
}
/* Unlock the mutex */
int
__objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
return
pthread_mutex_unlock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
/* Backend condition mutex functions */
if
(
pthread_mutex_lock
(
&
mutex
->
lock
)
!=
0
)
/* Lock DCE system mutex. */
return
-
1
;
/* Failed, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
/* Allocate a condition. */
int
__objc_condition_allocate
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
/*
if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
return -1;
else
return 0;
*/
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
/* Deallocate a condition. */
int
objc_mutex_trylock
(
objc_mutex_t
mutex
)
__objc_condition_deallocate
(
objc_condition_t
condition
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
/* Unimplemented. */
return
-
1
;
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
if
(
pthread_mutex_trylock
(
&
mutex
->
lock
)
!=
1
)
/* Lock DCE system mutex. */
return
-
1
;
/* Failed, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
/*
return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
*/
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Wait on the condition */
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
__objc_condition_wait
(
objc_condition_t
condition
,
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
(
objc_thread_t
)
-
1
;
/* Set owner to "no thread".*/
if
(
pthread_mutex_unlock
(
&
mutex
->
lock
)
!=
0
)
/* Unlock system mutex. */
return
-
1
;
/* Failed, abort. */
return
0
;
/* No, return success. */
/* Unimplemented. */
return
-
1
;
/*
return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)),
(pthread_mutex_t *)(&(mutex->backend)));
*/
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
/*
return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend)));
*/
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
/*
return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
*/
}
/* End of File */
gcc/objc/thr-irix.c
View file @
2024f9e4
...
...
@@ -32,283 +32,204 @@ Boston, MA 02111-1307, USA. */
#include <objc/thr.h>
#include "runtime.h"
/********
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct
objc_mutex
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
ulock_t
lock
;
/* Irix lock. */
};
/*****************************************************************************
* Static variables.
*/
static
void
*
__objc_shared_arena_handle
=
NULL
;
/* Storage arena locks. */
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Key structure for maintiain thread specific storage */
static
void
*
__objc_shared_arena_handle
=
NULL
;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
char
arena_name
[
64
];
/* Name of IRIX arena. */
DEBUG_PRINTF
(
"__objc_init_thread_system
\n
"
);
sprintf
(
arena_name
,
"/usr/tmp/objc_%05u"
,
(
unsigned
)
getpid
());
usconfig
(
CONF_INITUSERS
,
256
);
/* Up to 256 threads. */
usconfig
(
CONF_ARENATYPE
,
US_SHAREDONLY
);
/* Arena only for threads. */
if
(
!
(
__objc_shared_arena_handle
=
usinit
(
arena_name
)))
/* Init Failed? */
return
-
1
;
/* Yes, return error code. */
return
0
;
/* Name of IRIX arena. */
char
arena_name
[
64
];
DEBUG_PRINTF
(
"__objc_init_thread_system
\n
"
);
/* Construct a temporary name for arena. */
sprintf
(
arena_name
,
"/usr/tmp/objc_%05u"
,
(
unsigned
)
getpid
());
/* Up to 256 threads. Arena only for threads. */
usconfig
(
CONF_INITUSERS
,
256
);
usconfig
(
CONF_ARENATYPE
,
US_SHAREDONLY
);
/* Initialize the arena */
if
(
!
(
__objc_shared_arena_handle
=
usinit
(
arena_name
)))
/* Failed */
return
-
1
;
return
0
;
}
/* Close the threads subsystem. */
int
__objc_
fini
_thread_system
(
void
)
__objc_
close
_thread_system
(
void
)
{
return
0
;
}
/********
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
objc_thread_t
thread_id
=
NULL
;
int
sys_id
;
objc_mutex_lock
(
__objc_runtime_mutex
);
if
((
sys_id
=
sproc
((
void
*
)
func
,
PR_SALL
,
arg
))
>=
0
)
{
thread_id
=
(
objc_thread_t
)
sys_id
;
__objc_runtime_threads_alive
++
;
}
objc_mutex_unlock
(
__objc_runtime_mutex
);
return
thread_id
;
objc_thread_t
thread_id
;
int
sys_id
;
if
((
sys_id
=
sproc
((
void
*
)
func
,
PR_SALL
,
arg
))
>=
0
)
thread_id
=
(
objc_thread_t
)
sys_id
;
else
thread_id
=
NULL
;
return
thread_id
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
int
sys_priority
=
0
;
switch
(
priority
)
{
case
OBJC_THREAD_INTERACTIVE_PRIORITY
:
break
;
default:
case
OBJC_THREAD_BACKGROUND_PRIORITY
:
break
;
case
OBJC_THREAD_LOW_PRIORITY
:
break
;
}
return
-
1
;
/* Failed. */
/* Not implemented yet */
return
-
1
;
}
/********
* Return the current thread's priority.
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
return
-
1
;
/* Couldn't get priority. */
/* Not implemented yet */
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
sginap
(
0
);
/* Yield to equal process. */
sginap
(
0
);
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
objc_mutex_lock
(
__objc_runtime_mutex
);
__objc_runtime_threads_alive
--
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
/* IRIX only has exit. */
exit
(
__objc_thread_exit_status
);
exit
(
__objc_thread_exit_status
);
/* IRIX only has exit.
*/
return
-
1
;
/* Failed if we reached here
*/
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
return
(
objc_thread_t
)
get_pid
();
/* Threads are processes. */
/* Threads are processes. */
return
(
objc_thread_t
)
get_pid
();
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
*
((
void
**
)
&
PRDA
->
usr_prda
)
=
value
;
/* Set thread data ptr. */
return
0
;
*
((
void
**
)
&
PRDA
->
usr_prda
)
=
value
;
return
0
;
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__objc_thread_get_data
(
void
)
{
return
*
((
void
**
)
&
PRDA
->
usr_prda
);
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate
(
objc_mutex_t
mutex
)
{
if
(
!
(
(
ulock_t
)(
mutex
->
backend
)
=
usnewlock
(
__objc_shared_arena_handle
)
))
return
-
1
;
else
return
0
;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
return
*
((
void
**
)
&
PRDA
->
usr_prda
);
/* Return thread data ptr. */
usfreelock
((
ulock_t
)(
mutex
->
backend
),
__objc_shared_arena_handle
);
return
0
;
}
/********
* Allocate a mutex.
* Return the mutex pointer if successful or NULL if the allocation failed
* for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
/* Grab a lock on a mutex. */
int
__objc_mutex_lock
(
objc_mutex_t
mutex
)
{
objc_mutex_t
mutex
;
int
err
=
0
;
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
if
(
!
(
mutex
->
lock
=
usnewlock
(
__objc_shared_arena_handle
)))
err
=
-
1
;
if
(
err
!=
0
)
{
/* System init failed? */
objc_free
(
mutex
);
/* Yes, free local memory. */
return
NULL
;
/* Abort. */
}
mutex
->
owner
=
NULL
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
if
(
ussetlock
((
ulock_t
)(
mutex
->
backend
))
==
0
)
return
-
1
;
else
return
0
;
}
/********
* 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 deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
/* Try to grab a lock on a mutex. */
int
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
__objc_mutex_trylock
(
objc_mutex_t
mutex
)
{
int
depth
;
/* # of locks on mutex. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
usfreelock
(
mutex
->
lock
,
__objc_shared_arena_handle
);
/* Free IRIX lock. */
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
if
(
ustestlock
((
ulock_t
)(
mutex
->
backend
))
==
0
)
return
-
1
;
else
return
0
;
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
/* Unlock the mutex */
int
objc_mutex_
lock
(
objc_mutex_t
mutex
)
__objc_mutex_un
lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
{
/* Already own lock? */
DEBUG_PRINTF
(
"lock owned by: %d:%d
\n
"
,
mutex
->
owner
,
mutex
->
depth
);
return
++
mutex
->
depth
;
/* Yes, increment depth. */
}
DEBUG_PRINTF
(
"lock owned by: %d:%d (attempt by %d)
\n
"
,
mutex
->
owner
,
mutex
->
depth
,
thread_id
);
if
(
ussetlock
(
mutex
->
lock
)
==
0
)
/* Did lock acquire fail? */
return
-
1
;
/* Yes, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
usunsetlock
((
ulock_t
)(
mutex
->
backend
));
return
0
;
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
/* Backend condition mutex functions */
/* Allocate a condition. */
int
objc_mutex_trylock
(
objc_mutex_t
mutex
)
__objc_condition_allocate
(
objc_condition_t
condition
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
if
(
ustestlock
(
mutex
->
lock
)
==
0
)
/* Did lock acquire fail? */
return
-
1
;
/* Yes, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
/* Unimplemented. */
return
-
1
;
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Deallocate a condition. */
int
__objc_condition_deallocate
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
}
/* Wait on the condition */
int
__objc_condition_wait
(
objc_condition_t
condition
,
objc_mutex_t
mutex
)
{
/* Unimplemented. */
return
-
1
;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
}
/* Wake up one thread waiting on this condition. */
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
__objc_condition_signal
(
objc_condition_t
condition
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
DEBUG_PRINTF
(
"unlock by: %d:%d
\n
"
,
mutex
->
owner
,
mutex
->
depth
-
1
);
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
NULL
;
/* Set owner to "no thread".*/
usunsetlock
(
mutex
->
lock
);
/* Free lock. */
return
0
;
/* No, return success. */
/* Unimplemented. */
return
-
1
;
}
/* End of File */
gcc/objc/thr-mach.c
View file @
2024f9e4
...
...
@@ -31,434 +31,282 @@ Boston, MA 02111-1307, USA. */
#include <objc/thr.h>
#include "runtime.h"
/*
*******
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock
.
*/
st
ruct
objc_mutex
/*
Obtain the maximum thread priority that can set for t. Under the
mach threading model, it is possible for the developer to adjust the
maximum priority downward only-- cannot be raised without superuser
priviledges. Once lowered, it cannot be raised
.
*/
st
atic
int
__mach_get_max_thread_priority
(
cthread_t
t
,
int
*
base
)
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
struct
mutex
lock
;
/* cthread mutex */
};
struct
objc_condition
{
struct
condition
condition
;
/* cthread condition */
};
/********
* obtain the maximum thread priority that can set for t. Under the
* mach threading model, it is possible for the developer to adjust the
* maximum priority downward only-- cannot be raised without superuser
* priviledges. Once lowered, it cannot be raised.
*/
static
int
__mach_get_max_thread_priority
(
cthread_t
t
,
int
*
base
)
{
thread_t
threadP
;
kern_return_t
error
;
struct
thread_sched_info
info
;
unsigned
int
info_count
=
THREAD_SCHED_INFO_COUNT
;
thread_t
threadP
;
kern_return_t
error
;
struct
thread_sched_info
info
;
unsigned
int
info_count
=
THREAD_SCHED_INFO_COUNT
;
if
(
t
==
NULL
)
return
-
1
;
if
(
t
==
NULL
)
return
-
1
;
threadP
=
cthread_thread
(
t
);
/* get thread underlying */
threadP
=
cthread_thread
(
t
);
/* get thread underlying */
error
=
thread_info
(
threadP
,
THREAD_SCHED_INFO
,
(
thread_info_t
)
&
info
,
&
info_count
);
error
=
thread_info
(
threadP
,
THREAD_SCHED_INFO
,
(
thread_info_t
)
&
info
,
&
info_count
);
if
(
error
!=
KERN_SUCCESS
)
return
-
1
;
if
(
error
!=
KERN_SUCCESS
)
return
-
1
;
if
(
base
!=
NULL
)
*
base
=
info
.
base_priority
;
if
(
base
!=
NULL
)
*
base
=
info
.
base_priority
;
return
info
.
max_priority
;
return
info
.
max_priority
;
}
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
DEBUG_PRINTF
(
"__objc_init_thread_system
\n
"
);
return
0
;
/* Succeeded. */
return
0
;
}
/* Close the threads subsystem. */
int
__objc_
fini
_thread_system
(
void
)
__objc_
close
_thread_system
(
void
)
{
return
0
;
}
/********
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
objc_thread_t
thread_id
=
NULL
;
/* Detached thread id. */
cthread_t
new_thread_handle
;
/* cthread handle. */
objc_thread_t
thread_id
;
cthread_t
new_thread_handle
;
objc_mutex_lock
(
__objc_runtime_mutex
);
/* create thread */
new_thread_handle
=
cthread_fork
((
cthread_fn_t
)
func
,
arg
);
/* create thread */
new_thread_handle
=
cthread_fork
((
cthread_fn_t
)
func
,
arg
);
if
(
new_thread_handle
)
{
if
(
new_thread_handle
)
{
/* this is not terribly portable */
thread_id
=
*
(
objc_thread_t
*
)
&
new_thread_handle
;
cthread_detach
(
new_thread_handle
);
/* fully detach thread */
__objc_runtime_threads_alive
++
;
/* increment thread count */
thread_id
=
*
(
objc_thread_t
*
)
&
new_thread_handle
;
cthread_detach
(
new_thread_handle
);
}
objc_mutex_unlock
(
__objc_runtime_mutex
);
return
thread_id
;
else
thread_id
=
NULL
;
return
thread_id
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
objc_thread_t
*
t
=
objc_thread_id
();
cthread_t
cT
=
(
cthread_t
)
t
;
int
maxPriority
=
__mach_get_max_thread_priority
(
cT
,
NULL
);
int
sys_priority
=
0
;
objc_thread_t
*
t
=
objc_thread_id
();
cthread_t
cT
=
(
cthread_t
)
t
;
int
maxPriority
=
__mach_get_max_thread_priority
(
cT
,
NULL
);
int
sys_priority
=
0
;
if
(
maxPriority
==
-
1
)
return
-
1
;
if
(
maxPriority
==
-
1
)
return
-
1
;
switch
(
priority
)
{
switch
(
priority
)
{
case
OBJC_THREAD_INTERACTIVE_PRIORITY
:
sys_priority
=
maxPriority
;
break
;
sys_priority
=
maxPriority
;
break
;
case
OBJC_THREAD_BACKGROUND_PRIORITY
:
sys_priority
=
(
maxPriority
*
2
)
/
3
;
break
;
sys_priority
=
(
maxPriority
*
2
)
/
3
;
break
;
case
OBJC_THREAD_LOW_PRIORITY
:
sys_priority
=
maxPriority
/
3
;
break
;
sys_priority
=
maxPriority
/
3
;
break
;
default:
return
-
1
;
return
-
1
;
}
if
(
sys_priority
==
0
)
return
-
1
;
if
(
cthread_priority
(
cT
,
sys_priority
,
0
)
==
KERN_SUCCESS
)
return
0
;
/* Changed priority. End. */
return
-
1
;
/* Failed. */
if
(
sys_priority
==
0
)
return
-
1
;
/* Change the priority */
if
(
cthread_priority
(
cT
,
sys_priority
,
0
)
==
KERN_SUCCESS
)
return
0
;
else
return
-
1
;
}
/********
* Return the current thread's priority [well, whatever it is closest to].
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
objc_thread_t
*
t
=
objc_thread_id
();
cthread_t
cT
=
(
cthread_t
)
t
;
/* see objc_thread_id() */
int
basePriority
;
int
maxPriority
;
int
sys_priority
=
0
;
int
interactiveT
,
backgroundT
,
lowT
;
/* threasholds */
maxPriority
=
__mach_get_max_thread_priority
(
cT
,
&
basePriority
);
if
(
maxPriority
==
-
1
)
return
-
1
;
if
(
basePriority
>
(
(
maxPriority
*
2
)
/
3
))
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
/* interactive priority
*/
if
(
basePriority
>
(
maxPriority
/
3
))
return
OBJC_THREAD_BACKGROUND_PRIORITY
;
/* background priority
*/
return
OBJC_THREAD_LOW_PRIORITY
;
/* everything else is low */
objc_thread_t
*
t
=
objc_thread_id
();
cthread_t
cT
=
(
cthread_t
)
t
;
/* see objc_thread_id() */
int
basePriority
;
int
maxPriority
;
int
sys_priority
=
0
;
int
interactiveT
,
backgroundT
,
lowT
;
/* threasholds */
maxPriority
=
__mach_get_max_thread_priority
(
cT
,
&
basePriority
);
if
(
maxPriority
==
-
1
)
return
-
1
;
if
(
basePriority
>
(
(
maxPriority
*
2
)
/
3
))
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
if
(
basePriority
>
(
maxPriority
/
3
))
return
OBJC_THREAD_BACKGROUND_PRIORITY
;
return
OBJC_THREAD_LOW_PRIORITY
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
cthread_yield
();
/* Yield to equal thread. */
cthread_yield
();
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
objc_mutex_lock
(
__objc_runtime_mutex
);
__objc_runtime_threads_alive
--
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
cthread_exit
(
&
__objc_thread_exit_status
);
/* Terminate thread. */
/* exit the thread */
cthread_exit
(
&
__objc_thread_exit_status
);
/* Failed if we reached here */
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
cthread_t
self
=
cthread_self
();
return
(
objc_thread_t
)
self
;
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
return
*
(
objc_thread_t
*
)
&
self
;
}
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
cthread_set_data
(
cthread_self
(),
(
any_t
)
value
);
return
0
;
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__
objc_thread_get_data
(
void
)
{
return
(
void
*
)
cthread_data
(
cthread_self
());
}
/********
* Allocate a mutex. Return the mutex pointer if successful or NULL if the
* allocation failed for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate
(
objc_mutex_t
mutex
)
{
objc_mutex_t
mutex
;
int
err
=
0
;
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
int
err
=
0
;
mutex
->
backend
=
objc_malloc
(
sizeof
(
struct
mutex
));
err
=
mutex_init
(
&
(
mutex
->
lock
));
if
(
err
!=
0
)
{
/* System init failed? */
objc_free
(
mutex
);
/* Yes, free local memory. */
return
NULL
;
/* Abort. */
err
=
mutex_init
((
mutex_t
)(
mutex
->
backend
));
if
(
err
!=
0
)
{
objc_free
(
mutex
->
backend
);
return
-
1
;
}
mutex
->
owner
=
(
objc_thread_t
)
-
1
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
else
return
0
;
}
/********
* 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).
*/
/* Deallocate a mutex. */
int
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
__
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
int
depth
;
/* # of locks on mutex. */
mutex_clear
((
mutex_t
)(
mutex
->
backend
));
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
mutex_unlock
(
&
(
mutex
->
lock
));
/* Must unlock system mutex.*/
mutex_clear
(
&
(
mutex
->
lock
));
/* Free system mutex. */
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
objc_free
(
mutex
->
backend
);
mutex
->
backend
=
NULL
;
return
0
;
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
/* Grab a lock on a mutex. */
int
objc_mutex_lock
(
objc_mutex_t
mutex
)
__
objc_mutex_lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
mutex_lock
(
&
(
mutex
->
lock
));
/* Lock cthread mutex. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
mutex_lock
((
mutex_t
)(
mutex
->
backend
));
return
0
;
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
/* Try to grab a lock on a mutex. */
int
objc_mutex_trylock
(
objc_mutex_t
mutex
)
__
objc_mutex_trylock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
if
(
mutex_try_lock
(
&
(
mutex
->
lock
))
==
0
)
/* Lock cthread mutex. */
return
-
1
;
/* Failed, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
if
(
mutex_try_lock
((
mutex_t
)(
mutex
->
backend
))
==
0
)
return
-
1
;
else
return
0
;
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Unlock the mutex */
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
__
objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
(
objc_thread_t
)
-
1
;
/* Set owner to "no thread".*/
mutex_unlock
(
&
(
mutex
->
lock
));
/* unlock cthread mutex. */
return
0
;
/* No, return success. */
mutex_unlock
((
mutex_t
)(
mutex
->
backend
));
return
0
;
}
/********
* Allocate a condition. Return the condition pointer if successful or NULL
* if the allocation failed for any reason.
*/
objc_condition_t
objc_condition_allocate
(
void
)
{
objc_condition_t
condition
;
if
(
!
(
condition
=
(
objc_condition_t
)
objc_malloc
(
sizeof
(
struct
objc_condition
))))
return
NULL
;
/* Abort if malloc failed. */
/* Backend condition mutex functions */
condition_init
(
&
(
condition
->
condition
));
return
condition
;
/* Return mutex handle. */
/* Allocate a condition. */
int
__objc_condition_allocate
(
objc_condition_t
condition
)
{
condition
->
backend
=
objc_malloc
(
sizeof
(
struct
condition
));
condition_init
((
condition_t
)(
condition
->
backend
));
return
0
;
}
/********
* Deallocate a condition. Note that this includes an implicit
* condition_broadcast to insure that waiting threads have the opportunity
* to wake. It is legal to dealloc a condition only if no other
* thread is/will be using it. Here we do NOT check for other threads
* waiting but just wake them up.
*/
/* Deallocate a condition. */
int
objc_condition_deallocate
(
objc_condition_t
condition
)
__
objc_condition_deallocate
(
objc_condition_t
condition
)
{
condition_broadcast
(
&
(
condition
->
condition
));
condition_clear
(
&
(
condition
->
condition
)
);
objc_free
(
condition
)
;
return
0
;
condition_clear
((
condition_t
)(
condition
->
backend
));
objc_free
(
condition
->
backend
);
condition
->
backend
=
NULL
;
return
0
;
}
/********
* 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.
*/
/* Wait on the condition */
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
;
/* Cache our thread id. */
if
(
!
mutex
||
!
condition
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Locked more than once ? */
return
-
1
;
/* YES, return error */
/* mutex will be unlocked */
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
(
objc_thread_t
)
-
1
;
/* Set owner to "no thread".*/
condition_wait
(
&
(
condition
->
condition
),
&
(
mutex
->
lock
));
/* unlock, wait ..., lock */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
mutex
->
depth
=
1
;
/* Increment depth to end. */
return
0
;
/* Return success. */
condition_wait
((
condition_t
)(
condition
->
backend
),
(
mutex_t
)(
mutex
->
backend
));
return
0
;
}
/********
* Wake up all threads waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
/* Wake up all threads waiting on this condition. */
int
objc_condition_broadcast
(
objc_condition_t
condition
)
__
objc_condition_broadcast
(
objc_condition_t
condition
)
{
if
(
!
condition
)
return
-
1
;
condition_broadcast
(
&
(
condition
->
condition
));
return
0
;
condition_broadcast
((
condition_t
)(
condition
->
backend
));
return
0
;
}
/********
* Wake up one thread waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
/* Wake up one thread waiting on this condition. */
int
objc_condition_signal
(
objc_condition_t
condition
)
__
objc_condition_signal
(
objc_condition_t
condition
)
{
if
(
!
condition
)
return
-
1
;
condition_signal
(
&
(
condition
->
condition
));
return
0
;
condition_signal
((
condition_t
)(
condition
->
backend
));
return
0
;
}
/* End of File */
gcc/objc/thr-os2.c
View file @
2024f9e4
...
...
@@ -44,71 +44,39 @@ Boston, MA 02111-1307, USA. */
#include <stdlib.h>
/********
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct
objc_mutex
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
HMTX
handle
;
/* OS/2 mutex HANDLE. */
};
/* Backend initialization functions */
/*****************************************************************************
* Static variables.
*/
/* none needed for OS/2 */
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
DEBUG_PRINTF
(
"__objc_init_thread_system (os2-emx)
\n
"
);
/* no initialization of thread subsystem */
return
0
;
/* Yes, return success. */
return
0
;
}
/* Close the threads subsystem. */
int
__objc_
fini
_thread_system
(
void
)
__objc_
close
_thread_system
(
void
)
{
/* no termination code for thread subsystem */
return
0
;
}
/********
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
int
thread_id
=
0
;
/* id of the newly created thread */
int
thread_id
=
0
;
objc_mutex_lock
(
__objc_runtime_mutex
);
/* create a thread calling "func", args "arg", stack size 32768 bytes */
if
((
thread_id
=
_beginthread
(
func
,
NULL
,
32768
,
arg
))
<
0
)
thread_id
=
0
;
else
__objc_runtime_threads_alive
++
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
return
(
objc_thread_t
)
thread_id
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
ULONG
sys_class
=
0
;
ULONG
sys_priority
=
0
;
...
...
@@ -132,210 +100,168 @@ objc_thread_set_priority(int priority)
sys_priority
=
0
;
break
;
}
/* Change priority */
if
(
!
DosSetPriority
(
PRTYS_THREAD
,
sys_class
,
sys_priority
,
*
_threadid
))
return
0
;
/* Changed priority. End. */
return
-
1
;
/* Failed. */
return
0
;
else
return
-
1
;
}
/********
* Return the current thread's priority.
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
PTIB
ptib
;
PPIB
ppib
;
DosGetInfoBlocks
(
&
ptib
,
&
ppib
);
/* get information about current thread */
/* get information about current thread */
DosGetInfoBlocks
(
&
ptib
,
&
ppib
);
switch
(
ptib
->
tib_ptib2
->
tib2_ulpri
)
{
case
PRTYC_IDLETIME
:
case
PRTYC_REGULAR
:
case
PRTYC_TIMECRITICAL
:
case
PRTYC_FOREGROUNDSERVER
:
default:
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
}
switch
(
ptib
->
tib_ptib2
->
tib2_ulpri
)
{
case
PRTYC_IDLETIME
:
case
PRTYC_REGULAR
:
case
PRTYC_TIMECRITICAL
:
case
PRTYC_FOREGROUNDSERVER
:
default:
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
}
return
-
1
;
/* Couldn't get priority. */
return
-
1
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
DosSleep
(
0
);
/* Yield to equal thread. */
DosSleep
(
0
);
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
objc_mutex_lock
(
__objc_runtime_mutex
);
__objc_runtime_threads_alive
--
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
_endthread
();
/* terminate the thread, NEVER use DosExit () */
/* terminate the thread, NEVER use DosExit () */
_endthread
();
/* Failed if we reached here */
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* -1 which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
return
(
objc_thread_t
)
*
_threadid
;
/* Return thread id. */
return
(
objc_thread_t
)
*
_threadid
;
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
*
_threadstore
()
=
value
;
return
0
;
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__
objc_thread_get_data
(
void
)
{
return
*
_threadstore
();
}
/********
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
{
objc_mutex_t
mutex
;
int
err
=
0
;
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
if
(
DosCreateMutexSem
(
NULL
,
&
(
mutex
->
handle
),
0L
,
0
)
>
0
)
{
objc_free
(
mutex
);
return
NULL
;
}
/* Backend mutex functions */
mutex
->
owner
=
NULL
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
/* Allocate a mutex. */
int
__objc_mutex_allocate
(
objc_mutex_t
mutex
)
{
if
(
DosCreateMutexSem
(
NULL
,
(
HMTX
)(
&
(
mutex
->
backend
)),
0L
,
0
)
>
0
)
return
-
1
;
else
return
0
;
}
/********
* 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 deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
/* Deallocate a mutex. */
int
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
__
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
int
depth
;
/* # of locks on mutex. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
DosCloseMutexSem
(
mutex
->
handle
);
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
DosCloseMutexSem
((
HMTX
)(
mutex
->
backend
));
return
0
;
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
/* Grab a lock on a mutex. */
int
objc_mutex_lock
(
objc_mutex_t
mutex
)
__
objc_mutex_lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
if
(
DosRequestMutexSem
((
HMTX
)(
mutex
->
backend
),
-
1L
)
!=
0
)
return
-
1
;
else
return
0
;
}
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock
(
objc_mutex_t
mutex
)
{
if
(
DosRequestMutexSem
((
HMTX
)(
mutex
->
backend
),
0L
)
!=
0
)
return
-
1
;
else
return
0
;
}
if
(
DosRequestMutexSem
(
mutex
->
handle
,
-
1L
)
!=
0
)
return
-
1
;
/* Unlock the mutex */
int
__objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
if
(
DosReleaseMutexSem
((
HMTX
)(
mutex
->
backend
))
!=
0
)
return
-
1
;
else
return
0
;
}
mutex
->
owner
=
thread_id
;
/* Mark thread as owner.
*/
/* Backend condition mutex functions
*/
return
++
mutex
->
depth
;
/* Increment depth to end. */
/* Allocate a condition. */
int
__objc_condition_allocate
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
/* Deallocate a condition. */
int
objc_mutex_trylock
(
objc_mutex_t
mutex
)
__objc_condition_deallocate
(
objc_condition_t
condition
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
/* Unimplemented. */
return
-
1
;
}
if
(
DosRequestMutexSem
(
mutex
->
handle
,
0L
)
!=
0
)
return
-
1
;
/* Wait on the condition */
int
__objc_condition_wait
(
objc_condition_t
condition
,
objc_mutex_t
mutex
)
{
/* Unimplemented. */
return
-
1
;
}
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
++
mutex
->
depth
;
/* Increment depth to end. */
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Wake up one thread waiting on this condition. */
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
__objc_condition_signal
(
objc_condition_t
condition
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
NULL
;
/* Set owner to "no thread".*/
if
(
DosReleaseMutexSem
(
mutex
->
handle
)
!=
0
)
return
-
1
;
/* Failed, abort. */
return
0
;
/* No, return success. */
/* Unimplemented. */
return
-
1
;
}
/* End of File */
gcc/objc/thr-posix.c
View file @
2024f9e4
...
...
@@ -29,294 +29,182 @@ Boston, MA 02111-1307, USA. */
#include "runtime.h"
#include <pthread.h>
/********
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct
objc_mutex
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
pthread_mutex_t
lock
;
/* pthread mutex. */
};
/*****************************************************************************
* Static variables.
*/
static
pthread_key_t
__objc_thread_data_key
;
/* Data key for thread data.*/
/* Key structure for maintiain thread specific storage */
static
pthread_key_t
_objc_thread_storage
;
/* Backend initialization functions */
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
if
(
pthread_key_create
(
&
__objc_thread_data_key
,
NULL
)
==
0
)
return
0
;
/* Yes, return success. */
return
-
1
;
/* Failed. */
/* Initialize the thread storage key */
return
pthread_key_create
(
&
_objc_thread_storage
,
NULL
);
}
/* Close the threads subsystem. */
int
__objc_
fini
_thread_system
(
void
)
__objc_
close
_thread_system
(
void
)
{
return
0
;
}
/********
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
objc_thread_t
thread_id
=
NULL
;
/* Detached thread id. */
pthread_t
new_thread_handle
;
/* DCE thread handle. */
objc_mutex_lock
(
__objc_runtime_mutex
);
if
(
pthread_create
(
&
new_thread_handle
,
NULL
,
(
void
*
)
func
,
arg
)
==
0
)
{
thread_id
=
(
objc_thread_t
)
new_thread_handle
;
pthread_detach
(
new_thread_handle
);
/* Fully detach thread. */
__objc_runtime_threads_alive
++
;
}
objc_mutex_unlock
(
__objc_runtime_mutex
);
return
thread_id
;
objc_thread_t
thread_id
;
pthread_t
new_thread_handle
;
if
(
!
(
pthread_create
(
&
new_thread_handle
,
NULL
,
(
void
*
)
func
,
arg
))
)
thread_id
=
*
(
objc_thread_t
*
)
&
new_thread_handle
;
else
thread_id
=
NULL
;
return
thread_id
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
#if 0 /* no get/set priority in Linux pthreads */
int sys_priority = 0;
switch (priority) {
case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
break;
default:
case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break;
case OBJC_THREAD_LOW_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break;
}
if (pthread_setprio(pthread_self(), sys_priority) >= 0)
return 0; /* Changed priority. End. */
#endif
return
-
1
;
/* Failed. */
/* Not implemented yet */
return
-
1
;
}
/********
* Return the current thread's priority.
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
#if 0 /* no get/set priority in Linux pthreads */
int sys_priority; /* DCE thread priority. */
if ((sys_priority = pthread_getprio(pthread_self())) >= 0) {
if (sys_priority >= PRI_FG_MIN_NP && sys_priority <= PRI_FG_MAX_NP)
return OBJC_THREAD_INTERACTIVE_PRIORITY;
if (sys_priority >= PRI_BG_MIN_NP && sys_priority <= PRI_BG_MAX_NP)
return OBJC_THREAD_BACKGROUND_PRIORITY;
return OBJC_THREAD_LOW_PRIORITY;
}
#endif
return
-
1
;
/* Couldn't get priority. */
/* Not implemented yet */
return
-
1
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
pthread_yield
();
/* Yield to equal thread. */
pthread_yield
();
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
objc_mutex_lock
(
__objc_runtime_mutex
);
__objc_runtime_threads_alive
--
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
pthread_exit
(
&
__objc_thread_exit_status
);
/* Terminate thread. */
/* exit the thread */
pthread_exit
(
&
__objc_thread_exit_status
);
/* Failed if we reached here */
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* -1 which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
pthread_t
self
=
pthread_self
();
return
(
objc_thread_t
)
self
;
/* Return thread handle. */
return
*
(
objc_thread_t
*
)
&
self
;
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
if
(
pthread_setspecific
(
__objc_thread_data_key
,
(
void
*
)
value
)
==
0
)
return
0
;
/* Return thread data. */
return
-
1
;
return
pthread_setspecific
(
_objc_thread_storage
,
value
);
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__objc_thread_get_data
(
void
)
{
return
pthread_getspecific
(
_objc_thread_storage
);
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate
(
objc_mutex_t
mutex
)
{
return
pthread_getspecific
(
__objc_thread_data_key
);
if
(
pthread_mutex_init
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)),
NULL
))
return
-
1
;
else
return
0
;
}
/********
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
/* Deallocate a mutex. */
int
__objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
objc_mutex_t
mutex
;
int
err
=
0
;
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
err
=
pthread_mutex_init
(
&
mutex
->
lock
,
NULL
);
if
(
err
!=
0
)
{
/* System init failed? */
objc_free
(
mutex
);
/* Yes, free local memory. */
return
NULL
;
/* Abort. */
}
mutex
->
owner
=
NULL
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
if
(
pthread_mutex_destroy
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
))))
return
-
1
;
else
return
0
;
}
/********
* 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 deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
/* Grab a lock on a mutex. */
int
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
__objc_mutex_lock
(
objc_mutex_t
mutex
)
{
int
depth
;
/* # of locks on mutex. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
pthread_mutex_unlock
(
&
mutex
->
lock
);
/* Must unlock system mutex.*/
pthread_mutex_destroy
(
&
mutex
->
lock
);
/* Free system mutex. */
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
return
pthread_mutex_lock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
/* Try to grab a lock on a mutex. */
int
objc_mutex_
lock
(
objc_mutex_t
mutex
)
__objc_mutex_try
lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
if
(
pthread_mutex_lock
(
&
mutex
->
lock
)
!=
0
)
/* Lock DCE system mutex. */
return
-
1
;
/* Failed, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
return
pthread_mutex_trylock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
/* Unlock the mutex */
int
objc_mutex_try
lock
(
objc_mutex_t
mutex
)
__objc_mutex_un
lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
if
(
pthread_mutex_trylock
(
&
mutex
->
lock
)
!=
1
)
/* Lock DCE system mutex. */
return
-
1
;
/* Failed, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
return
pthread_mutex_unlock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Backend condition mutex functions */
/* Allocate a condition. */
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
__objc_condition_allocate
(
objc_condition_t
condition
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
NULL
;
/* Set owner to "no thread".*/
if
(
pthread_mutex_unlock
(
&
mutex
->
lock
)
!=
0
)
/* Unlock system mutex. */
return
-
1
;
/* Failed, abort. */
return
0
;
/* No, return success. */
if
(
pthread_cond_init
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)),
NULL
))
return
-
1
;
else
return
0
;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate
(
objc_condition_t
condition
)
{
return
pthread_cond_destroy
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)));
}
/* Wait on the condition */
int
__objc_condition_wait
(
objc_condition_t
condition
,
objc_mutex_t
mutex
)
{
return
pthread_cond_wait
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)),
(
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast
(
objc_condition_t
condition
)
{
return
pthread_cond_broadcast
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)));
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal
(
objc_condition_t
condition
)
{
return
pthread_cond_signal
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)));
}
/* End of File */
gcc/objc/thr-pthreads.c
View file @
2024f9e4
/* GNU Objective C Runtime Thread Implementation for PCThreads under Linux.
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Scott Christley <scottc@net-community.com>
Condition functions added by: Mircea Oancea <mircea@first.elcom.pub.ro>
This file is part of GNU CC.
...
...
@@ -24,35 +25,16 @@ Boston, MA 02111-1307, USA. */
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <pthread.h>
#include <p
c
thread.h>
#include <objc/thr.h>
#include "runtime.h"
/* Key structure for maintiain thread specific storage */
static
pthread_key_t
_objc_thread_storage
;
/********
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct
objc_mutex
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
pthread_mutex_t
mutex
;
/* PCThread mutex */
};
struct
objc_condition
{
pthread_cond_t
condition
;
/* cthread condition */
};
/* Backend initialization functions */
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
...
...
@@ -60,11 +42,9 @@ __objc_init_thread_system(void)
return
pthread_key_create
(
&
_objc_thread_storage
,
NULL
);
}
/********
* Finalize the threads subsystem. Returns 0 if successful, or -1 if not
*/
/* Close the threads subsystem. */
int
__objc_
fini
_thread_system
(
void
)
__objc_
close
_thread_system
(
void
)
{
/* Destroy the thread storage key */
/* Not implemented yet */
...
...
@@ -72,104 +52,76 @@ __objc_fini_thread_system(void)
return
0
;
}
/********
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
objc_thread_t
thread_id
;
pthread_t
new_thread_handle
;
objc_mutex_lock
(
__objc_runtime_mutex
);
if
(
!
(
pthread_create
(
&
new_thread_handle
,
NULL
,
(
void
*
)
func
,
arg
))
)
{
thread_id
=
*
(
objc_thread_t
*
)
&
new_thread_handle
;
__objc_runtime_threads_alive
++
;
}
else
thread_id
=
NULL
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
return
thread_id
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
/* Not implemented yet */
return
-
1
;
/* Failed. */
return
-
1
;
}
/********
* Return the current thread's priority.
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
/* Not implemented yet */
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
/* Highest priority. */
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
pthread_yield
(
NULL
);
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
objc_mutex_lock
(
__objc_runtime_mutex
);
__objc_runtime_threads_alive
--
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
pthread_exit
(
&
__objc_thread_exit_status
);
/* Terminate thread. */
/* exit the thread */
pthread_exit
(
&
__objc_thread_exit_status
);
/* Failed if we reached here */
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
pthread_t
self
=
pthread_self
();
return
*
(
objc_thread_t
*
)
&
self
;
/* Return thread handle. */
return
*
(
objc_thread_t
*
)
&
self
;
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
return
pthread_setspecific
(
_objc_thread_storage
,
value
);
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__
objc_thread_get_data
(
void
)
{
void
*
value
=
NULL
;
...
...
@@ -179,240 +131,88 @@ objc_thread_get_data(void)
return
NULL
;
}
/********
* Allocate a mutex. Return the mutex pointer if successful or NULL if the
* allocation failed for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate
(
objc_mutex_t
mutex
)
{
objc_mutex_t
mutex
;
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
/* Create PCThread mutex */
if
(
pthread_mutex_init
(
&
(
mutex
->
mutex
),
NULL
)
)
{
/* Failed */
objc_free
(
mutex
);
return
NULL
;
}
mutex
->
owner
=
NULL
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
if
(
pthread_mutex_init
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)),
NULL
))
return
-
1
;
else
return
0
;
}
/********
* 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).
*/
/* Deallocate a mutex. */
int
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
__
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
int
depth
;
/* # of locks on mutex. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
/* Destroy PCThread mutex */
pthread_mutex_destroy
(
&
(
mutex
->
mutex
));
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
if
(
pthread_mutex_destroy
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
))))
return
-
1
;
else
return
0
;
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
/* Grab a lock on a mutex. */
int
objc_mutex_lock
(
objc_mutex_t
mutex
)
__
objc_mutex_lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
int
status
;
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
{
return
++
mutex
->
depth
;
/* Yes, increment depth. */
}
/* Lock the PCThread mutex */
status
=
pthread_mutex_lock
(
&
(
mutex
->
mutex
));
if
(
status
)
{
return
status
;
/* Failed */
}
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
return
pthread_mutex_lock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
/* Try to grab a lock on a mutex. */
int
objc_mutex_trylock
(
objc_mutex_t
mutex
)
__
objc_mutex_trylock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
int
status
;
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
/* Lock the PCThread mutex */
status
=
pthread_mutex_trylock
(
&
(
mutex
->
mutex
));
if
(
status
)
return
status
;
/* Failed */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
return
pthread_mutex_trylock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Unlock the mutex */
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
__
objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
int
status
;
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
NULL
;
/* Set owner to "no thread".*/
/* Unlock the PCThread mutex */
status
=
pthread_mutex_unlock
(
&
(
mutex
->
mutex
));
if
(
status
)
return
status
;
/* Failed */
return
0
;
/* No, return success. */
return
pthread_mutex_unlock
((
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Allocate a condition. Return the condition pointer if successful or NULL
* if the allocation failed for any reason.
*/
objc_condition_t
objc_condition_allocate
(
void
)
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate
(
objc_condition_t
condition
)
{
objc_condition_t
condition
;
if
(
!
(
condition
=
(
objc_condition_t
)
objc_malloc
(
sizeof
(
struct
objc_condition
))))
return
NULL
;
/* Abort if malloc failed. */
if
(
pthread_cond_init
(
&
(
condition
->
condition
),
NULL
)
)
{
objc_free
(
condition
);
return
NULL
;
}
return
condition
;
/* Return condition handle. */
if
(
pthread_cond_init
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)),
NULL
))
return
-
1
;
else
return
0
;
}
/********
* Deallocate a condition. Note that this includes an implicit
* condition_broadcast to insure that waiting threads have the opportunity
* to wake. It is legal to dealloc a condition only if no other
* thread is/will be using it. Here we do NOT check for other threads
* waiting but just wake them up.
*/
/* Deallocate a condition. */
int
objc_condition_deallocate
(
objc_condition_t
condition
)
__
objc_condition_deallocate
(
objc_condition_t
condition
)
{
pthread_cond_broadcast
(
&
(
condition
->
condition
));
pthread_cond_destroy
(
&
(
condition
->
condition
));
objc_free
(
condition
);
return
0
;
return
pthread_cond_destroy
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)));
}
/********
* 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.
*/
/* Wait on the condition */
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
;
/* Cache our thread id. */
if
(
!
mutex
||
!
condition
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Locked more than once ? */
return
-
1
;
/* YES, return error */
/* mutex will be unlocked */
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
(
objc_thread_t
)
-
1
;
/* Set owner to "no thread".*/
pthread_cond_wait
(
&
(
condition
->
condition
),
&
(
mutex
->
mutex
));
/* unlock, wait ..., lock */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
mutex
->
depth
=
1
;
/* Increment depth to end. */
return
0
;
/* Return success. */
return
pthread_cond_wait
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)),
(
pthread_mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Wake up all threads waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
/* Wake up all threads waiting on this condition. */
int
objc_condition_broadcast
(
objc_condition_t
condition
)
__
objc_condition_broadcast
(
objc_condition_t
condition
)
{
if
(
!
condition
)
return
-
1
;
pthread_cond_broadcast
(
&
(
condition
->
condition
));
return
0
;
return
pthread_cond_broadcast
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)));
}
/********
* Wake up one thread waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
/* Wake up one thread waiting on this condition. */
int
objc_condition_signal
(
objc_condition_t
condition
)
__
objc_condition_signal
(
objc_condition_t
condition
)
{
if
(
!
condition
)
return
-
1
;
pthread_cond_signal
(
&
(
condition
->
condition
));
return
0
;
return
pthread_cond_signal
((
pthread_cond_t
*
)(
&
(
condition
->
backend
)));
}
/* End of File */
gcc/objc/thr-single.c
View file @
2024f9e4
...
...
@@ -27,214 +27,166 @@ Boston, MA 02111-1307, USA. */
#include <objc/thr.h>
#include "runtime.h"
/********
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct
objc_mutex
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
};
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Thread local storage for a single thread */
static
void
*
thread_local_storage
=
NULL
;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
DEBUG_PRINTF
(
"__objc_init_thread_system
\n
"
);
return
-
1
;
/* Failed. */
/* No thread support available */
return
-
1
;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system
(
void
)
{
/* No thread support available */
return
-
1
;
}
/********
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
return
NULL
;
/* We can't start threads. */
/* No thread support available */
return
NULL
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
return
-
1
;
/* Failed. */
/* No thread support available */
return
-
1
;
}
/********
* Return the current thread's priority.
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
/* Highest priority. */
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
return
;
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
exit
(
__objc_thread_exit_status
);
/* No thread support available */
/* Should we really exit the program */
/* exit(&__objc_thread_exit_status); */
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
return
(
objc_thread_t
)
1
;
/* No thread support, use 1.*/
/* No thread support, use 1. */
return
(
objc_thread_t
)
1
;
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
static
void
*
thread_local_storage
=
NULL
;
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
thread_local_storage
=
value
;
return
0
;
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__
objc_thread_get_data
(
void
)
{
return
thread_local_storage
;
}
/********
* Allocate a mutex. Return the mutex pointer if successful or NULL if the
* allocation failed for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
{
objc_mutex_t
mutex
;
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
mutex
->
owner
=
NULL
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
}
/********
* 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
;
/* # of locks on mutex. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int
objc_mutex_lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int
objc_mutex_trylock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
NULL
;
/* Set owner to "no thread".*/
return
0
;
/* No, return success. */
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate
(
objc_mutex_t
mutex
)
{
return
0
;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
return
0
;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock
(
objc_mutex_t
mutex
)
{
/* There can only be one thread, so we always get the lock */
return
0
;
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock
(
objc_mutex_t
mutex
)
{
/* There can only be one thread, so we always get the lock */
return
0
;
}
/* Unlock the mutex */
int
__objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
return
0
;
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate
(
objc_condition_t
condition
)
{
return
0
;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate
(
objc_condition_t
condition
)
{
return
0
;
}
/* Wait on the condition */
int
__objc_condition_wait
(
objc_condition_t
condition
,
objc_mutex_t
mutex
)
{
return
0
;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast
(
objc_condition_t
condition
)
{
return
0
;
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal
(
objc_condition_t
condition
)
{
return
0
;
}
/* End of File */
gcc/objc/thr-solaris.c
View file @
2024f9e4
...
...
@@ -32,400 +32,228 @@ Boston, MA 02111-1307, USA. */
#include <synch.h>
#include <errno.h>
/********
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct
objc_mutex
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
mutex_t
lock
;
/* System mutex. */
};
/* Key structure for maintiain thread specific storage */
static
thread_key_t
__objc_thread_data_key
;
struct
objc_condition
{
cond_t
condition
;
/* solaris condition */
};
/*****************************************************************************
* Static variables.
*/
static
thread_key_t
__objc_thread_data_key
;
/* Data key for thread data.*/
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
DEBUG_PRINTF
(
"__objc_init_thread_system
\n
"
);
if
(
thr_keycreate
(
&
__objc_thread_data_key
,
NULL
)
==
0
)
return
0
;
/* Yes, return success. */
return
-
1
;
/* Failed. */
/* Initialize the thread storage key */
if
(
thr_keycreate
(
&
__objc_thread_data_key
,
NULL
)
==
0
)
return
0
;
else
return
-
1
;
}
/* Close the threads subsystem. */
int
__objc_
fini
_thread_system
(
void
)
__objc_
close
_thread_system
(
void
)
{
return
0
;
}
/********
* Create a new thread of execution and return its id. Return -1 if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
objc_thread_t
thread_id
=
NULL
;
/* Detached thread id. */
thread_t
new_thread_id
=
0
;
/* Solaris thread id type. */
int
errn
;
objc_mutex_lock
(
__objc_runtime_mutex
);
objc_thread_t
thread_id
;
thread_t
new_thread_id
=
0
;
if
(
thr_create
(
NULL
,
0
,
(
void
*
)
func
,
arg
,
THR_DETACHED
|
THR_NEW_LWP
,
&
new_thread_id
)
==
0
)
{
/* Created new thread? */
thread_id
=
(
objc_thread_t
)
new_thread_id
;
/* Yes, remember its id. */
__objc_runtime_threads_alive
++
;
}
&
new_thread_id
)
==
0
)
thread_id
=
*
(
objc_thread_t
*
)
&
new_thread_id
;
else
thread_id
=
NULL
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
return
thread_id
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
int
sys_priority
=
0
;
int
sys_priority
=
0
;
switch
(
priority
)
{
switch
(
priority
)
{
case
OBJC_THREAD_INTERACTIVE_PRIORITY
:
sys_priority
=
300
;
break
;
sys_priority
=
300
;
break
;
default:
case
OBJC_THREAD_BACKGROUND_PRIORITY
:
sys_priority
=
200
;
break
;
sys_priority
=
200
;
break
;
case
OBJC_THREAD_LOW_PRIORITY
:
sys_priority
=
1000
;
break
;
sys_priority
=
1000
;
break
;
}
if
(
thr_setprio
(
thr_self
(),
sys_priority
)
==
0
)
return
0
;
/* Changed priority. End. */
return
-
1
;
/* Failed. */
/* Change priority */
if
(
thr_setprio
(
thr_self
(),
sys_priority
)
==
0
)
return
0
;
else
return
-
1
;
}
/********
* Return the current thread's priority.
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
int
sys_priority
;
/* Solaris thread priority. */
int
sys_priority
;
if
(
thr_getprio
(
thr_self
(),
&
sys_priority
)
==
0
)
{
if
(
sys_priority
>=
250
)
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
else
if
(
sys_priority
>=
150
)
return
OBJC_THREAD_BACKGROUND_PRIORITY
;
return
OBJC_THREAD_LOW_PRIORITY
;
if
(
thr_getprio
(
thr_self
(),
&
sys_priority
)
==
0
)
{
if
(
sys_priority
>=
250
)
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
else
if
(
sys_priority
>=
150
)
return
OBJC_THREAD_BACKGROUND_PRIORITY
;
return
OBJC_THREAD_LOW_PRIORITY
;
}
return
-
1
;
/* Couldn't get priority. */
/* Couldn't get priority. */
return
-
1
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
thr_yield
();
/* Yield to equal thread. */
thr_yield
();
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
objc_mutex_lock
(
__objc_runtime_mutex
);
__objc_runtime_threads_alive
++
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
thr_exit
(
&
__objc_thread_exit_status
);
/* Terminate thread. */
/* exit the thread */
thr_exit
(
&
__objc_thread_exit_status
);
/* Failed if we reached here */
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
return
(
objc_thread_t
)
thr_self
();
return
(
objc_thread_t
)
thr_self
();
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
if
(
thr_setspecific
(
__objc_thread_data_key
,
value
)
==
0
)
return
0
;
if
(
thr_setspecific
(
__objc_thread_data_key
,
value
)
==
0
)
return
0
;
else
return
-
1
;
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__
objc_thread_get_data
(
void
)
{
void
*
value
=
NULL
;
if
(
thr_getspecific
(
__objc_thread_data_key
,
&
value
)
==
0
)
return
value
;
/* Return thread data. */
return
NULL
;
}
void
*
value
=
NULL
;
/********
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
{
struct
objc_mutex
*
mutex
;
int
err
=
0
;
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
err
=
mutex_init
(
&
mutex
->
lock
,
USYNC_THREAD
,
0
);
if
(
err
!=
0
)
{
/* System init failed? */
objc_free
(
mutex
);
/* Yes, free local memory. */
return
NULL
;
/* Abort. */
}
mutex
->
owner
=
NULL
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
if
(
thr_getspecific
(
__objc_thread_data_key
,
&
value
)
==
0
)
return
value
;
return
NULL
;
}
/********
* 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 deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
/* Backend mutex functions */
/* Allocate a mutex. */
int
objc_mutex_de
allocate
(
objc_mutex_t
mutex
)
__objc_mutex_
allocate
(
objc_mutex_t
mutex
)
{
int
depth
;
/* # of locks on mutex. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
mutex_destroy
(
&
mutex
->
lock
);
/* System deallocate. */
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
if
(
mutex_init
(
(
mutex_t
*
)(
&
(
mutex
->
backend
)),
USYNC_THREAD
,
0
))
return
-
1
;
else
return
0
;
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
/* Deallocate a mutex. */
int
objc_mutex_lock
(
objc_mutex_t
mutex
)
__objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
if
(
mutex_lock
(
&
mutex
->
lock
)
!=
0
)
/* Did lock acquire fail? */
return
-
1
;
/* Yes, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
mutex_destroy
((
mutex_t
*
)(
&
(
mutex
->
backend
)));
return
0
;
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
/* Grab a lock on a mutex. */
int
objc_mutex_try
lock
(
objc_mutex_t
mutex
)
__objc_mutex_
lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
if
(
mutex_trylock
(
&
mutex
->
lock
)
!=
0
)
/* Did lock acquire fail? */
return
-
1
;
/* Yes, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
mutex
->
depth
=
1
;
/* Increment depth to end. */
if
(
mutex_lock
((
mutex_t
*
)(
&
(
mutex
->
backend
)))
!=
0
)
return
-
1
;
else
return
0
;
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Try to grab a lock on a mutex. */
int
objc_mutex_un
lock
(
objc_mutex_t
mutex
)
__objc_mutex_try
lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
NULL
;
/* Set owner to "no thread".*/
if
(
mutex_unlock
(
&
mutex
->
lock
)
!=
0
)
/* Did lock release fail? */
return
-
1
;
/* Yes, return error value. */
return
0
;
/* No, return success. */
if
(
mutex_trylock
((
mutex_t
*
)(
&
(
mutex
->
backend
)))
!=
0
)
return
-
1
;
else
return
0
;
}
/********
* Allocate a condition. Return the condition pointer if successful or NULL
* if the allocation failed for any reason.
*/
objc_condition_t
objc_condition_allocate
(
void
)
/* Unlock the mutex */
int
__objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
objc_condition_t
condition
;
if
(
!
(
condition
=
(
objc_condition_t
)
objc_malloc
(
sizeof
(
struct
objc_condition
))))
return
NULL
;
/* Abort if malloc failed. */
if
(
mutex_unlock
((
mutex_t
*
)(
&
(
mutex
->
backend
)))
!=
0
)
return
-
1
;
else
return
0
;
}
cond_init
(
&
(
condition
->
condition
),
USYNC_THREAD
,
NULL
);
/* Backend condition mutex functions */
return
condition
;
/* Return new condition */
/* Allocate a condition. */
int
__objc_condition_allocate
(
objc_condition_t
condition
)
{
return
cond_init
((
cond_t
*
)(
&
(
condition
->
backend
)),
USYNC_THREAD
,
NULL
);
}
/********
* Deallocate a condition. Note that this includes an implicit
* condition_broadcast to insure that waiting threads have the opportunity
* to wake. It is legal to dealloc a condition only if no other
* thread is/will be using it. Here we do NOT check for other threads
* waiting but just wake them up.
*/
/* Deallocate a condition. */
int
objc_condition_deallocate
(
objc_condition_t
condition
)
__
objc_condition_deallocate
(
objc_condition_t
condition
)
{
cond_broadcast
(
&
(
condition
->
condition
));
/* Wakeup waiting threads */
cond_destroy
(
&
(
condition
->
condition
));
/* Kill condition */
objc_free
(
condition
);
/* Release struct memory */
return
0
;
return
cond_destroy
((
cond_t
*
)(
&
(
condition
->
backend
)));
}
/********
* 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.
*/
/* Wait on the condition */
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
;
/* Cache our thread id. */
if
(
!
mutex
||
!
condition
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Locked more than once ? */
return
-
1
;
/* YES, return error */
/* mutex will be unlocked */
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
(
objc_thread_t
)
-
1
;
/* Set owner to "no thread".*/
cond_wait
(
&
(
condition
->
condition
),
&
(
mutex
->
lock
));
/* unlock, wait ..., lock */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
mutex
->
depth
=
1
;
/* Must be here ! */
return
0
;
/* Return success. */
return
cond_wait
((
cond_t
*
)(
&
(
condition
->
backend
)),
(
mutex_t
*
)(
&
(
mutex
->
backend
)));
}
/********
* Wake up all threads waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
/* Wake up all threads waiting on this condition. */
int
objc_condition_broadcast
(
objc_condition_t
condition
)
__
objc_condition_broadcast
(
objc_condition_t
condition
)
{
if
(
!
condition
)
return
-
1
;
cond_broadcast
(
&
(
condition
->
condition
));
return
0
;
return
cond_broadcast
((
cond_t
*
)(
&
(
condition
->
backend
)));
}
/********
* Wake up one thread waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
/* Wake up one thread waiting on this condition. */
int
objc_condition_signal
(
objc_condition_t
condition
)
__
objc_condition_signal
(
objc_condition_t
condition
)
{
if
(
!
condition
)
return
-
1
;
cond_signal
(
&
(
condition
->
condition
));
return
0
;
return
cond_signal
((
cond_t
*
)(
&
(
condition
->
backend
)));
}
/* End of File */
gcc/objc/thr-win32.c
View file @
2024f9e4
...
...
@@ -32,306 +32,241 @@ Boston, MA 02111-1307, USA. */
#endif
#include <windows.h>
/********
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct
objc_mutex
{
volatile
objc_thread_t
owner
;
/* Id of thread that owns. */
volatile
int
depth
;
/* # of acquires. */
HANDLE
handle
;
/* Win32 mutex HANDLE. */
};
/*****************************************************************************
* Static variables.
*/
static
DWORD
__objc_data_tls
=
(
DWORD
)
-
1
;
/* Win32 Thread Local Index.*/
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
/* Key structure for maintiain thread specific storage */
static
DWORD
__objc_data_tls
=
(
DWORD
)
-
1
;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system
(
void
)
{
DEBUG_PRINTF
(
"__objc_init_thread_system
\n
"
);
/* Initialize the thread storage key */
if
((
__objc_data_tls
=
TlsAlloc
())
!=
(
DWORD
)
-
1
)
return
0
;
/* Yes, return success. */
return
-
1
;
/* Failed. */
return
0
;
else
return
-
1
;
}
/* Close the threads subsystem. */
int
__objc_
fini
_thread_system
(
void
)
__objc_
close
_thread_system
(
void
)
{
if
(
__objc_data_tls
!=
(
DWORD
)
-
1
)
{
if
(
__objc_data_tls
!=
(
DWORD
)
-
1
)
TlsFree
(
__objc_data_tls
);
return
0
;
}
return
-
1
;
return
0
;
}
/********
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument.
*/
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
objc_thread_create
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
__objc_thread_detach
(
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
DWORD
thread_id
=
0
;
/* Detached thread id. */
HANDLE
win32_handle
;
/* Win32 thread handle. */
DWORD
thread_id
=
0
;
HANDLE
win32_handle
;
objc_mutex_lock
(
__objc_runtime_mutex
);
if
((
win32_handle
=
CreateThread
(
NULL
,
0
,
(
LPTHREAD_START_ROUTINE
)
func
,
arg
,
0
,
&
thread_id
)))
{
__objc_runtime_threads_alive
++
;
}
else
thread_id
=
0
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
if
(
!
(
win32_handle
=
CreateThread
(
NULL
,
0
,
(
LPTHREAD_START_ROUTINE
)
func
,
arg
,
0
,
&
thread_id
)))
thread_id
=
0
;
return
(
objc_thread_t
)
thread_id
;
}
/********
* Set the current thread's priority.
*/
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
__
objc_thread_set_priority
(
int
priority
)
{
int
sys_priority
=
0
;
switch
(
priority
)
{
case
OBJC_THREAD_INTERACTIVE_PRIORITY
:
sys_priority
=
THREAD_PRIORITY_NORMAL
;
break
;
default:
case
OBJC_THREAD_BACKGROUND_PRIORITY
:
sys_priority
=
THREAD_PRIORITY_BELOW_NORMAL
;
break
;
case
OBJC_THREAD_LOW_PRIORITY
:
sys_priority
=
THREAD_PRIORITY_LOWEST
;
break
;
}
int
sys_priority
=
0
;
switch
(
priority
)
{
case
OBJC_THREAD_INTERACTIVE_PRIORITY
:
sys_priority
=
THREAD_PRIORITY_NORMAL
;
break
;
default:
case
OBJC_THREAD_BACKGROUND_PRIORITY
:
sys_priority
=
THREAD_PRIORITY_BELOW_NORMAL
;
break
;
case
OBJC_THREAD_LOW_PRIORITY
:
sys_priority
=
THREAD_PRIORITY_LOWEST
;
break
;
}
/* Change priority */
if
(
SetThreadPriority
(
GetCurrentThread
(),
sys_priority
))
return
0
;
/* Changed priority. End. */
return
-
1
;
/* Failed. */
return
0
;
else
return
-
1
;
}
/********
* Return the current thread's priority.
*/
/* Return the current thread's priority. */
int
objc_thread_get_priority
(
void
)
__
objc_thread_get_priority
(
void
)
{
int
sys_priority
;
int
sys_priority
;
sys_priority
=
GetThreadPriority
(
GetCurrentThread
());
switch
(
sys_priority
)
{
case
THREAD_PRIORITY_HIGHEST
:
case
THREAD_PRIORITY_TIME_CRITICAL
:
case
THREAD_PRIORITY_ABOVE_NORMAL
:
case
THREAD_PRIORITY_NORMAL
:
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
default:
case
THREAD_PRIORITY_BELOW_NORMAL
:
return
OBJC_THREAD_BACKGROUND_PRIORITY
;
switch
(
sys_priority
)
{
case
THREAD_PRIORITY_HIGHEST
:
case
THREAD_PRIORITY_TIME_CRITICAL
:
case
THREAD_PRIORITY_ABOVE_NORMAL
:
case
THREAD_PRIORITY_NORMAL
:
return
OBJC_THREAD_INTERACTIVE_PRIORITY
;
default:
case
THREAD_PRIORITY_BELOW_NORMAL
:
return
OBJC_THREAD_BACKGROUND_PRIORITY
;
case
THREAD_PRIORITY_IDLE
:
case
THREAD_PRIORITY_LOWEST
:
return
OBJC_THREAD_LOW_PRIORITY
;
}
return
-
1
;
/* Couldn't get priority. */
case
THREAD_PRIORITY_IDLE
:
case
THREAD_PRIORITY_LOWEST
:
return
OBJC_THREAD_LOW_PRIORITY
;
}
/* Couldn't get priority. */
return
-
1
;
}
/********
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
/* Yield our process time to another thread. */
void
objc_thread_yield
(
void
)
__
objc_thread_yield
(
void
)
{
Sleep
(
0
);
/* Yield to equal thread. */
Sleep
(
0
);
}
/********
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
/* Terminate the current thread. */
int
objc_thread_exit
(
void
)
__
objc_thread_exit
(
void
)
{
objc_mutex_lock
(
__objc_runtime_mutex
);
__objc_runtime_threads_alive
--
;
objc_mutex_unlock
(
__objc_runtime_mutex
);
ExitThread
(
__objc_thread_exit_status
);
/* Terminate thread. */
/* exit the thread */
ExitThread
(
__objc_thread_exit_status
);
/* Failed if we reached here */
return
-
1
;
}
/********
* Returns an integer value which uniquely describes a thread. Must not be
* -1 which is reserved as a marker for "no thread".
*/
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
objc_thread_id
(
void
)
__
objc_thread_id
(
void
)
{
return
(
objc_thread_t
)
GetCurrentThreadId
();
/* Return thread id. */
return
(
objc_thread_t
)
GetCurrentThreadId
();
}
/********
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
/* Sets the thread's local storage pointer. */
int
objc_thread_set_data
(
void
*
value
)
__
objc_thread_set_data
(
void
*
value
)
{
if
(
TlsSetValue
(
__objc_data_tls
,
value
))
return
0
;
/* Return thread data. */
return
-
1
;
return
0
;
else
return
-
1
;
}
/********
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
/* Returns the thread's local storage pointer. */
void
*
objc_thread_get_data
(
void
)
__
objc_thread_get_data
(
void
)
{
return
TlsGetValue
(
__objc_data_tls
);
/* Return thread data. */
}
/********
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate
(
objc_mutex_t
mutex
)
{
if
((
mutex
->
backend
=
(
void
*
)
CreateMutex
(
NULL
,
0
,
NULL
))
==
NULL
)
return
-
1
;
else
return
0
;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate
(
objc_mutex_t
mutex
)
{
objc_mutex_t
mutex
;
int
err
=
0
;
CloseHandle
((
HANDLE
)(
mutex
->
backend
));
return
0
;
}
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Abort if malloc failed. */
/* Grab a lock on a mutex. */
int
__objc_mutex_lock
(
objc_mutex_t
mutex
)
{
int
status
;
if
((
mutex
->
handle
=
CreateMutex
(
NULL
,
0
,
NULL
))
==
NULL
)
{
objc_free
(
mutex
);
/* Failed, free memory. */
return
NULL
;
/* Abort. */
}
mutex
->
owner
=
NULL
;
/* No owner. */
mutex
->
depth
=
0
;
/* No locks. */
return
mutex
;
/* Return mutex handle. */
status
=
WaitForSingleObject
((
HANDLE
)(
mutex
->
backend
),
INFINITE
);
if
(
status
!=
WAIT_OBJECT_0
&&
status
!=
WAIT_ABANDONED
)
return
-
1
;
else
return
0
;
}
/********
* 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 deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
/* Try to grab a lock on a mutex. */
int
objc_mutex_deallocate
(
objc_mutex_t
mutex
)
__objc_mutex_trylock
(
objc_mutex_t
mutex
)
{
int
depth
;
/* # of locks on mutex. */
int
status
;
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
depth
=
objc_mutex_lock
(
mutex
);
/* Must have lock. */
status
=
WaitForSingleObject
((
HANDLE
)(
mutex
->
backend
),
0
);
if
(
status
!=
WAIT_OBJECT_0
&&
status
!=
WAIT_ABANDONED
)
return
-
1
;
else
return
0
;
}
CloseHandle
(
mutex
->
handle
);
/* Close Win32 handle. */
objc_free
(
mutex
);
/* Free memory. */
return
depth
;
/* Return last depth. */
/* Unlock the mutex */
int
__objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
if
(
ReleaseMutex
((
HANDLE
)(
mutex
->
backend
))
==
0
)
return
-
1
;
else
return
0
;
}
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
/* Backend condition mutex functions */
/* Allocate a condition. */
int
objc_mutex_lock
(
objc_mutex_t
mutex
)
__objc_condition_allocate
(
objc_condition_t
condition
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
int
status
;
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
status
=
WaitForSingleObject
(
mutex
->
handle
,
INFINITE
);
if
(
status
!=
WAIT_OBJECT_0
&&
status
!=
WAIT_ABANDONED
)
return
-
1
;
/* Failed, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
/* Unimplemented. */
return
-
1
;
}
return
++
mutex
->
depth
;
/* Increment depth to end. */
/* Deallocate a condition. */
int
__objc_condition_deallocate
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
}
/********
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
/* Wait on the condition */
int
objc_mutex_trylock
(
objc_mutex_t
mutex
)
__objc_condition_wait
(
objc_condition_t
condition
,
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
DWORD
status
;
/* Return status from Win32.*/
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
==
thread_id
)
/* Already own lock? */
return
++
mutex
->
depth
;
/* Yes, increment depth. */
status
=
WaitForSingleObject
(
mutex
->
handle
,
0
);
if
(
status
!=
WAIT_OBJECT_0
&&
status
!=
WAIT_ABANDONED
)
return
-
1
;
/* Failed, abort. */
mutex
->
owner
=
thread_id
;
/* Mark thread as owner. */
return
++
mutex
->
depth
;
/* Increment depth to end. */
/* Unimplemented. */
return
-
1
;
}
/********
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Wake up all threads waiting on this condition. */
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
__objc_condition_broadcast
(
objc_condition_t
condition
)
{
objc_thread_t
thread_id
;
/* Cache our thread id. */
if
(
!
mutex
)
/* Is argument bad? */
return
-
1
;
/* Yes, abort. */
thread_id
=
objc_thread_id
();
/* Get this thread's id. */
if
(
mutex
->
owner
!=
thread_id
)
/* Does some else own lock? */
return
-
1
;
/* Yes, abort. */
if
(
mutex
->
depth
>
1
)
/* Released last lock? */
return
--
mutex
->
depth
;
/* No, Decrement depth, end.*/
mutex
->
depth
=
0
;
/* Yes, reset depth to 0. */
mutex
->
owner
=
NULL
;
/* Set owner to "no thread".*/
if
(
ReleaseMutex
(
mutex
->
handle
)
==
0
)
return
-
1
;
/* Failed, abort. */
return
0
;
/* No, return success. */
/* Unimplemented. */
return
-
1
;
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal
(
objc_condition_t
condition
)
{
/* Unimplemented. */
return
-
1
;
}
/* End of File */
gcc/objc/thr.c
View file @
2024f9e4
...
...
@@ -27,20 +27,15 @@ Boston, MA 02111-1307, USA. */
#include <stdlib.h>
#include "runtime.h"
/*************************************************************************
* Universal static variables:
*/
int
__objc_thread_exit_status
=
0
;
/* Global exit status. */
/* Global exit status. */
int
__objc_thread_exit_status
=
0
;
/* Flag which lets us know if we ever became multi threaded */
int
__objc_is_multi_threaded
=
0
;
/* The hook function called when the runtime becomes multi threaded */
objc_thread_callback
_objc_became_multi_threaded
=
NULL
;
/*****************************************************************************
* Universal Functionality
*/
/*
Use this to set the hook function that will be called when the
runtime initially becomes multi threaded.
...
...
@@ -60,94 +55,480 @@ objc_thread_callback objc_set_thread_callback(objc_thread_callback func)
return
temp
;
}
/********
* First function called in a thread, starts everything else.
/*
Private functions
These functions are utilized by the frontend, but they are not
considered part of the public interface.
*/
/*
First function called in a thread, starts everything else.
This function is passed to the backend by objc_thread_detach
as the starting function for a new thread.
*/
struct
__objc_thread_start_state
{
SEL
selector
;
id
object
;
id
argument
;
SEL
selector
;
id
object
;
id
argument
;
};
static
volatile
void
__objc_thread_detach_function
(
struct
__objc_thread_start_state
*
istate
)
{
if
(
istate
)
{
/* Is state valid? */
id
(
*
imp
)(
id
,
SEL
,
id
);
SEL
selector
=
istate
->
selector
;
id
object
=
istate
->
object
;
id
argument
=
istate
->
argument
;
/* Valid state? */
if
(
istate
)
{
id
(
*
imp
)(
id
,
SEL
,
id
);
SEL
selector
=
istate
->
selector
;
id
object
=
istate
->
object
;
id
argument
=
istate
->
argument
;
objc_free
(
istate
);
/* Don't need anymore so free it */
objc_free
(
istate
);
/* Clear out the thread local storage */
objc_thread_set_data
(
NULL
);
/* Clear out the thread local storage */
objc_thread_set_data
(
NULL
);
/* Check to see if we just became multi threaded */
if
(
!
__objc_is_multi_threaded
)
{
__objc_is_multi_threaded
=
1
;
/* Check to see if we just became 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
)();
}
/* Call the hook function */
if
(
_objc_became_multi_threaded
!=
NULL
)
(
*
_objc_became_multi_threaded
)();
}
if
((
imp
=
(
id
(
*
)(
id
,
SEL
,
id
))
objc_msg_lookup
(
object
,
selector
)))
{
(
*
imp
)(
object
,
selector
,
argument
);
}
else
fprintf
(
stderr
,
"__objc_thread_start called with bad selector.
\n
"
);
}
else
{
fprintf
(
stderr
,
"__objc_thread_start called with NULL state.
\n
"
);
}
objc_thread_exit
();
/* Call the method */
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
"
);
}
else
objc_error
(
nil
,
OBJC_ERR_BAD_STATE
,
"objc_thread_detach called with NULL state.
\n
"
);
/* Exit the thread */
objc_thread_exit
();
}
/********
* 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.
*/
/*
Frontend functions
These functions constitute the public interface to the Objective-C thread
and mutex functionality.
*/
/* Frontend thread functions */
/*
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
;
/* Initialial thread state. */
objc_thread_t
thread_id
=
NULL
;
/* Detached thread id. */
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
))))
/* Can we allocate state? */
return
NULL
;
/* No, abort. */
objc_malloc
(
sizeof
(
*
istate
))))
return
NULL
;
istate
->
selector
=
selector
;
/* Initialize the thread's */
istate
->
object
=
object
;
/* state structure. */
/* Initialize the state structure */
istate
->
selector
=
selector
;
istate
->
object
=
object
;
istate
->
argument
=
argument
;
if
((
thread_id
=
objc_thread_create
((
void
*
)
__objc_thread_detach_function
,
istate
))
==
NULL
)
{
objc_free
(
istate
);
/* Release state if failed. */
return
thread_id
;
}
/* 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
;
}
#undef objc_mutex_lock()
#undef objc_mutex_unlock()
/* Set the current thread's priority. */
int
objc_thread_set_priority
(
int
priority
)
{
/* Call the backend */
return
__objc_thread_set_priority
(
priority
);
}
/* Return the current thread's priority. */
int
objc_
mutex_unlock_x
(
objc_mutex_t
mutex
,
const
char
*
f
,
int
l
)
objc_
thread_get_priority
(
void
)
{
printf
(
"%16.16s#%4d < unlock"
,
f
,
l
);
return
objc_mutex_unlock
(
mutex
);
/* Call the backend */
return
__objc_thread_get_priority
(
);
}
/*
Yield our process time to another thread. Any BUSY waiting that is done
by a thread should use this function to make sure that other threads can
make progress even on a lazy uniprocessor system.
*/
void
objc_thread_yield
(
void
)
{
/* Call the backend */
__objc_thread_yield
();
}
/*
Terminate the current tread. Doesn't return.
Actually, if it failed returns -1.
*/
int
objc_
mutex_lock_x
(
objc_mutex_t
mutex
,
const
char
*
f
,
int
l
)
objc_
thread_exit
(
void
)
{
printf
(
"%16.16s#%4d < lock"
,
f
,
l
);
return
objc_mutex_lock
(
mutex
);
/* 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
();
}
/*
Returns an integer value which uniquely describes a thread. Must not be
NULL which is reserved as a marker for "no thread".
*/
objc_thread_t
objc_thread_id
(
void
)
{
/* Call the backend */
return
__objc_thread_id
();
}
/*
Sets the thread's local storage pointer.
Returns 0 if successful or -1 if failed.
*/
int
objc_thread_set_data
(
void
*
value
)
{
/* Call the backend */
return
__objc_thread_set_data
(
value
);
}
/*
Returns the thread's local storage pointer. Returns NULL on failure.
*/
void
*
objc_thread_get_data
(
void
)
{
/* Call the backend */
return
__objc_thread_get_data
();
}
/* Frontend mutex functions */
/*
Allocate a mutex. Return the mutex pointer if successful or NULL if the
allocation failed for any reason.
*/
objc_mutex_t
objc_mutex_allocate
(
void
)
{
objc_mutex_t
mutex
;
/* Allocate the mutex structure */
if
(
!
(
mutex
=
(
objc_mutex_t
)
objc_malloc
(
sizeof
(
struct
objc_mutex
))))
return
NULL
;
/* Call backend to create the mutex */
if
(
__objc_mutex_allocate
(
mutex
))
{
/* failed! */
objc_free
(
mutex
);
return
NULL
;
}
/* Initialize mutex */
mutex
->
owner
=
NULL
;
mutex
->
depth
=
0
;
return
mutex
;
}
/*
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
;
}
/*
Grab a lock on a mutex. If this thread already has a lock on this mutex
then we increment the lock count. If another thread has a lock on the
mutex we block and wait for the thread to release the lock.
Returns the lock count on the mutex held by this thread.
*/
int
objc_mutex_lock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
int
status
;
/* Valid mutex? */
if
(
!
mutex
)
return
-
1
;
/* If we already own the lock then increment depth */
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
);
/* Failed? */
if
(
status
)
return
status
;
/* Successfully locked the thread */
mutex
->
owner
=
thread_id
;
return
mutex
->
depth
=
1
;
}
/*
Try to grab a lock on a mutex. If this thread already has a lock on
this mutex then we increment the lock count and return it. If another
thread has a lock on the mutex returns -1.
*/
int
objc_mutex_trylock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
int
status
;
/* Valid mutex? */
if
(
!
mutex
)
return
-
1
;
/* If we already own the lock then increment depth */
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
);
/* Failed? */
if
(
status
)
return
status
;
/* Successfully locked the thread */
mutex
->
owner
=
thread_id
;
return
mutex
->
depth
=
1
;
}
/*
Unlocks the mutex by one level.
Decrements the lock count on this mutex by one.
If the lock count reaches zero, release the lock on the mutex.
Returns the lock count on the mutex.
It is an error to attempt to unlock a mutex which this thread
doesn't hold in which case return -1 and the mutex is unaffected.
*/
int
objc_mutex_unlock
(
objc_mutex_t
mutex
)
{
objc_thread_t
thread_id
;
int
status
;
/* Valid mutex? */
if
(
!
mutex
)
return
-
1
;
/* If another thread owns the lock then abort */
thread_id
=
objc_thread_id
();
if
(
mutex
->
owner
!=
thread_id
)
return
-
1
;
/* Decrement depth and return */
if
(
mutex
->
depth
>
1
)
return
--
mutex
->
depth
;
/* Depth down to zero so we are no longer the owner */
mutex
->
depth
=
0
;
mutex
->
owner
=
NULL
;
/* Have the backend unlock the mutex */
status
=
__objc_mutex_unlock
(
mutex
);
/* Failed? */
if
(
status
)
return
status
;
return
0
;
}
/* Frontend condition mutex functions */
/*
Allocate a condition. Return the condition pointer if successful or NULL
if the allocation failed for any reason.
*/
objc_condition_t
objc_condition_allocate
(
void
)
{
objc_condition_t
condition
;
/* Allocate the condition mutex structure */
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
))
{
/* failed! */
objc_free
(
condition
);
return
NULL
;
}
/* Success! */
return
condition
;
}
/*
Deallocate a condition. Note that this includes an implicit
condition_broadcast to insure that waiting threads have the opportunity
to wake. It is legal to dealloc a condition only if no other
thread is/will be using it. Here we do NOT check for other threads
waiting but just wake them up.
*/
int
objc_condition_deallocate
(
objc_condition_t
condition
)
{
/* Broadcast the condition */
if
(
objc_condition_broadcast
(
condition
))
return
-
1
;
/* Call the backend to destroy */
if
(
__objc_condition_deallocate
(
condition
))
return
-
1
;
/* Free the condition mutex structure */
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
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_thread_t
thread_id
;
/* Valid arguments? */
if
(
!
mutex
||
!
condition
)
return
-
1
;
/* Make sure we are owner of mutex */
thread_id
=
objc_thread_id
();
if
(
mutex
->
owner
!=
thread_id
)
return
-
1
;
/* Cannot be locked more than once */
if
(
mutex
->
depth
>
1
)
return
-
1
;
/* Virtually unlock the mutex */
mutex
->
depth
=
0
;
mutex
->
owner
=
(
objc_thread_t
)
NULL
;
/* Call the backend to wait */
__objc_condition_wait
(
condition
,
mutex
);
/* Make ourselves owner of the mutex */
mutex
->
owner
=
thread_id
;
mutex
->
depth
=
1
;
return
0
;
}
/*
Wake up all threads waiting on this condition. It is recommended that
the called would lock the same mutex as the threads in objc_condition_wait
before changing the "condition predicate" and make this call and unlock it
right away after this call.
*/
int
objc_condition_broadcast
(
objc_condition_t
condition
)
{
/* Valid condition mutex? */
if
(
!
condition
)
return
-
1
;
return
__objc_condition_broadcast
(
condition
);
}
/*
Wake up one thread waiting on this condition. It is recommended that
the called would lock the same mutex as the threads in objc_condition_wait
before changing the "condition predicate" and make this call and unlock it
right away after this call.
*/
int
objc_condition_signal
(
objc_condition_t
condition
)
{
/* Valid condition mutex? */
if
(
!
condition
)
return
-
1
;
return
__objc_condition_signal
(
condition
);
}
/* End of File */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment