1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "../libnetdata.h"
static size_t default_stacksize = 0, wanted_stacksize = 0;
static pthread_attr_t *attr = NULL;
// ----------------------------------------------------------------------------
// per thread data
typedef struct {
void *arg;
pthread_t *thread;
const char *tag;
void *(*start_routine) (void *);
NETDATA_THREAD_OPTIONS options;
} NETDATA_THREAD;
static __thread NETDATA_THREAD *netdata_thread = NULL;
const char *netdata_thread_tag(void) {
return ((netdata_thread && netdata_thread->tag && *netdata_thread->tag)?netdata_thread->tag:"MAIN");
}
// ----------------------------------------------------------------------------
// compatibility library functions
pid_t gettid(void) {
#ifdef __FreeBSD__
return (pid_t)pthread_getthreadid_np();
#elif defined(__APPLE__)
#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
uint64_t curthreadid;
pthread_threadid_np(NULL, &curthreadid);
return (pid_t)curthreadid;
#else /* __MAC_OS_X_VERSION_MIN_REQUIRED */
return (pid_t)pthread_self;
#endif /* __MAC_OS_X_VERSION_MIN_REQUIRED */
#else /* __APPLE__*/
return (pid_t)syscall(SYS_gettid);
#endif /* __FreeBSD__, __APPLE__*/
}
// ----------------------------------------------------------------------------
// early initialization
size_t netdata_threads_init(void) {
int i;
// --------------------------------------------------------------------
// get the required stack size of the threads of netdata
attr = callocz(1, sizeof(pthread_attr_t));
i = pthread_attr_init(attr);
if(i != 0)
fatal("pthread_attr_init() failed with code %d.", i);
i = pthread_attr_getstacksize(attr, &default_stacksize);
if(i != 0)
fatal("pthread_attr_getstacksize() failed with code %d.", i);
else
debug(D_OPTIONS, "initial pthread stack size is %zu bytes", default_stacksize);
return default_stacksize;
}
// ----------------------------------------------------------------------------
// late initialization
void netdata_threads_init_after_fork(size_t stacksize) {
wanted_stacksize = stacksize;
int i;
// ------------------------------------------------------------------------
// set default pthread stack size
if(attr && default_stacksize < wanted_stacksize && wanted_stacksize > 0) {
i = pthread_attr_setstacksize(attr, wanted_stacksize);
if(i != 0)
fatal("pthread_attr_setstacksize() to %zu bytes, failed with code %d.", wanted_stacksize, i);
else
debug(D_SYSTEM, "Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
}
}
// ----------------------------------------------------------------------------
// netdata_thread_create
static void thread_cleanup(void *ptr) {
if(netdata_thread != ptr) {
NETDATA_THREAD *info = (NETDATA_THREAD *)ptr;
error("THREADS: internal error - thread local variable does not match the one passed to this function. Expected thread '%s', passed thread '%s'", netdata_thread->tag, info->tag);
}
if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP))
info("thread with task id %d finished", gettid());
freez((void *)netdata_thread->tag);
netdata_thread->tag = NULL;
freez(netdata_thread);
netdata_thread = NULL;
}
static void *thread_start(void *ptr) {
netdata_thread = (NETDATA_THREAD *)ptr;
if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_STARTUP))
info("thread created with task id %d", gettid());
if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
error("cannot set pthread cancel type to DEFERRED.");
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("cannot set pthread cancel state to ENABLE.");
void *ret = NULL;
pthread_cleanup_push(thread_cleanup, ptr);
ret = netdata_thread->start_routine(netdata_thread->arg);
pthread_cleanup_pop(1);
return ret;
}
int netdata_thread_create(netdata_thread_t *thread, const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg) {
NETDATA_THREAD *info = mallocz(sizeof(NETDATA_THREAD));
info->arg = arg;
info->thread = thread;
info->tag = strdupz(tag);
info->start_routine = start_routine;
info->options = options;
int ret = pthread_create(thread, attr, thread_start, info);
if(ret != 0)
error("failed to create new thread for %s. pthread_create() failed with code %d", tag, ret);
else {
if (!(options & NETDATA_THREAD_OPTION_JOINABLE)) {
int ret2 = pthread_detach(*thread);
if (ret2 != 0)
error("cannot request detach of newly created %s thread. pthread_detach() failed with code %d", tag, ret2);
}
}
return ret;
}
// ----------------------------------------------------------------------------
// netdata_thread_cancel
int netdata_thread_cancel(netdata_thread_t thread) {
int ret = pthread_cancel(thread);
if(ret != 0)
error("cannot cancel thread. pthread_cancel() failed with code %d.", ret);
return ret;
}
// ----------------------------------------------------------------------------
// netdata_thread_join
int netdata_thread_join(netdata_thread_t thread, void **retval) {
int ret = pthread_join(thread, retval);
if(ret != 0)
error("cannot join thread. pthread_join() failed with code %d.", ret);
return ret;
}
int netdata_thread_detach(pthread_t thread) {
int ret = pthread_detach(thread);
if(ret != 0)
error("cannot detach thread. pthread_detach() failed with code %d.", ret);
return ret;
}
|