freeswitch/libs/xmlrpc-c/lib/abyss/src/thread_pthread.c

260 lines
4.9 KiB
C

#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include "xmlrpc_config.h"
#include "bool.h"
#include "mallocvar.h"
#include "xmlrpc-c/util_int.h"
#include "xmlrpc-c/string_int.h"
#include "pthreadx.h"
#include "xmlrpc-c/abyss.h"
#include "thread.h"
struct abyss_thread {
pthread_t thread;
void * userHandle;
TThreadProc * func;
TThreadDoneFn * threadDone;
};
/* We used to have MIN_STACK_SIZE = 16K, which was said to be the
minimum stack size on Win32. Scott Kolodzeski found in November
2005 that this was insufficient for 64 bit Solaris -- we fail
when creating the first thread. So we changed to 128K.
*/
#define MIN_STACK_SIZE (128*1024L)
typedef void * (pthreadStartRoutine)(void *);
static pthreadStartRoutine pthreadStart;
static void *
pthreadStart(void * const arg) {
struct abyss_thread * const threadP = arg;
bool const executeTrue = true;
pthread_cleanup_push(threadP->threadDone, threadP->userHandle);
threadP->func(threadP->userHandle);
pthread_cleanup_pop(executeTrue);
/* Note that func() may not return; it may just exit the thread,
by calling ThreadExit(), in which case code here doesn't run.
*/
threadP->threadDone(threadP->userHandle);
return NULL;
}
void
ThreadCreate(TThread ** const threadPP,
void * const userHandle,
TThreadProc * const func,
TThreadDoneFn * const threadDone,
bool const useSigchld ATTR_UNUSED,
size_t const stackSize,
const char ** const errorP) {
if ((size_t)(int)stackSize != stackSize)
xmlrpc_asprintf(errorP, "Stack size %lu is too big",
(unsigned long)stackSize);
else {
TThread * threadP;
MALLOCVAR(threadP);
if (threadP == NULL)
xmlrpc_asprintf(errorP,
"Can't allocate memory for thread descriptor.");
else {
pthread_attr_t attr;
int rc;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, MAX(MIN_STACK_SIZE, stackSize));
threadP->userHandle = userHandle;
threadP->func = func;
threadP->threadDone = threadDone;
rc = pthread_create(&threadP->thread, &attr,
pthreadStart, threadP);
if (rc == 0) {
*errorP = NULL;
*threadPP = threadP;
} else
xmlrpc_asprintf(
errorP, "pthread_create() failed, errno = %d (%s)",
errno, strerror(errno));
pthread_attr_destroy(&attr);
if (*errorP)
free(threadP);
}
}
}
bool
ThreadRun(TThread * const threadP ATTR_UNUSED) {
return TRUE;
}
bool
ThreadStop(TThread * const threadP ATTR_UNUSED) {
return TRUE;
}
bool
ThreadKill(TThread * const threadP ATTR_UNUSED) {
return (pthread_kill(threadP->thread, SIGTERM) == 0);
}
void
ThreadWaitAndRelease(TThread * const threadP) {
void * threadReturn;
pthread_join(threadP->thread, &threadReturn);
free(threadP);
}
void
ThreadExit(TThread * const threadP ATTR_UNUSED,
int const retValue) {
pthread_exit((void*)&retValue);
/* Note that the above runs our cleanup routine (which we registered
with pthread_cleanup_push() before exiting.
*/
}
void
ThreadRelease(TThread * const threadP) {
pthread_detach(threadP->thread);
free(threadP);
}
bool
ThreadForks(void) {
return FALSE;
}
void
ThreadUpdateStatus(TThread * const threadP ATTR_UNUSED) {
/* Threads keep their own statuses up to date, so there's nothing
to do here.
*/
}
void
ThreadHandleSigchld(pid_t const pid ATTR_UNUSED) {
/* Death of a child signals have nothing to do with pthreads */
}
/*********************************************************************
** Mutex
*********************************************************************/
struct abyss_mutex {
pthread_mutex_t pthreadMutex;
};
bool
MutexCreate(TMutex ** const mutexPP) {
TMutex * mutexP;
bool succeeded;
MALLOCVAR(mutexP);
if (mutexP) {
int rc;
rc = pthread_mutex_init(&mutexP->pthreadMutex, NULL);
succeeded = (rc == 0);
} else
succeeded = FALSE;
if (!succeeded)
free(mutexP);
*mutexPP = mutexP;
return succeeded;
}
bool
MutexLock(TMutex * const mutexP) {
return (pthread_mutex_lock(&mutexP->pthreadMutex) == 0);
}
bool
MutexUnlock(TMutex * const mutexP) {
return (pthread_mutex_unlock(&mutexP->pthreadMutex) == 0);
}
bool
MutexTryLock(TMutex * const mutexP) {
return (pthread_mutex_trylock(&mutexP->pthreadMutex) == 0);
}
void
MutexDestroy(TMutex * const mutexP) {
pthread_mutex_destroy(&mutexP->pthreadMutex);
free(mutexP);
}