/simpletypesystem/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/simpletypesystem/trunk

« back to all changes in this revision

Viewing changes to libssts/MainLoop.c

* Merged in new Main Loop branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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[S_MAIN_LOOP_RING_LAST][S_MAIN_LOOP_STATE_LAST];
 
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
  SMutex * teardown_handler_mutex;
 
81
};
 
82
 
 
83
schar *
 
84
s_main_loop_state_get_name (SMainLoopState state) {
 
85
  return SMainLoopStateName[state];
 
86
}
 
87
 
 
88
schar *
 
89
s_main_loop_ring_get_name (SMainLoopRing ring) {
 
90
  return SMainLoopStateName[ring];
 
91
}
 
92
 
 
93
/* ************************************************************************** */
 
94
 
 
95
void
 
96
_s_main_loop_do_list (SLinkedList * event_handler_list);
 
97
 
 
98
void
 
99
_s_main_loop_do_ring_two (SMainLoop * self);
 
100
 
 
101
/* -----------------------------------------------------------------------------
 
102
 * imprementation of the real functions and stuffs.
 
103
 * -----------------------------------------------------------------------------
 
104
 */
 
105
 
 
106
SMainLoop *
 
107
s_main_loop_new () {
 
108
  SMainLoop * self = malloc (sizeof (SMainLoop));
 
109
 
 
110
  for (sint i = 0; i < S_MAIN_LOOP_RING_LAST; i++){
 
111
    for (sint j = 0; j < S_MAIN_LOOP_STATE_LAST; j++){
 
112
      self->mutex[i][j] = s_mutex_new ();
 
113
    }
 
114
  }
 
115
  
 
116
  self->teardown_handler_mutex = s_mutex_new ();
 
117
  
 
118
  s_mutex_lock (self->mutex[S_MAIN_LOOP_RING_NONE][S_MAIN_LOOP_STATE_NONE]);
 
119
 
 
120
  self->ref_count = 1;
 
121
  self->ring_1_state = S_MAIN_LOOP_STATE_EVENT;
 
122
  self->ring_2_state = S_MAIN_LOOP_STATE_EVENT;
 
123
  self->is_run = FALSE;
 
124
  
 
125
  self->ring_1_event_handler_list = s_linked_list_new (FREEFUNC (free));
 
126
  self->ring_1_io_push_list = s_linked_list_new (FREEFUNC (free));
 
127
  self->ring_1_io_pull_list = s_linked_list_new (FREEFUNC (free));
 
128
  self->ring_1_workers_list = s_linked_list_new (FREEFUNC (free));
 
129
 
 
130
  self->ring_2_event_handler_list = s_linked_list_new (FREEFUNC (free));
 
131
  self->ring_2_io_push_list = s_linked_list_new (FREEFUNC (free));
 
132
  self->ring_2_io_pull_list = s_linked_list_new (FREEFUNC (free));
 
133
  self->ring_2_workers_list = s_linked_list_new (FREEFUNC (free));
 
134
 
 
135
  self->teardown_handler_list = s_linked_list_new (FREEFUNC (_s_main_loop_teardown_handerer_obj_free));
 
136
 
 
137
  s_mutex_unlock (self->mutex[S_MAIN_LOOP_RING_NONE][S_MAIN_LOOP_STATE_NONE]);
 
138
 
 
139
  return self;
 
140
}
 
141
 
 
142
SMainLoop *
 
143
s_main_loop_get_default () {
 
144
  if (_default_main_loop == NULL) {
 
145
    _default_main_loop = s_main_loop_new ();
 
146
  }
 
147
  return _default_main_loop;
 
148
}
 
149
 
 
150
void
 
151
s_main_loop_run (SMainLoop * self) {
 
152
  assert (self != NULL);
 
153
  self->is_run = TRUE;
 
154
  while (self->is_run) {
 
155
    switch (self->ring_1_state) {
 
156
      case (S_MAIN_LOOP_STATE_EVENT):
 
157
        _s_main_loop_do_list (self->ring_1_event_handler_list);
 
158
        self->ring_1_state = S_MAIN_LOOP_STATE_IO_PUSH;
 
159
        break;
 
160
      case (S_MAIN_LOOP_STATE_IO_PUSH):
 
161
        _s_main_loop_do_list (self->ring_1_io_push_list);
 
162
        self->ring_1_state = S_MAIN_LOOP_STATE_IO_PULL;
 
163
        break;
 
164
      case (S_MAIN_LOOP_STATE_IO_PULL):
 
165
        _s_main_loop_do_list (self->ring_1_io_pull_list);
 
166
        self->ring_1_state = S_MAIN_LOOP_STATE_RING_TWO_NEXT;
 
167
        break;
 
168
      case (S_MAIN_LOOP_STATE_RING_TWO_NEXT):
 
169
        _s_main_loop_do_ring_two (self);
 
170
        self->ring_1_state = S_MAIN_LOOP_STATE_DO_WORKERS;
 
171
        break;
 
172
      case (S_MAIN_LOOP_STATE_DO_WORKERS):
 
173
        _s_main_loop_do_list (self->ring_1_workers_list);
 
174
        self->ring_1_state = S_MAIN_LOOP_STATE_SLEEP;
 
175
        break;
 
176
      case (S_MAIN_LOOP_STATE_SLEEP):
 
177
        s_usleep (1);
 
178
        self->ring_1_state = S_MAIN_LOOP_STATE_EVENT;
 
179
        break;
 
180
      default:
 
181
        s_err_print ("Reaching a place that should not be reached.\n"
 
182
                     "Aborting.");
 
183
        exit (666);
 
184
    }
 
185
    s_mutex_lock (self->mutex[S_MAIN_LOOP_RING_NONE][S_MAIN_LOOP_STATE_NONE]);
 
186
 
 
187
    sint no_of_handlers = 0;
 
188
 
 
189
    no_of_handlers += s_linked_list_len (self->ring_1_event_handler_list);
 
190
    no_of_handlers += s_linked_list_len (self->ring_1_io_push_list);
 
191
    no_of_handlers += s_linked_list_len (self->ring_1_io_pull_list);
 
192
    no_of_handlers += s_linked_list_len (self->ring_1_workers_list);
 
193
 
 
194
    no_of_handlers += s_linked_list_len (self->ring_2_event_handler_list);
 
195
    no_of_handlers += s_linked_list_len (self->ring_2_io_push_list);
 
196
    no_of_handlers += s_linked_list_len (self->ring_2_io_pull_list);
 
197
    no_of_handlers += s_linked_list_len (self->ring_2_workers_list);
 
198
 
 
199
    if (!self->is_run || no_of_handlers == 0) {
 
200
      s_mutex_unlock (self->mutex[S_MAIN_LOOP_RING_NONE][S_MAIN_LOOP_STATE_NONE]);
 
201
      break;
 
202
    }
 
203
    s_mutex_unlock (self->mutex[S_MAIN_LOOP_RING_NONE][S_MAIN_LOOP_STATE_NONE]);
 
204
  }
 
205
}
 
206
 
 
207
 
 
208
void
 
209
s_main_loop_quit (SMainLoop * self) {
 
210
  s_mutex_lock (self->mutex[S_MAIN_LOOP_RING_NONE][S_MAIN_LOOP_STATE_NONE]);
 
211
  self->is_run = FALSE;
 
212
 
 
213
  s_linked_list_free (self->ring_1_event_handler_list, TRUE);
 
214
  s_linked_list_free (self->ring_1_io_push_list, TRUE);
 
215
  s_linked_list_free (self->ring_1_io_pull_list, TRUE);
 
216
  s_linked_list_free (self->ring_1_workers_list, TRUE);
 
217
 
 
218
  s_linked_list_free (self->ring_2_event_handler_list, TRUE);
 
219
  s_linked_list_free (self->ring_2_io_push_list, TRUE);
 
220
  s_linked_list_free (self->ring_2_io_pull_list, TRUE);
 
221
  s_linked_list_free (self->ring_2_workers_list, TRUE);
 
222
 
 
223
  s_linked_list_free (self->teardown_handler_list, TRUE);
 
224
 
 
225
  for (sint i = 0; i < S_MAIN_LOOP_RING_LAST; i++) {
 
226
    for (sint j = 0; j < S_MAIN_LOOP_STATE_LAST; j++) {
 
227
      s_print ("[%d][%d]\n",i,j);
 
228
      s_mutex_free (self->mutex[i][j]);
 
229
    }
 
230
  }
 
231
  
 
232
  s_mutex_free (self->teardown_handler_mutex);
 
233
  
 
234
  free (self);
 
235
}
 
236
 
 
237
void
 
238
s_main_loop_ref (SMainLoop * self) {
 
239
  self->ref_count++;
 
240
}
 
241
 
 
242
void
 
243
s_main_loop_unref (SMainLoop * self) {
 
244
  self->ref_count--;
 
245
}
 
246
 
 
247
void
 
248
s_main_loop_add_event_handler (SMainLoop * self,
 
249
                               SMainLoopRing ring,
 
250
                               RunFunc event_handler,
 
251
                               spointer user_data) {
 
252
  //
 
253
  s_mutex_lock (self->mutex[ring][S_MAIN_LOOP_STATE_EVENT]);
 
254
  if (user_data == NULL) {
 
255
    s_err_print ("No user data provided to the event handeler."
 
256
                 " This is an error.");
 
257
    print_backtrace ();
 
258
    return;
 
259
  }
 
260
 
 
261
  SMainLoopItem * item = malloc (sizeof (SMainLoopItem));
 
262
  item->state = S_MAIN_LOOP_STATE_EVENT;
 
263
  item->callback = event_handler;
 
264
  item->user_data = user_data;
 
265
  item->is_alive = TRUE;
 
266
 
 
267
  switch (ring) {
 
268
    case (S_MAIN_LOOP_RING_ONE):
 
269
      s_linked_list_append (self->ring_1_event_handler_list, item);
 
270
      break;
 
271
    case (S_MAIN_LOOP_RING_TWO):
 
272
      s_linked_list_append (self->ring_2_event_handler_list, item);
 
273
      break;
 
274
    default:
 
275
      s_err_print ("Invalid value of the ring parameter for "
 
276
                   "s_main_loop_add_io_pull function.");
 
277
  }
 
278
  s_mutex_unlock (self->mutex[ring][S_MAIN_LOOP_STATE_EVENT]);
 
279
}
 
280
 
 
281
void
 
282
s_main_loop_add_io_push (SMainLoop * self,
 
283
                         SMainLoopRing ring,
 
284
                         RunFunc push_callback,
 
285
                         spointer user_data) {
 
286
  //
 
287
  s_mutex_lock (self->mutex[ring][S_MAIN_LOOP_STATE_IO_PUSH]);
 
288
  if (user_data == NULL) {
 
289
    s_err_print ("No user data provided to the IO push event."
 
290
                 " This is an error.");
 
291
    print_backtrace ();
 
292
    return;
 
293
  }
 
294
 
 
295
  SMainLoopItem * item = malloc (sizeof (SMainLoopItem));
 
296
  item->state = S_MAIN_LOOP_STATE_IO_PUSH;
 
297
  item->callback = push_callback;
 
298
  item->user_data = user_data;
 
299
  item->is_alive = TRUE;
 
300
 
 
301
  switch (ring) {
 
302
    case (S_MAIN_LOOP_RING_ONE):
 
303
      s_linked_list_append (self->ring_1_io_push_list, item);
 
304
      break;
 
305
    case (S_MAIN_LOOP_RING_TWO):
 
306
      s_linked_list_append (self->ring_2_io_push_list, item);
 
307
      break;
 
308
    default:
 
309
      s_err_print ("Invalid value of the ring parameter for "
 
310
                   "s_main_loop_add_io_push function.");
 
311
  }
 
312
  s_mutex_unlock (self->mutex[ring][S_MAIN_LOOP_STATE_IO_PUSH]);
 
313
}
 
314
 
 
315
void
 
316
s_main_loop_add_io_pull (SMainLoop * self,
 
317
                         SMainLoopRing ring,
 
318
                         RunFunc pull_callback,
 
319
                         spointer user_data) {
 
320
  //
 
321
  s_mutex_lock (self->mutex[ring][S_MAIN_LOOP_STATE_IO_PULL]);
 
322
  if (user_data == NULL) {
 
323
    s_err_print ("No user data provided to the IO pull event."
 
324
                 " This is an error.");
 
325
    print_backtrace ();
 
326
    return;
 
327
  }
 
328
 
 
329
  SMainLoopItem * item = malloc (sizeof (SMainLoopItem));
 
330
  item->state = S_MAIN_LOOP_STATE_IO_PULL;
 
331
  item->callback = pull_callback;
 
332
  item->user_data = user_data;
 
333
  item->is_alive = TRUE;
 
334
 
 
335
  switch (ring) {
 
336
    case (S_MAIN_LOOP_RING_ONE):
 
337
      s_linked_list_append (self->ring_1_io_pull_list, item);
 
338
      break;
 
339
    case (S_MAIN_LOOP_RING_TWO):
 
340
      s_linked_list_append (self->ring_2_io_pull_list, item);
 
341
      break;
 
342
    default:
 
343
      s_err_print ("Invalid value of the ring parameter for "
 
344
                   "s_main_loop_add_ function.");
 
345
  }
 
346
  s_mutex_unlock (self->mutex[ring][S_MAIN_LOOP_STATE_IO_PULL]);
 
347
}
 
348
 
 
349
void
 
350
s_main_loop_add_worker (SMainLoop * self,
 
351
                        SMainLoopRing ring,
 
352
                        RunFunc worker_callback,
 
353
                        spointer user_data) {
 
354
  //
 
355
  s_mutex_lock (self->mutex[ring][S_MAIN_LOOP_STATE_DO_WORKERS]);
 
356
  s_dbg_print ("locked");
 
357
  
 
358
  SMainLoopItem * item = malloc (sizeof (SMainLoopItem));
 
359
  item->state = S_MAIN_LOOP_STATE_DO_WORKERS;
 
360
  item->callback = worker_callback;
 
361
  item->user_data = user_data;
 
362
  item->is_alive = TRUE;
 
363
 
 
364
  switch (ring) {
 
365
    case (S_MAIN_LOOP_RING_ONE):
 
366
      s_linked_list_append (self->ring_1_workers_list, item);
 
367
      break;
 
368
    case (S_MAIN_LOOP_RING_TWO):
 
369
      s_linked_list_append (self->ring_2_workers_list, item);
 
370
      break;
 
371
    default:
 
372
      s_err_print ("Invalid value of the ring parameter for "
 
373
                   "s_main_loop_add_worker function.");
 
374
  }
 
375
  s_mutex_unlock (self->mutex[ring][S_MAIN_LOOP_STATE_DO_WORKERS]);
 
376
  s_dbg_print ("Unlocked");
 
377
}
 
378
 
 
379
void
 
380
s_main_loop_add_teardown_handler (SMainLoop * self,
 
381
                                  Callback teardown_handler,
 
382
                                                          spointer self_obj,
 
383
                                                          spointer user_data) {
 
384
  s_mutex_lock (self->teardown_handler_mutex);
 
385
  if (self == NULL) {
 
386
    s_err_print ("No self pointer provided for the teardown handler "
 
387
                 "This is an error.");
 
388
    print_backtrace ();
 
389
  }
 
390
 
 
391
  SMainLoopTeardownHandler * item = malloc (sizeof (SMainLoopTeardownHandler));
 
392
 
 
393
  item->teardown_handler = teardown_handler;
 
394
  item->obj_self = self_obj;
 
395
  item->user_data = user_data;
 
396
 
 
397
  s_linked_list_append (self->teardown_handler_list, item);
 
398
  s_mutex_unlock (self->teardown_handler_mutex);
 
399
}
 
400
 
 
401
/* ************************************************************************** */
 
402
 
 
403
void
 
404
_s_main_loop_teardown_handerer_obj_free (SMainLoopTeardownHandler * self) {
 
405
  Callback callback = self->teardown_handler;
 
406
  callback (self->obj_self, self->user_data);
 
407
  free (self);
 
408
}
 
409
 
 
410
void
 
411
_s_main_loop_do_list (SLinkedList * event_handler_list) {
 
412
  if (s_linked_list_len (event_handler_list) == 0) {
 
413
    return;
 
414
  }
 
415
 
 
416
  s_linked_list_head (event_handler_list);
 
417
  do {
 
418
    SMainLoopItem * item = s_linked_list_get_current (event_handler_list);
 
419
    RunFunc callback = item->callback;
 
420
    spointer user_data = item->user_data;
 
421
 
 
422
    item->is_alive  = callback (user_data);
 
423
  } while (s_linked_list_next (event_handler_list));
 
424
 
 
425
  s_linked_list_head (event_handler_list);
 
426
  do {
 
427
    SMainLoopItem * item = s_linked_list_get_current (event_handler_list);
 
428
    if (!item->is_alive) {
 
429
      s_linked_list_remove_current (event_handler_list, TRUE);
 
430
    }
 
431
  } while (s_linked_list_next (event_handler_list));
 
432
 
 
433
}
 
434
 
 
435
void
 
436
_s_main_loop_do_ring_two (SMainLoop * self) {
 
437
  switch (self->ring_2_state) {
 
438
    case (S_MAIN_LOOP_STATE_EVENT):
 
439
      _s_main_loop_do_list (self->ring_2_event_handler_list);
 
440
      self->ring_2_state = S_MAIN_LOOP_STATE_IO_PUSH;
 
441
      break;
 
442
    case (S_MAIN_LOOP_STATE_IO_PUSH):
 
443
      _s_main_loop_do_list (self->ring_2_io_push_list);
 
444
      self->ring_2_state = S_MAIN_LOOP_STATE_IO_PULL;
 
445
      break;
 
446
    case (S_MAIN_LOOP_STATE_IO_PULL):
 
447
      _s_main_loop_do_list (self->ring_2_io_pull_list);
 
448
      self->ring_2_state = S_MAIN_LOOP_STATE_DO_WORKERS;
 
449
      break;
 
450
    case (S_MAIN_LOOP_STATE_DO_WORKERS):
 
451
      _s_main_loop_do_list (self->ring_2_workers_list);
 
452
      self->ring_2_state = S_MAIN_LOOP_STATE_EVENT;
 
453
      break;
 
454
    default:
 
455
      s_err_print ("Reaching a place that should not be reached.\n"
 
456
                   "Aborting.");
 
457
      exit (666);
 
458
  }
 
459
}
 
460
 
 
461