]> git.stg.codes - stg.git/blob - projects/stargazer/eventloop.cpp
Improved handling errors got from server.
[stg.git] / projects / stargazer / eventloop.cpp
1 #include <csignal>
2 #include <cerrno>
3 #include <cstring>
4
5 #include "stg/locker.h"
6 #include "stg/common.h"
7 #include "eventloop.h"
8
9 EVENT_LOOP::EVENT_LOOP()
10     : ACTIONS_LIST(),
11       _running(false),
12       _stopped(true),
13       _tid(),
14       _mutex(),
15       _condition()
16 {
17 pthread_mutex_init(&_mutex, NULL);
18 pthread_cond_init(&_condition, NULL);
19 }
20
21 EVENT_LOOP::~EVENT_LOOP()
22 {
23 pthread_cond_destroy(&_condition);
24 pthread_mutex_destroy(&_mutex);
25 }
26
27 bool EVENT_LOOP::Start()
28 {
29 _running = true;
30 if (pthread_create(&_tid, NULL, Run, this))
31     {
32     printfd(__FILE__, "EVENT_LOOP::Start - Failed to create thread: '%s'\n", strerror(errno));
33     return true;
34     }
35 return false;
36 }
37
38 bool EVENT_LOOP::Stop()
39 {
40 _running = false;
41 // Wake up thread
42 pthread_cond_signal(&_condition);
43 // Wait until thread exit
44 pthread_join(_tid, NULL);
45 return false;
46 }
47
48 void * EVENT_LOOP::Run(void * self)
49 {
50 EVENT_LOOP * ev = static_cast<EVENT_LOOP *>(self);
51 ev->Runner();
52 return NULL;
53 }
54
55 void EVENT_LOOP::Runner()
56 {
57 sigset_t signalSet;
58 sigfillset(&signalSet);
59 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
60
61 _stopped = false;
62 printfd(__FILE__, "EVENT_LOOP::Runner - Before start\n");
63 while (_running)
64     {
65         {
66         STG_LOCKER lock(&_mutex, __FILE__, __LINE__);
67         // Check for any actions...
68         if (empty())
69             {
70             // ... and sleep until new actions added
71             printfd(__FILE__, "EVENT_LOOP::Runner - Sleeping until new actions arrived\n");
72             pthread_cond_wait(&_condition, &_mutex);
73             }
74         // Check for running after wake up
75         if (!_running)
76             {
77             // Don't process any actions if stopping
78             break;
79             }
80         }
81     // Create new empty actions list
82     ACTIONS_LIST local;
83     // Fast swap with current
84     swap(local);
85     // Invoke all current actions
86     printfd(__FILE__, "EVENT_LOOP::Runner - Invoke %d actions\n", local.size());
87     local.InvokeAll();
88     }
89 printfd(__FILE__, "EVENT_LOOP::Runner - Before stop\n");
90 _stopped = true;
91 }
92
93 namespace {
94
95 pthread_mutex_t singletonMutex;
96
97 }
98
99 EVENT_LOOP & EVENT_LOOP_SINGLETON::GetInstance()
100 {
101 // Double-checking technique
102 if (!_instance)
103     {
104     STG_LOCKER lock(&singletonMutex, __FILE__, __LINE__);
105     if (!_instance)
106         {
107         CreateInstance();
108         }
109     }
110 return *_instance;
111 }
112
113 void EVENT_LOOP_SINGLETON::CreateInstance()
114 {
115 static EVENT_LOOP loop;
116 _instance = &loop;
117 }
118
119 EVENT_LOOP * EVENT_LOOP_SINGLETON::_instance = NULL;