threads.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "../libnetdata.h"
  3. static pthread_attr_t *netdata_threads_attr = NULL;
  4. // ----------------------------------------------------------------------------
  5. // per thread data
  6. typedef struct {
  7. void *arg;
  8. pthread_t *thread;
  9. const char *tag;
  10. void *(*start_routine) (void *);
  11. NETDATA_THREAD_OPTIONS options;
  12. } NETDATA_THREAD;
  13. static __thread NETDATA_THREAD *netdata_thread = NULL;
  14. inline int netdata_thread_tag_exists(void) {
  15. return (netdata_thread && netdata_thread->tag && *netdata_thread->tag);
  16. }
  17. const char *netdata_thread_tag(void) {
  18. return (netdata_thread_tag_exists() ? netdata_thread->tag : "MAIN");
  19. }
  20. // ----------------------------------------------------------------------------
  21. // compatibility library functions
  22. static __thread pid_t gettid_cached_tid = 0;
  23. pid_t gettid(void) {
  24. pid_t tid = 0;
  25. if(likely(gettid_cached_tid > 0))
  26. return gettid_cached_tid;
  27. #ifdef __FreeBSD__
  28. tid = (pid_t)pthread_getthreadid_np();
  29. #elif defined(__APPLE__)
  30. #if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
  31. uint64_t curthreadid;
  32. pthread_threadid_np(NULL, &curthreadid);
  33. tid = (pid_t)curthreadid;
  34. #else /* __MAC_OS_X_VERSION_MIN_REQUIRED */
  35. tid = (pid_t)pthread_self;
  36. #endif /* __MAC_OS_X_VERSION_MIN_REQUIRED */
  37. #else /* __APPLE__*/
  38. tid = (pid_t)syscall(SYS_gettid);
  39. #endif /* __FreeBSD__, __APPLE__*/
  40. gettid_cached_tid = tid;
  41. return tid;
  42. }
  43. // ----------------------------------------------------------------------------
  44. // early initialization
  45. size_t netdata_threads_init(void) {
  46. int i;
  47. // --------------------------------------------------------------------
  48. // get the required stack size of the threads of netdata
  49. netdata_threads_attr = callocz(1, sizeof(pthread_attr_t));
  50. i = pthread_attr_init(netdata_threads_attr);
  51. if(i != 0)
  52. fatal("pthread_attr_init() failed with code %d.", i);
  53. size_t stacksize = 0;
  54. i = pthread_attr_getstacksize(netdata_threads_attr, &stacksize);
  55. if(i != 0)
  56. fatal("pthread_attr_getstacksize() failed with code %d.", i);
  57. else
  58. debug(D_OPTIONS, "initial pthread stack size is %zu bytes", stacksize);
  59. return stacksize;
  60. }
  61. // ----------------------------------------------------------------------------
  62. // late initialization
  63. void netdata_threads_init_after_fork(size_t stacksize) {
  64. int i;
  65. // ------------------------------------------------------------------------
  66. // set pthread stack size
  67. if(netdata_threads_attr && stacksize > (size_t)PTHREAD_STACK_MIN) {
  68. i = pthread_attr_setstacksize(netdata_threads_attr, stacksize);
  69. if(i != 0)
  70. error("pthread_attr_setstacksize() to %zu bytes, failed with code %d.", stacksize, i);
  71. else
  72. info("Set threads stack size to %zu bytes", stacksize);
  73. }
  74. else
  75. error("Invalid pthread stacksize %zu", stacksize);
  76. }
  77. // ----------------------------------------------------------------------------
  78. // netdata_thread_create
  79. void rrdset_thread_rda_free(void);
  80. void sender_thread_buffer_free(void);
  81. void query_target_free(void);
  82. void service_exits(void);
  83. static void thread_cleanup(void *ptr) {
  84. if(netdata_thread != ptr) {
  85. NETDATA_THREAD *info = (NETDATA_THREAD *)ptr;
  86. 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);
  87. }
  88. if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP))
  89. info("thread with task id %d finished", gettid());
  90. sender_thread_buffer_free();
  91. rrdset_thread_rda_free();
  92. query_target_free();
  93. thread_cache_destroy();
  94. service_exits();
  95. worker_unregister();
  96. freez((void *)netdata_thread->tag);
  97. netdata_thread->tag = NULL;
  98. freez(netdata_thread);
  99. netdata_thread = NULL;
  100. }
  101. static void thread_set_name_np(NETDATA_THREAD *nt) {
  102. if (nt->tag) {
  103. int ret = 0;
  104. char threadname[NETDATA_THREAD_NAME_MAX+1];
  105. strncpyz(threadname, nt->tag, NETDATA_THREAD_NAME_MAX);
  106. #if defined(__FreeBSD__)
  107. pthread_set_name_np(pthread_self(), threadname);
  108. #elif defined(__APPLE__)
  109. ret = pthread_setname_np(threadname);
  110. #else
  111. ret = pthread_setname_np(pthread_self(), threadname);
  112. #endif
  113. if (ret != 0)
  114. error("cannot set pthread name of %d to %s. ErrCode: %d", gettid(), threadname, ret);
  115. else
  116. info("set name of thread %d to %s", gettid(), threadname);
  117. }
  118. }
  119. void uv_thread_set_name_np(uv_thread_t ut, const char* name) {
  120. int ret = 0;
  121. char threadname[NETDATA_THREAD_NAME_MAX+1];
  122. strncpyz(threadname, name, NETDATA_THREAD_NAME_MAX);
  123. #if defined(__FreeBSD__)
  124. pthread_set_name_np(ut, threadname);
  125. #elif defined(__APPLE__)
  126. // Apple can only set its own name
  127. UNUSED(ut);
  128. #else
  129. ret = pthread_setname_np(ut, threadname);
  130. #endif
  131. if (ret)
  132. info("cannot set libuv thread name to %s. Err: %d", threadname, ret);
  133. }
  134. void os_thread_get_current_name_np(char threadname[NETDATA_THREAD_NAME_MAX + 1])
  135. {
  136. threadname[0] = '\0';
  137. #if defined(__FreeBSD__)
  138. pthread_get_name_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
  139. #elif defined(HAVE_PTHREAD_GETNAME_NP) /* Linux & macOS */
  140. (void)pthread_getname_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
  141. #endif
  142. }
  143. static void *thread_start(void *ptr) {
  144. netdata_thread = (NETDATA_THREAD *)ptr;
  145. if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_STARTUP))
  146. info("thread created with task id %d", gettid());
  147. if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
  148. error("cannot set pthread cancel type to DEFERRED.");
  149. if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
  150. error("cannot set pthread cancel state to ENABLE.");
  151. thread_set_name_np(ptr);
  152. void *ret = NULL;
  153. pthread_cleanup_push(thread_cleanup, ptr);
  154. ret = netdata_thread->start_routine(netdata_thread->arg);
  155. pthread_cleanup_pop(1);
  156. return ret;
  157. }
  158. int netdata_thread_create(netdata_thread_t *thread, const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg) {
  159. NETDATA_THREAD *info = mallocz(sizeof(NETDATA_THREAD));
  160. info->arg = arg;
  161. info->thread = thread;
  162. info->tag = strdupz(tag);
  163. info->start_routine = start_routine;
  164. info->options = options;
  165. int ret = pthread_create(thread, netdata_threads_attr, thread_start, info);
  166. if(ret != 0)
  167. error("failed to create new thread for %s. pthread_create() failed with code %d", tag, ret);
  168. else {
  169. if (!(options & NETDATA_THREAD_OPTION_JOINABLE)) {
  170. int ret2 = pthread_detach(*thread);
  171. if (ret2 != 0)
  172. error("cannot request detach of newly created %s thread. pthread_detach() failed with code %d", tag, ret2);
  173. }
  174. }
  175. return ret;
  176. }
  177. // ----------------------------------------------------------------------------
  178. // netdata_thread_cancel
  179. #ifdef NETDATA_INTERNAL_CHECKS
  180. int netdata_thread_cancel_with_trace(netdata_thread_t thread, int line, const char *file, const char *function) {
  181. #else
  182. int netdata_thread_cancel(netdata_thread_t thread) {
  183. #endif
  184. int ret = pthread_cancel(thread);
  185. if(ret != 0)
  186. #ifdef NETDATA_INTERNAL_CHECKS
  187. error("cannot cancel thread. pthread_cancel() failed with code %d at %d@%s, function %s()", ret, line, file, function);
  188. #else
  189. error("cannot cancel thread. pthread_cancel() failed with code %d.", ret);
  190. #endif
  191. return ret;
  192. }
  193. // ----------------------------------------------------------------------------
  194. // netdata_thread_join
  195. int netdata_thread_join(netdata_thread_t thread, void **retval) {
  196. int ret = pthread_join(thread, retval);
  197. if(ret != 0)
  198. error("cannot join thread. pthread_join() failed with code %d.", ret);
  199. return ret;
  200. }
  201. int netdata_thread_detach(pthread_t thread) {
  202. int ret = pthread_detach(thread);
  203. if(ret != 0)
  204. error("cannot detach thread. pthread_detach() failed with code %d.", ret);
  205. return ret;
  206. }