/simpletypesystem/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/simpletypesystem/trunk
116.1.1 by Gustav Hartvigsson
* Implemented the SMainLoop
1
#include "MainLoop.h"
2
#include "Thread.h"
3
#include "LinkedList.h"
4
5
/*
6
Copyright (c) 2013-2016 Gustav Hartvigsson
7
8
Permission is hereby granted, free of charge, to any person obtaining a copy
9
of this software and associated documentation files (the "Software"), to deal
10
in the Software without restriction, including without limitation the rights
11
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
copies of the Software, and to permit persons to whom the Software is
13
furnished to do so, subject to the following conditions:
14
15
The above copyright notice and this permission notice shall be included in
16
all copies or substantial portions of the Software.
17
18
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
THE SOFTWARE.
25
 */
26
27
/*
28
 * The default mainloop, it is hidden.
29
 */
30
SMainLoop *
31
_default_main_loop = NULL;
32
33
/*
34
 * The items that are held by the linked lists in SMainLoop.
35
 */
36
typedef struct SMainLoopItem {
37
  SMainLoopState state; /* in what list should this item be? */
38
  sboolean is_alive; /* If this is TRUE then this can be removed. */
39
40
  RunFunc callback; /* The callback that is run. */
41
  spointer user_data; /* Pointer to the user data that was provided. */
42
} SMainLoopItem;
43
44
typedef struct  SMainLoopTeardownHandler {
45
  Callback teardown_handler;
46
47
  spointer obj_self;
48
  spointer user_data;
49
50
} SMainLoopTeardownHandler;
51
52
/* This is the freeing function for MainLoopTeardownHandler objcets it also
53
 * calls the teardown handler.
54
 *
55
 * This reduces the iteration time for the teardown.
56
 */
57
void
58
_s_main_loop_teardown_handerer_obj_free (SMainLoopTeardownHandler * self);
59
60
struct SMainLoop {
61
  suint ref_count;
62
  SMainLoopState ring_1_state;
63
  SMainLoopState ring_2_state;
64
  sboolean is_run;
65
66
  SMutex * mutex;
67
68
  SLinkedList * ring_1_event_handler_list;
69
  SLinkedList * ring_1_io_push_list;
70
  SLinkedList * ring_1_io_pull_list;
71
  SLinkedList * ring_1_workers_list;
72
73
  SLinkedList * ring_2_event_handler_list;
74
  SLinkedList * ring_2_io_push_list;
75
  SLinkedList * ring_2_io_pull_list;
76
  SLinkedList * ring_2_workers_list;
77
78
  SLinkedList * teardown_handler_list;
79
};
80
81
schar *
82
s_main_loop_state_get_name (SMainLoopState state) {
83
  return SMainLoopStateName[state];
84
}
85
86
schar *
87
s_main_loop_ring_get_name (SMainLoopRing ring) {
88
  return SMainLoopStateName[ring];
89
}
90
91
/* ************************************************************************** */
92
93
void
94
_s_main_loop_do_list (SLinkedList * event_handler_list);
95
96
void
97
_s_main_loop_do_ring_two (SMainLoop * self);
98
99
/* -----------------------------------------------------------------------------
100
 * imprementation of the real functions and stuffs.
101
 * -----------------------------------------------------------------------------
102
 */
103
104
SMainLoop *
105
s_main_loop_new () {
106
  SMainLoop * self = malloc (sizeof (SMainLoop));
107
108
  self->mutex = s_mutex_new ();
109
  s_mutex_lock (self->mutex);
110
111
  self->ref_count = 1;
112
  self->ring_1_state = S_MAIN_LOOP_STATE_EVENT;
113
  self->ring_2_state = S_MAIN_LOOP_STATE_EVENT;
114
  self->is_run = FALSE;
115
116
  self->ring_1_event_handler_list = s_linked_list_new (FREEFUNC (free));
117
  self->ring_1_io_push_list = s_linked_list_new (FREEFUNC (free));
118
  self->ring_1_io_pull_list = s_linked_list_new (FREEFUNC (free));
119
  self->ring_1_workers_list = s_linked_list_new (FREEFUNC (free));
120
121
  self->ring_2_event_handler_list = s_linked_list_new (FREEFUNC (free));
122
  self->ring_2_io_push_list = s_linked_list_new (FREEFUNC (free));
123
  self->ring_2_io_pull_list = s_linked_list_new (FREEFUNC (free));
124
  self->ring_2_workers_list = s_linked_list_new (FREEFUNC (free));
125
126
  self->teardown_handler_list = s_linked_list_new (FREEFUNC (_s_main_loop_teardown_handerer_obj_free));
127
128
  s_mutex_unlock (self->mutex);
129
130
  return self;
131
}
132
133
SMainLoop *
134
s_main_loop_get_default () {
135
  if (_default_main_loop == NULL) {
136
    _default_main_loop = s_main_loop_new ();
137
  }
138
  return _default_main_loop;
139
}
140
141
void
142
s_main_loop_run (SMainLoop * self) {
143
  assert (self != NULL);
144
  self->is_run = TRUE;
145
  while (self->is_run) {
146
    switch (self->ring_1_state) {
147
      case (S_MAIN_LOOP_STATE_EVENT):
148
        _s_main_loop_do_list (self->ring_1_event_handler_list);
149
        self->ring_1_state = S_MAIN_LOOP_STATE_IO_PUSH;
150
        break;
151
      case (S_MAIN_LOOP_STATE_IO_PUSH):
152
        _s_main_loop_do_list (self->ring_1_io_push_list);
153
        self->ring_1_state = S_MAIN_LOOP_STATE_IO_PULL;
154
        break;
155
      case (S_MAIN_LOOP_STATE_IO_PULL):
156
        _s_main_loop_do_list (self->ring_1_io_pull_list);
157
        self->ring_1_state = S_MAIN_LOOP_STATE_RING_TWO_NEXT;
158
        break;
159
      case (S_MAIN_LOOP_STATE_RING_TWO_NEXT):
160
        _s_main_loop_do_ring_two (self);
161
        self->ring_1_state = S_MAIN_LOOP_STATE_DO_WORKERS;
162
        break;
163
      case (S_MAIN_LOOP_STATE_DO_WORKERS):
164
        _s_main_loop_do_list (self->ring_1_workers_list);
165
        self->ring_1_state = S_MAIN_LOOP_STATE_SLEEP;
166
        break;
167
      case (S_MAIN_LOOP_STATE_SLEEP):
168
        s_usleep (1);
169
        self->ring_1_state = S_MAIN_LOOP_STATE_EVENT;
170
        break;
171
      default:
172
        s_err_print ("Reaching a place that should not be reached.\n"
173
                     "Aborting.");
174
        exit (666);
175
    }
176
    s_mutex_lock (self->mutex);
177
178
    sint no_of_handlers = 0;
179
180
    no_of_handlers += s_linked_list_len (self->ring_1_event_handler_list);
181
    no_of_handlers += s_linked_list_len (self->ring_1_io_push_list);
182
    no_of_handlers += s_linked_list_len (self->ring_1_io_pull_list);
183
    no_of_handlers += s_linked_list_len (self->ring_1_workers_list);
184
185
    no_of_handlers += s_linked_list_len (self->ring_2_event_handler_list);
186
    no_of_handlers += s_linked_list_len (self->ring_2_io_push_list);
187
    no_of_handlers += s_linked_list_len (self->ring_2_io_pull_list);
188
    no_of_handlers += s_linked_list_len (self->ring_2_workers_list);
189
190
    if (!self->is_run || no_of_handlers == 0) {
191
      s_mutex_unlock (self->mutex);
192
      break;
193
    }
194
    s_mutex_unlock (self->mutex);
195
196
  }
197
}
198
199
200
void
201
s_main_loop_quit (SMainLoop * self) {
202
  s_mutex_lock (self->mutex);
203
  self->is_run = FALSE;
204
205
  s_linked_list_free (self->ring_1_event_handler_list, TRUE);
206
  s_linked_list_free (self->ring_1_io_push_list, TRUE);
207
  s_linked_list_free (self->ring_1_io_pull_list, TRUE);
208
  s_linked_list_free (self->ring_1_workers_list, TRUE);
209
210
  s_linked_list_free (self->ring_2_event_handler_list, TRUE);
211
  s_linked_list_free (self->ring_2_io_push_list, TRUE);
212
  s_linked_list_free (self->ring_2_io_pull_list, TRUE);
213
  s_linked_list_free (self->ring_2_workers_list, TRUE);
214
215
  s_linked_list_free (self->teardown_handler_list, TRUE);
216
217
218
  s_mutex_free (self->mutex);
219
  free (self);
220
}
221
222
void
223
s_main_loop_ref (SMainLoop * self) {
224
  self->ref_count++;
225
}
226
227
void
228
s_main_loop_unref (SMainLoop * self) {
229
  self->ref_count--;
230
}
231
232
void
233
s_main_loop_add_event_handler (SMainLoop * self,
234
                               SMainLoopRing ring,
235
                               RunFunc event_handler,
236
                               spointer user_data) {
237
  //
238
  if (user_data == NULL) {
239
    s_err_print ("No user data provided to the event handeler."
240
                 " This is an error.");
241
    print_backtrace ();
242
    return;
243
  }
244
245
  SMainLoopItem * item = malloc (sizeof (SMainLoopItem));
246
  item->state = S_MAIN_LOOP_STATE_EVENT;
247
  item->callback = event_handler;
248
  item->user_data = user_data;
249
  item->is_alive = TRUE;
250
251
  switch (ring) {
252
    case (S_MAIN_LOOP_RING_ONE):
253
       s_linked_list_append (self->ring_1_event_handler_list, item);
254
      break;
255
    case (S_MAIN_LOOP_RING_TWO):
256
      s_linked_list_append (self->ring_2_event_handler_list, item);
257
      break;
258
     default:
259
      s_err_print ("Invalid value of the ring parameter for "
260
                   "s_main_loop_add_io_pull function.");
261
  }
262
263
}
264
265
void
266
s_main_loop_add_io_push (SMainLoop * self,
267
                         SMainLoopRing ring,
268
                         RunFunc push_callback,
269
                         spointer user_data) {
270
  //
271
  if (user_data == NULL) {
272
    s_err_print ("No user data provided to the IO push event."
273
                 " This is an error.");
274
    print_backtrace ();
275
    return;
276
  }
277
278
  SMainLoopItem * item = malloc (sizeof (SMainLoopItem));
279
  item->state = S_MAIN_LOOP_STATE_IO_PUSH;
280
  item->callback = push_callback;
281
  item->user_data = user_data;
282
  item->is_alive = TRUE;
283
284
  switch (ring) {
285
    case (S_MAIN_LOOP_RING_ONE):
286
       s_linked_list_append (self->ring_1_io_push_list, item);
287
      break;
288
    case (S_MAIN_LOOP_RING_TWO):
289
      s_linked_list_append (self->ring_2_io_push_list, item);
290
      break;
291
     default:
292
      s_err_print ("Invalid value of the ring parameter for "
293
                   "s_main_loop_add_io_push function.");
294
  }
295
296
}
297
298
void
299
s_main_loop_add_io_pull (SMainLoop * self,
300
                         SMainLoopRing ring,
301
                         RunFunc pull_callback,
302
                         spointer user_data) {
303
  //
304
  if (user_data == NULL) {
305
    s_err_print ("No user data provided to the IO pull event."
306
                 " This is an error.");
307
    print_backtrace ();
308
    return;
309
  }
310
311
  SMainLoopItem * item = malloc (sizeof (SMainLoopItem));
312
  item->state = S_MAIN_LOOP_STATE_IO_PULL;
313
  item->callback = pull_callback;
314
  item->user_data = user_data;
315
  item->is_alive = TRUE;
316
317
  switch (ring) {
318
    case (S_MAIN_LOOP_RING_ONE):
319
       s_linked_list_append (self->ring_1_io_pull_list, item);
320
      break;
321
    case (S_MAIN_LOOP_RING_TWO):
322
      s_linked_list_append (self->ring_2_io_pull_list, item);
323
      break;
324
     default:
325
      s_err_print ("Invalid value of the ring parameter for "
326
                   "s_main_loop_add_ function.");
327
  }
328
329
}
330
331
void
332
s_main_loop_add_worker (SMainLoop * self,
333
                        SMainLoopRing ring,
334
                        RunFunc worker_callback,
335
                        spointer user_data) {
336
  //
337
338
  SMainLoopItem * item = malloc (sizeof (SMainLoopItem));
339
  item->state = S_MAIN_LOOP_STATE_DO_WORKERS;
340
  item->callback = worker_callback;
341
  item->user_data = user_data;
342
  item->is_alive = TRUE;
343
344
  switch (ring) {
345
    case (S_MAIN_LOOP_RING_ONE):
346
       s_linked_list_append (self->ring_1_workers_list, item);
347
      break;
348
    case (S_MAIN_LOOP_RING_TWO):
349
      s_linked_list_append (self->ring_2_workers_list, item);
350
      break;
351
     default:
352
      s_err_print ("Invalid value of the ring parameter for "
353
                   "s_main_loop_add_worker function.");
354
  }
355
356
}
357
358
void
359
s_main_loop_add_teardown_handler (SMainLoop * self,
360
                                  Callback teardown_handler,
361
				                          spointer self_obj,
362
				                          spointer user_data) {
363
  if (self == NULL) {
364
    s_err_print ("No self pointer provided for the teardown handler "
365
                 "This is an error.");
366
    print_backtrace ();
367
  }
368
369
  SMainLoopTeardownHandler * item = malloc (sizeof (SMainLoopTeardownHandler));
370
371
  item->teardown_handler = teardown_handler;
372
  item->obj_self = self_obj;
373
  item->user_data = user_data;
374
375
  s_linked_list_append (self->teardown_handler_list, item);
376
}
377
378
/* ************************************************************************** */
379
380
void
381
_s_main_loop_teardown_handerer_obj_free (SMainLoopTeardownHandler * self) {
382
  Callback callback = self->teardown_handler;
383
  callback (self->obj_self, self->user_data);
384
  free (self);
385
}
386
387
void
388
_s_main_loop_do_list (SLinkedList * event_handler_list) {
389
  if (s_linked_list_len (event_handler_list) == 0) {
390
    return;
391
  }
392
393
  s_linked_list_head (event_handler_list);
394
  do {
395
    SMainLoopItem * item = s_linked_list_get_current (event_handler_list);
396
    RunFunc callback = item->callback;
397
    spointer user_data = item->user_data;
398
399
    item->is_alive  = callback (user_data);
400
  } while (s_linked_list_next (event_handler_list));
401
402
  s_linked_list_head (event_handler_list);
403
  do {
404
    SMainLoopItem * item = s_linked_list_get_current (event_handler_list);
405
    if (!item->is_alive) {
406
      s_linked_list_remove_current (event_handler_list, TRUE);
407
    }
408
  } while (s_linked_list_next (event_handler_list));
409
410
}
411
412
void
413
_s_main_loop_do_ring_two (SMainLoop * self) {
414
  switch (self->ring_2_state) {
415
    case (S_MAIN_LOOP_STATE_EVENT):
416
      _s_main_loop_do_list (self->ring_2_event_handler_list);
417
      self->ring_2_state = S_MAIN_LOOP_STATE_IO_PUSH;
418
      break;
419
    case (S_MAIN_LOOP_STATE_IO_PUSH):
420
      _s_main_loop_do_list (self->ring_2_io_push_list);
421
      self->ring_2_state = S_MAIN_LOOP_STATE_IO_PULL;
422
      break;
423
    case (S_MAIN_LOOP_STATE_IO_PULL):
424
      _s_main_loop_do_list (self->ring_2_io_pull_list);
425
      self->ring_2_state = S_MAIN_LOOP_STATE_DO_WORKERS;
426
      break;
427
    case (S_MAIN_LOOP_STATE_DO_WORKERS):
428
      _s_main_loop_do_list (self->ring_2_workers_list);
429
      self->ring_2_state = S_MAIN_LOOP_STATE_EVENT;
430
      break;
431
    default:
432
      s_err_print ("Reaching a place that should not be reached.\n"
433
                   "Aborting.");
434
      exit (666);
435
  }
436
}
437
438