RetroArch/deps/pthreads/pthread_set.c
2017-12-26 20:52:03 +01:00

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);
}