summaryrefslogtreecommitdiffstats
path: root/fetcher
AgeCommit message (Expand)Author
2014-09-22set error handler and throw exceptions on error caseBernhard Posselt
2014-09-16also use url in user agentBernhard Posselt
2014-09-16fix enclosureBernhard Posselt
2014-06-26style fixesBernhard Posselt
2014-06-25style fixesBernhard Posselt
2014-05-14convert array() to []Bernhard Posselt
2014-05-13try to fix return type of enhancer and feed fetcherBernhard Posselt
2014-05-13fix doc comments in feedfetcherBernhard Posselt
2014-05-13fix doc comments in feedfetcherBernhard Posselt
2014-05-12more fixesBernhard Posselt
2014-05-12remove dead codeBernhard Posselt
2014-04-19update headers to be compatible with phpdoc, slim down license text to make c...Bernhard Posselt
2014-04-19split up api class for easier testing and clearer codeBernhard Posselt
2014-04-10add proxy support based on simplepie pr, fix #491Bernhard Posselt
2014-04-09port to internal controller, some routes are still brokenBernhard Posselt
2014-04-09ported to owncloud internal appframework classes, confused with how to start ...Bernhard Posselt
2014-04-08remove html tags from feed titleBernhard Posselt
2014-04-08migrated database, utility, bootstrap from appframeworkBernhard Posselt
2014-02-11fix XSS when importing articles, speed up update and adding of feeds by only ...Bernhard Posselt
2014-02-11disable simplepie caching, see https://github.com/simplepie/simplepie/issues/...Bernhard Posselt
2014-01-26fallback to feed url if simplepie doesnt fetch a permanent linkAlessandro Cosentino
2014-01-23fix unit testsRobin Appelman
2014-01-23fallback to using the feed link if an item doesn't specificy a linkRobin Appelman
2013-09-27always open links in new tabBernhard Posselt
2013-09-27use seperate direcotires for article enhancers and fetchersBernhard Posselt
85' href='#n185'>185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
// SPDX-License-Identifier: GPL-3.0-or-later

#include "../libnetdata.h"

static pthread_attr_t *netdata_threads_attr = NULL;

// ----------------------------------------------------------------------------
// per thread data

typedef struct {
    void *arg;
    char tag[NETDATA_THREAD_NAME_MAX + 1];
    SPINLOCK detach_lock;
    void *(*start_routine) (void *);
    NETDATA_THREAD_OPTIONS options;
} NETDATA_THREAD;

static __thread NETDATA_THREAD *netdata_thread = NULL;

inline int netdata_thread_tag_exists(void) {
    return (netdata_thread && *netdata_thread->tag);
}

static const char *thread_name_get(bool recheck) {
    static __thread char threadname[NETDATA_THREAD_NAME_MAX + 1] = "";

    if(netdata_thread_tag_exists())
        strncpyz(threadname, netdata_thread->tag, NETDATA_THREAD_NAME_MAX);
    else {
        if(!recheck && threadname[0])
            return threadname;

#if defined(__FreeBSD__)
        pthread_get_name_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
        if(strcmp(threadname, "netdata") == 0)
            strncpyz(threadname, "MAIN", NETDATA_THREAD_NAME_MAX);
#elif defined(__APPLE__)
        strncpyz(threadname, "MAIN", NETDATA_THREAD_NAME_MAX);
#elif defined(HAVE_PTHREAD_GETNAME_NP)
        pthread_getname_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
        if(strcmp(threadname, "netdata") == 0)
            strncpyz(threadname, "MAIN", NETDATA_THREAD_NAME_MAX);
#else
        strncpyz(threadname, "MAIN", NETDATA_THREAD_NAME_MAX);
#endif
    }

    return threadname;
}

const char *netdata_thread_tag(void) {
    return thread_name_get(false);
}

static size_t webrtc_id = 0;
static __thread bool webrtc_name_set = false;
void webrtc_set_thread_name(void) {
    if(!netdata_thread && !webrtc_name_set) {
        webrtc_name_set = true;
        char threadname[NETDATA_THREAD_NAME_MAX + 1];

#if defined(__FreeBSD__)
        snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
        pthread_set_name_np(pthread_self(), threadname);
#elif defined(__APPLE__)
        snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
        pthread_setname_np(threadname);
#elif defined(HAVE_PTHREAD_GETNAME_NP)
        pthread_getname_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX+1);
        if(strcmp(threadname, "netdata") == 0) {
            snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
            pthread_setname_np(pthread_self(), threadname);
        }
#else
        snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
        pthread_setname_np(pthread_self(), threadname);
#endif

        thread_name_get(true);
    }
}

// ----------------------------------------------------------------------------
// compatibility library functions

static __thread pid_t gettid_cached_tid = 0;
pid_t gettid(void) {
    pid_t tid = 0;

    if(likely(gettid_cached_tid > 0))
        return gettid_cached_tid;

#ifdef __FreeBSD__

    tid = (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);
        tid = (pid_t)curthreadid;
    #else /* __MAC_OS_X_VERSION_MIN_REQUIRED */
        tid = (pid_t)pthread_self;
    #endif /* __MAC_OS_X_VERSION_MIN_REQUIRED */

#else /* __APPLE__*/

    tid = (pid_t)syscall(SYS_gettid);

#endif /* __FreeBSD__, __APPLE__*/

    gettid_cached_tid = tid;
    return tid;
}

// ----------------------------------------------------------------------------
// early initialization

size_t netdata_threads_init(void) {
    int i;

    // --------------------------------------------------------------------
    // get the required stack size of the threads of netdata

    if(!netdata_threads_attr) {
        netdata_threads_attr = callocz(1, sizeof(pthread_attr_t));
        i = pthread_attr_init(netdata_threads_attr);
        if (i != 0)
            fatal("pthread_attr_init() failed with code %d.", i);
    }

    size_t stacksize = 0;
    i = pthread_attr_getstacksize(netdata_threads_attr, &stacksize);
    if(i != 0)
        fatal("pthread_attr_getstacksize() failed with code %d.", i);

    return stacksize;
}

// ----------------------------------------------------------------------------
// late initialization

void netdata_threads_init_after_fork(size_t stacksize) {
    int i;

    // ------------------------------------------------------------------------
    // set pthread stack size

    if(netdata_threads_attr && stacksize > (size_t)PTHREAD_STACK_MIN) {
        i = pthread_attr_setstacksize(netdata_threads_attr, stacksize);
        if(i != 0)
            nd_log(NDLS_DAEMON, NDLP_WARNING, "pthread_attr_setstacksize() to %zu bytes, failed with code %d.", stacksize, i);
        else
            nd_log(NDLS_DAEMON, NDLP_DEBUG, "Set threads stack size to %zu bytes", stacksize);
    }
    else
        nd_log(NDLS_DAEMON, NDLP_WARNING, "Invalid pthread stacksize %zu", stacksize);
}

// ----------------------------------------------------------------------------
// threads init for external plugins

void netdata_threads_init_for_external_plugins(size_t stacksize) {
    size_t default_stacksize = netdata_threads_init();
    if(default_stacksize < 1 * 1024 * 1024)
        default_stacksize = 1 * 1024 * 1024;

    netdata_threads_init_after_fork(stacksize ? stacksize : default_stacksize);
}

// ----------------------------------------------------------------------------
// netdata_thread_create

void rrdset_thread_rda_free(void);
void sender_thread_buffer_free(void);
void query_target_free(void);
void service_exits(void);
void rrd_collector_finished(void);

static void thread_cleanup(void *ptr) {
    if(netdata_thread != ptr) {
        NETDATA_THREAD *info = (NETDATA_THREAD *)ptr;
        nd_log(NDLS_DAEMON, NDLP_ERR, "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);
    }
    spinlock_lock(&netdata_thread->detach_lock);

    if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP))
        nd_log(NDLS_DAEMON, NDLP_DEBUG, "thread with task id %d finished", gettid());

    rrd_collector_finished();
    sender_thread_buffer_free();
    rrdset_thread_rda_free();
    query_target_free();
    thread_cache_destroy();
    service_exits();
    worker_unregister();

    netdata_thread->tag[0] = '\0';

    spinlock_unlock(&netdata_thread->detach_lock);
    freez(netdata_thread);
    netdata_thread = NULL;
}

void netdata_thread_set_tag(const char *tag) {
    if(!tag || !*tag)
        return;

    int ret = 0;

    char threadname[NETDATA_THREAD_NAME_MAX+1];
    strncpyz(threadname, tag, NETDATA_THREAD_NAME_MAX);

#if defined(__FreeBSD__)
    pthread_set_name_np(pthread_self(), threadname);
#elif defined(__APPLE__)
    ret = pthread_setname_np(threadname);
#else
    ret = pthread_setname_np(pthread_self(), threadname);
#endif

    if (ret != 0)
        nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot set pthread name of %d to %s. ErrCode: %d", gettid(), threadname, ret);
    else
        nd_log(NDLS_DAEMON, NDLP_DEBUG, "set name of thread %d to %s", gettid(), threadname);

    if(netdata_thread) {
        strncpyz(netdata_thread->tag, threadname, sizeof(netdata_thread->tag) - 1);
    }
}

void uv_thread_set_name_np(uv_thread_t ut, const char* name) {
    int ret = 0;

    char threadname[NETDATA_THREAD_NAME_MAX+1];
    strncpyz(threadname, name, NETDATA_THREAD_NAME_MAX);

#if defined(__FreeBSD__)
    pthread_set_name_np(ut ? ut : pthread_self(), threadname);
#elif defined(__APPLE__)
    // Apple can only set its own name
    UNUSED(ut);
#else
    ret = pthread_setname_np(ut ? ut : pthread_self(), threadname);
#endif

    thread_name_get(true);

    if (ret)
        nd_log(NDLS_DAEMON, NDLP_NOTICE, "cannot set libuv thread name to %s. Err: %d", threadname, ret);
}

void os_thread_get_current_name_np(char threadname[NETDATA_THREAD_NAME_MAX + 1])
{
    threadname[0] = '\0';
#if defined(__FreeBSD__)
    pthread_get_name_np(pthread_self(),</