summaryrefslogtreecommitdiff
path: root/src/Threads.cc
blob: f5f9a7fc29e7800d9d5f469d1c9fbf7124f3dd7d (plain)
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
#include <atomic>
#include "Exceptions.h"
#include "Threads.h"
#include "Local.h"
#include "TaskMan.h"

namespace Balau {

class ThreadHelper {
  public:
    static void * threadProc(void * arg);
};

}

Balau::Lock::Lock() {
    int r;
    pthread_mutexattr_t attr;

    r = pthread_mutexattr_init(&attr);
    RAssert(r == 0, "Couldn't initialize mutex attribute; r = %i", r);
    r = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    RAssert(r == 0, "Couldn't set mutex attribute; r = %i", r);
    r = pthread_mutex_init(&m_lock, &attr);
    RAssert(r == 0, "Couldn't initialize mutex; r = %i", r);
    r = pthread_mutexattr_destroy(&attr);
    RAssert(r == 0, "Couldn't destroy mutex attribute; r = %i", r);
}

Balau::RWLock::RWLock() {
    int r;

    r = pthread_rwlock_init(&m_lock, NULL);
    RAssert(r == 0, "Couldn't initialize read write lock; r = %i", r);
}

void * Balau::ThreadHelper::threadProc(void * arg) {
    void * r = NULL;
    bool success = false;
    try {
        void * tls = Local::createTLS();
        g_tlsManager->setTLS(tls);
        Balau::Thread * thread = reinterpret_cast<Balau::Thread *>(arg);
        r = thread->proc();
        free(tls);
        success = true;
    }
    catch (Exit & e) {
        Printer::log(M_ERROR, "We shouldn't have gotten an Exit exception here... exitting anyway");
        auto trace = e.getTrace();
        for (String & str : trace)
            Printer::log(M_ERROR, "%s", str.to_charp());
    }
    catch (RessourceException & e) {
        Printer::log(M_ERROR | M_ALERT, "The Thread got a ressource problem: %s", e.getMsg());
        const char * details = e.getDetails();
        if (details)
            Printer::log(M_ERROR, "  %s", details);
        auto trace = e.getTrace();
        for (String & str : trace)
            Printer::log(M_DEBUG, "%s", str.to_charp());
    }
    catch (GeneralException & e) {
        Printer::log(M_ERROR | M_ALERT, "The Thread caused an exception: %s", e.getMsg());
        const char * details = e.getDetails();
        if (details)
            Printer::log(M_ERROR, "  %s", details);
        auto trace = e.getTrace();
        for (String & str : trace)
            Printer::log(M_DEBUG, "%s", str.to_charp());
    }
    catch (...) {
        Printer::log(M_ERROR | M_ALERT, "The Thread caused an unknown exception");
    }

    if (!success)
        TaskMan::stop(-1);

    return r;
}

Balau::Thread::~Thread() {
    join();
}

void * Balau::Thread::join() {
    void * r = NULL;
    if (!m_joined.exchange(true)) {
        threadExit();
        pthread_join(m_thread, &r);
    }
    return r;
}

void Balau::Thread::threadStart() {
    pthread_attr_t attr;
    int r;

    r = pthread_attr_init(&attr);
    RAssert(r == 0, "Couldn't initialize pthread attribute; r = %i", r);
    r = pthread_create(&m_thread, &attr, Balau::ThreadHelper::threadProc, this);
    RAssert(r == 0, "Couldn't create pthread; r = %i", r);
    r = pthread_attr_destroy(&attr);
    RAssert(r == 0, "Couldn't destroy pthread attribute; r = %i", r);
}