/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, * 2018, 2019, 2020 * Jonathan Schleifer <js@nil.im> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <errno.h> #ifdef HAVE_PTHREAD_NP_H # include <pthread_np.h> #endif #ifdef OF_HAIKU # include <kernel/OS.h> #endif #import "thread.h" #import "macros.h" static int minPrio = 0, maxPrio = 0, normalPrio = 0; struct thread_ctx { void (*function)(id object); id object; const char *name; }; /* * This is done here to make sure this is done as early as possible in the main * thread. */ OF_CONSTRUCTOR() { pthread_attr_t pattr; if (pthread_attr_init(&pattr) == 0) { #ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY int policy; #endif struct sched_param param; #ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY if (pthread_attr_getschedpolicy(&pattr, &policy) == 0) { minPrio = sched_get_priority_min(policy); maxPrio = sched_get_priority_max(policy); if (minPrio == -1 || maxPrio == -1) minPrio = maxPrio = 0; } if (pthread_attr_getschedparam(&pattr, ¶m) != 0) normalPrio = param.sched_priority; else minPrio = maxPrio = 0; pthread_attr_destroy(&pattr); #endif } } static void * functionWrapper(void *data) { struct thread_ctx *ctx = data; if (ctx->name != NULL) of_thread_set_name(ctx->name); pthread_cleanup_push(free, data); ctx->function(ctx->object); pthread_cleanup_pop(1); return NULL; } bool of_thread_attr_init(of_thread_attr_t *attr) { pthread_attr_t pattr; if (pthread_attr_init(&pattr) != 0) return false; @try { attr->priority = 0; if (pthread_attr_getstacksize(&pattr, &attr->stackSize) != 0) return false; } @finally { pthread_attr_destroy(&pattr); } return true; } bool of_thread_new(of_thread_t *thread, const char *name, void (*function)(id), id object, const of_thread_attr_t *attr) { bool ret; pthread_attr_t pattr; if (pthread_attr_init(&pattr) != 0) return false; @try { struct thread_ctx *ctx; if (attr != NULL) { struct sched_param param; if (attr->priority < -1 || attr->priority > 1) { errno = EINVAL; return false; } #ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED if (pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED) != 0) return false; #endif if (attr->priority < 0) { param.sched_priority = minPrio + (1.0f + attr->priority) * (normalPrio - minPrio); } else param.sched_priority = normalPrio + attr->priority * (maxPrio - normalPrio); if (pthread_attr_setschedparam(&pattr, ¶m) != 0) return false; if (attr->stackSize > 0) { if (pthread_attr_setstacksize(&pattr, attr->stackSize) != 0) return false; } } if ((ctx = malloc(sizeof(*ctx))) == NULL) { errno = ENOMEM; return false; } ctx->function = function; ctx->object = object; ctx->name = name; ret = (pthread_create(thread, &pattr, functionWrapper, ctx) == 0); } @finally { pthread_attr_destroy(&pattr); } return ret; } bool of_thread_join(of_thread_t thread) { void *ret; return (pthread_join(thread, &ret) == 0); } bool of_thread_detach(of_thread_t thread) { return (pthread_detach(thread) == 0); } void of_thread_set_name(const char *name) { #if defined(OF_HAIKU) rename_thread(find_thread(NULL), name); #elif defined(HAVE_PTHREAD_SET_NAME_NP) pthread_set_name_np(pthread_self(), name); #elif defined(HAVE_PTHREAD_SETNAME_NP) # if defined(OF_MACOS) || defined(OF_IOS) pthread_setname_np(name); # elif defined(__GLIBC__) char buffer[16]; strncpy(buffer, name, 15); buffer[15] = 0; pthread_setname_np(pthread_self(), buffer); # endif #endif }