/*-------------------------------------------------------------------------
* drawElements Thread Library
* ---------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Unix implementation of thread management.
*//*--------------------------------------------------------------------*/
#include "deThread.h"
#if (DE_OS == DE_OS_UNIX || DE_OS == DE_OS_OSX || DE_OS == DE_OS_ANDROID || DE_OS == DE_OS_SYMBIAN || DE_OS == DE_OS_IOS)
#include "deMemory.h"
#include "deInt32.h"
#if !defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE < 500)
# error "You are using too old posix API!"
#endif
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include <sys/syscall.h>
#if (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS)
# if !defined(_SC_NPROCESSORS_CONF)
# define _SC_NPROCESSORS_CONF 57
# endif
# if !defined(_SC_NPROCESSORS_ONLN)
# define _SC_NPROCESSORS_ONLN 58
# endif
#endif
typedef struct Thread_s
{
pthread_t thread;
deThreadFunc func;
void* arg;
} Thread;
DE_STATIC_ASSERT(sizeof(deThread) >= sizeof(Thread*));
static void* startThread (void* entryPtr)
{
Thread* thread = (Thread*)entryPtr;
deThreadFunc func = thread->func;
void* arg = thread->arg;
/* Start actual thread. */
func(arg);
return DE_NULL;
}
deThread deThread_create (deThreadFunc func, void* arg, const deThreadAttributes* attributes)
{
pthread_attr_t attr;
Thread* thread = (Thread*)deCalloc(sizeof(Thread));
if (!thread)
return 0;
thread->func = func;
thread->arg = arg;
if (pthread_attr_init(&attr) != 0)
{
deFree(thread);
return 0;
}
/* \todo [2009-11-12 pyry] Map attributes. */
DE_UNREF(attributes);
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) != 0)
{
pthread_attr_destroy(&attr);
deFree(thread);
return 0;
}
if (pthread_create(&thread->thread, &attr, startThread, thread) != 0)
{
pthread_attr_destroy(&attr);
deFree(thread);
return 0;
}
DE_ASSERT(thread->thread);
pthread_attr_destroy(&attr);
return (deThread)thread;
}
deBool deThread_join (deThread threadptr)
{
Thread* thread = (Thread*)threadptr;
int ret;
DE_ASSERT(thread->thread);
ret = pthread_join(thread->thread, DE_NULL);
/* If join fails for some reason, at least mark as detached. */
if (ret != 0)
pthread_detach(thread->thread);
/* Thread is no longer valid as far as we are concerned. */
thread->thread = 0;
return (ret == 0);
}
void deThread_destroy (deThread threadptr)
{
Thread* thread = (Thread*)threadptr;
if (thread->thread)
{
/* Not joined, detach. */
int ret = pthread_detach(thread->thread);
DE_ASSERT(ret == 0);
DE_UNREF(ret);
}
deFree(thread);
}
void deSleep (deUint32 milliseconds)
{
/* Maximum value for usleep is 10^6. */
deUint32 seconds = milliseconds / 1000;
milliseconds = milliseconds - seconds * 1000;
if (seconds > 0)
sleep(seconds);
usleep((useconds_t)milliseconds * (useconds_t)1000);
}
void deYield (void)
{
sched_yield();
}
#if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID)
deUint32 deGetNumAvailableLogicalCores (void)
{
unsigned long mask = 0;
const unsigned int maskSize = sizeof(mask);
long ret;
deMemset(&mask, 0, sizeof(mask));
ret = syscall(__NR_sched_getaffinity, 0, maskSize, &mask);
if (ret > 0)
{
return (deUint32)dePop64(mask);
}
else
{
#if defined(_SC_NPROCESSORS_ONLN)
const long count = sysconf(_SC_NPROCESSORS_ONLN);
if (count <= 0)
return 1;
else
return (deUint32)count;
#else
return 1;
#endif
}
}
#else
deUint32 deGetNumAvailableLogicalCores (void)
{
#if defined(_SC_NPROCESSORS_ONLN)
const long count = sysconf(_SC_NPROCESSORS_ONLN);
if (count <= 0)
return 1;
else
return (deUint32)count;
#else
return 1;
#endif
}
#endif
deUint32 deGetNumTotalLogicalCores (void)
{
#if defined(_SC_NPROCESSORS_CONF)
const long count = sysconf(_SC_NPROCESSORS_CONF);
if (count <= 0)
return 1;
else
return (deUint32)count;
#else
return 1;
#endif
}
deUint32 deGetNumTotalPhysicalCores (void)
{
/* \todo [2015-04-09 pyry] Parse /proc/cpuinfo perhaps? */
return deGetNumTotalLogicalCores();
}
#endif /* DE_OS */