mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 16:09:47 +00:00
400 lines
11 KiB
C
400 lines
11 KiB
C
/*
|
|
* pthread_set.c
|
|
*
|
|
* Description:
|
|
* POSIX thread functions related to state.
|
|
*
|
|
* --------------------------------------------------------------------------
|
|
*
|
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
|
* Copyright(C) 2008 Jason Schmidlapp
|
|
*
|
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
|
*
|
|
*
|
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
|
* Copyright(C) 1998 John E. Bossom
|
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
|
*
|
|
* Contact Email: rpj@callisto.canberra.edu.au
|
|
*
|
|
* The original list of contributors to the Pthreads-win32 project
|
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
|
* source code distribution. The list can also be seen at the
|
|
* following World Wide Web location:
|
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library in the file COPYING.LIB;
|
|
* if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
*/
|
|
|
|
#include "pthread.h"
|
|
#include "implement.h"
|
|
#include "sched.h"
|
|
|
|
int pthread_setcancelstate (int state, int *oldstate)
|
|
/*
|
|
* ------------------------------------------------------
|
|
* DOCPUBLIC
|
|
* This function atomically sets the calling thread's
|
|
* cancelability state to 'state' and returns the previous
|
|
* cancelability state at the location referenced by
|
|
* 'oldstate'
|
|
*
|
|
* PARAMETERS
|
|
* state,
|
|
* oldstate
|
|
* PTHREAD_CANCEL_ENABLE
|
|
* cancellation is enabled,
|
|
*
|
|
* PTHREAD_CANCEL_DISABLE
|
|
* cancellation is disabled
|
|
*
|
|
*
|
|
* DESCRIPTION
|
|
* This function atomically sets the calling thread's
|
|
* cancelability state to 'state' and returns the previous
|
|
* cancelability state at the location referenced by
|
|
* 'oldstate'.
|
|
*
|
|
* NOTES:
|
|
* 1) Use to disable cancellation around 'atomic' code that
|
|
* includes cancellation points
|
|
*
|
|
* COMPATIBILITY ADDITIONS
|
|
* If 'oldstate' is NULL then the previous state is not returned
|
|
* but the function still succeeds. (Solaris)
|
|
*
|
|
* RESULTS
|
|
* 0 successfully set cancelability type,
|
|
* EINVAL 'state' is invalid
|
|
*
|
|
* ------------------------------------------------------
|
|
*/
|
|
{
|
|
int result = 0;
|
|
pthread_t self = pthread_self ();
|
|
pte_thread_t * sp = (pte_thread_t *) self;
|
|
|
|
if (sp == NULL
|
|
|| (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE))
|
|
return EINVAL;
|
|
|
|
/*
|
|
* Lock for async-cancel safety.
|
|
*/
|
|
(void) pthread_mutex_lock (&sp->cancelLock);
|
|
|
|
if (oldstate != NULL)
|
|
*oldstate = sp->cancelState;
|
|
|
|
sp->cancelState = state;
|
|
|
|
/*
|
|
* Check if there is a pending asynchronous cancel
|
|
*/
|
|
if (state == PTHREAD_CANCEL_ENABLE
|
|
&& (sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS)
|
|
&& (pte_osThreadCheckCancel(sp->threadId) == PTE_OS_INTERRUPTED) )
|
|
{
|
|
sp->state = PThreadStateCanceling;
|
|
sp->cancelState = PTHREAD_CANCEL_DISABLE;
|
|
(void) pthread_mutex_unlock (&sp->cancelLock);
|
|
pte_throw (PTE_EPS_CANCEL);
|
|
|
|
/* Never reached */
|
|
}
|
|
|
|
(void) pthread_mutex_unlock (&sp->cancelLock);
|
|
|
|
return (result);
|
|
}
|
|
|
|
int pthread_setcanceltype (int type, int *oldtype)
|
|
/*
|
|
* ------------------------------------------------------
|
|
* DOCPUBLIC
|
|
* This function atomically sets the calling thread's
|
|
* cancelability type to 'type' and returns the previous
|
|
* cancelability type at the location referenced by
|
|
* 'oldtype'
|
|
*
|
|
* PARAMETERS
|
|
* type,
|
|
* oldtype
|
|
* PTHREAD_CANCEL_DEFERRED
|
|
* only deferred cancelation is allowed,
|
|
*
|
|
* PTHREAD_CANCEL_ASYNCHRONOUS
|
|
* Asynchronous cancellation is allowed
|
|
*
|
|
*
|
|
* DESCRIPTION
|
|
* This function atomically sets the calling thread's
|
|
* cancelability type to 'type' and returns the previous
|
|
* cancelability type at the location referenced by
|
|
* 'oldtype'
|
|
*
|
|
* NOTES:
|
|
* 1) Use with caution; most code is not safe for use
|
|
* with asynchronous cancelability.
|
|
*
|
|
* COMPATIBILITY ADDITIONS
|
|
* If 'oldtype' is NULL then the previous type is not returned
|
|
* but the function still succeeds. (Solaris)
|
|
*
|
|
* RESULTS
|
|
* 0 successfully set cancelability type,
|
|
* EINVAL 'type' is invalid
|
|
* EPERM Async cancellation is not supported.
|
|
*
|
|
* ------------------------------------------------------
|
|
*/
|
|
{
|
|
int result = 0;
|
|
pthread_t self = pthread_self ();
|
|
pte_thread_t * sp = (pte_thread_t *) self;
|
|
|
|
#ifndef PTE_SUPPORT_ASYNC_CANCEL
|
|
if (type == PTHREAD_CANCEL_ASYNCHRONOUS)
|
|
{
|
|
/* Async cancellation is not supported at this time. See notes in
|
|
* pthread_cancel.
|
|
*/
|
|
return EPERM;
|
|
}
|
|
#endif /* PTE_SUPPORT_ASYNC_CANCEL */
|
|
|
|
if (sp == NULL
|
|
|| (type != PTHREAD_CANCEL_DEFERRED
|
|
&& type != PTHREAD_CANCEL_ASYNCHRONOUS))
|
|
return EINVAL;
|
|
|
|
/*
|
|
* Lock for async-cancel safety.
|
|
*/
|
|
(void) pthread_mutex_lock (&sp->cancelLock);
|
|
|
|
if (oldtype != NULL)
|
|
*oldtype = sp->cancelType;
|
|
|
|
sp->cancelType = type;
|
|
|
|
/*
|
|
* Check if there is a pending asynchronous cancel
|
|
*/
|
|
|
|
if (sp->cancelState == PTHREAD_CANCEL_ENABLE
|
|
&& (type == PTHREAD_CANCEL_ASYNCHRONOUS)
|
|
&& (pte_osThreadCheckCancel(sp->threadId) == PTE_OS_INTERRUPTED) )
|
|
{
|
|
sp->state = PThreadStateCanceling;
|
|
sp->cancelState = PTHREAD_CANCEL_DISABLE;
|
|
(void) pthread_mutex_unlock (&sp->cancelLock);
|
|
pte_throw (PTE_EPS_CANCEL);
|
|
|
|
/* Never reached */
|
|
}
|
|
|
|
(void) pthread_mutex_unlock (&sp->cancelLock);
|
|
|
|
return (result);
|
|
}
|
|
|
|
int pthread_setconcurrency (int level)
|
|
{
|
|
if (level < 0)
|
|
return EINVAL;
|
|
|
|
pte_concurrency = level;
|
|
return 0;
|
|
}
|
|
|
|
int pthread_setschedparam (pthread_t thread, int policy,
|
|
const struct sched_param *param)
|
|
{
|
|
int result;
|
|
|
|
/* Validate the thread id. */
|
|
result = pthread_kill (thread, 0);
|
|
if (0 != result)
|
|
return result;
|
|
|
|
/* Validate the scheduling policy. */
|
|
if (policy < SCHED_MIN || policy > SCHED_MAX)
|
|
return EINVAL;
|
|
|
|
/* Ensure the policy is SCHED_OTHER. */
|
|
if (policy != SCHED_OTHER)
|
|
return ENOTSUP;
|
|
|
|
return (pte_setthreadpriority (thread, policy, param->sched_priority));
|
|
}
|
|
|
|
|
|
int
|
|
pte_setthreadpriority (pthread_t thread, int policy, int priority)
|
|
{
|
|
int prio;
|
|
int result;
|
|
pte_thread_t * tp = (pte_thread_t *) thread;
|
|
|
|
prio = priority;
|
|
|
|
/* Validate priority level. */
|
|
if (prio < sched_get_priority_min (policy) ||
|
|
prio > sched_get_priority_max (policy))
|
|
return EINVAL;
|
|
|
|
result = pthread_mutex_lock (&tp->threadLock);
|
|
|
|
if (0 == result)
|
|
{
|
|
/* If this fails, the current priority is unchanged. */
|
|
|
|
if (0 != pte_osThreadSetPriority(tp->threadId, prio))
|
|
result = EINVAL;
|
|
else
|
|
{
|
|
/*
|
|
* Must record the thread's sched_priority as given,
|
|
* not as finally adjusted.
|
|
*/
|
|
tp->sched_priority = priority;
|
|
}
|
|
|
|
(void) pthread_mutex_unlock (&tp->threadLock);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int pthread_setspecific (pthread_key_t key, const void *value)
|
|
/*
|
|
* ------------------------------------------------------
|
|
* DOCPUBLIC
|
|
* This function sets the value of the thread specific
|
|
* key in the calling thread.
|
|
*
|
|
* PARAMETERS
|
|
* key
|
|
* an instance of pthread_key_t
|
|
* value
|
|
* the value to set key to
|
|
*
|
|
*
|
|
* DESCRIPTION
|
|
* This function sets the value of the thread specific
|
|
* key in the calling thread.
|
|
*
|
|
* RESULTS
|
|
* 0 successfully set value
|
|
* EAGAIN could not set value
|
|
* ENOENT SERIOUS!!
|
|
*
|
|
* ------------------------------------------------------
|
|
*/
|
|
{
|
|
pthread_t self;
|
|
int result = 0;
|
|
|
|
if (key != pte_selfThreadKey)
|
|
{
|
|
/*
|
|
* Using pthread_self will implicitly create
|
|
* an instance of pthread_t for the current
|
|
* thread if one wasn't explicitly created
|
|
*/
|
|
self = pthread_self ();
|
|
if (self == NULL)
|
|
return ENOENT;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Resolve catch-22 of registering thread with selfThread
|
|
* key
|
|
*/
|
|
pte_thread_t * sp = (pte_thread_t *) pthread_getspecific (pte_selfThreadKey);
|
|
|
|
if (sp == NULL)
|
|
{
|
|
if (value == NULL)
|
|
return ENOENT;
|
|
|
|
self = *((pthread_t *) value);
|
|
}
|
|
else
|
|
self = sp;
|
|
}
|
|
|
|
result = 0;
|
|
|
|
if (key != NULL)
|
|
{
|
|
if (self != NULL && key->destructor != NULL && value != NULL)
|
|
{
|
|
/*
|
|
* Only require associations if we have to
|
|
* call user destroy routine.
|
|
* Don't need to locate an existing association
|
|
* when setting data to NULL since the
|
|
* data is stored with the operating system; not
|
|
* on the association; setting assoc to NULL short
|
|
* circuits the search.
|
|
*/
|
|
ThreadKeyAssoc *assoc;
|
|
|
|
if (pthread_mutex_lock(&(key->keyLock)) == 0)
|
|
{
|
|
pte_thread_t * sp = (pte_thread_t *) self;
|
|
|
|
(void) pthread_mutex_lock(&(sp->threadLock));
|
|
|
|
assoc = (ThreadKeyAssoc *) sp->keys;
|
|
/*
|
|
* Locate existing association
|
|
*/
|
|
while (assoc != NULL)
|
|
{
|
|
/*
|
|
* Association already exists
|
|
*/
|
|
if (assoc->key == key)
|
|
break;
|
|
assoc = assoc->nextKey;
|
|
}
|
|
|
|
/*
|
|
* create an association if not found
|
|
*/
|
|
if (assoc == NULL)
|
|
result = pte_tkAssocCreate (sp, key);
|
|
|
|
(void) pthread_mutex_unlock(&(sp->threadLock));
|
|
}
|
|
(void) pthread_mutex_unlock(&(key->keyLock));
|
|
}
|
|
|
|
if (result == 0)
|
|
{
|
|
if (pte_osTlsSetValue (key->key, (void *) value) != PTE_OS_OK)
|
|
result = EAGAIN;
|
|
}
|
|
}
|
|
|
|
return (result);
|
|
}
|