38
42
GDestroyNotify notify;
45
struct _InfIoDispatch {
48
InfIoDispatchFunc func;
50
GDestroyNotify notify;
53
typedef struct _InfGtkIoUserdata InfGtkIoUserdata;
54
struct _InfGtkIoUserdata {
57
InfIoTimeout* timeout;
58
InfIoDispatch* dispatch;
41
65
typedef struct _InfGtkIoPrivate InfGtkIoPrivate;
42
66
struct _InfGtkIoPrivate {
43
67
/* TODO: GMainContext */
70
int* mutexref; /* reference counter for the mutex */
49
77
#define INF_GTK_IO_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), INF_GTK_TYPE_IO, InfGtkIoPrivate))
51
79
static GObjectClass* parent_class;
54
inf_gtk_io_watch_new(InfNativeSocket* socket,
82
inf_gtk_io_userdata_free(gpointer data)
84
InfGtkIoUserdata* userdata;
85
userdata = (InfGtkIoUserdata*)data;
87
/* Note that the shared members may already be invalid at this point */
89
/* Note also that we cannot lock the mutex here, because this function
90
* might or might not be called with it being locked already. However in
91
* this case we can use an atomic operation instead. */
93
if(g_atomic_int_dec_and_test(userdata->mutexref) == TRUE)
95
g_mutex_free(userdata->mutex);
96
g_free(userdata->mutexref);
99
g_slice_free(InfGtkIoUserdata, userdata);
103
inf_gtk_io_watch_new(InfGtkIo* io,
104
InfNativeSocket* socket,
56
106
gpointer user_data,
57
107
GDestroyNotify notify)
60
watch = g_slice_new(InfGtkIoWatch);
110
watch = g_slice_new(InfIoWatch);
61
112
watch->socket = socket;
63
114
watch->func = func;
64
115
watch->user_data = user_data;
65
116
watch->notify = notify;
117
watch->executing = FALSE;
118
watch->disposed = FALSE;
70
inf_gtk_io_watch_free(InfGtkIoWatch* watch)
123
inf_gtk_io_watch_free(InfIoWatch* watch)
73
g_source_remove(watch->id);
75
126
watch->notify(watch->user_data);
77
g_slice_free(InfGtkIoWatch, watch);
128
g_slice_free(InfIoWatch, watch);
80
static InfGtkIoTimeout*
81
132
inf_gtk_io_timeout_new(InfGtkIo* io,
82
133
InfIoTimeoutFunc func,
83
134
gpointer user_data,
84
135
GDestroyNotify notify)
86
InfGtkIoTimeout* timeout;
87
timeout = g_slice_new(InfGtkIoTimeout);
137
InfIoTimeout* timeout;
138
timeout = g_slice_new(InfIoTimeout);
142
222
InfGtkIoPrivate* priv;
145
226
io = INF_GTK_IO(object);
146
227
priv = INF_GTK_IO_PRIVATE(io);
229
g_mutex_lock(priv->mutex);
148
231
for(item = priv->watches; item != NULL; item = g_slist_next(item))
149
inf_gtk_io_watch_free((InfGtkIoWatch*)item->data);
233
/* We have a stack-ref on the InfGtkIo when exeucting the callback */
234
g_assert( ((InfIoWatch*)item->data)->executing == FALSE);
236
if( ((InfIoWatch*)item->data)->id != 0)
237
g_source_remove( ((InfIoWatch*)item->data)->id);
238
inf_gtk_io_watch_free((InfIoWatch*)item->data);
150
240
g_slist_free(priv->watches);
152
242
for(item = priv->timeouts; item != NULL; item = g_slist_next(item))
153
inf_gtk_io_timeout_free((InfGtkIoTimeout*)item->data);
244
if( ((InfIoTimeout*)item->data)->id != 0)
245
g_source_remove( ((InfIoTimeout*)item->data)->id);
246
inf_gtk_io_timeout_free((InfIoTimeout*)item->data);
154
248
g_slist_free(priv->timeouts);
250
for(item = priv->dispatchs; item != NULL; item = g_slist_next(item))
252
if( ((InfIoDispatch*)item->data)->id != 0)
253
g_source_remove( ((InfIoDispatch*)item->data)->id);
254
inf_gtk_io_dispatch_free((InfIoDispatch*)item->data);
256
g_slist_free(priv->dispatchs);
257
g_mutex_unlock(priv->mutex);
259
/* some callback userdata might still have a reference to the mutex, and
260
* wait for the callback function to be called until it is released. The
261
* callback function will do nothing since g_source_is_destroyed() will
262
* return FALSE since we removed all sources above. But we need to keep
263
* the mutex alive so that the callbacks can check. */
264
if(g_atomic_int_dec_and_test(priv->mutexref))
266
g_mutex_free(priv->mutex);
267
g_free(priv->mutexref);
156
270
G_OBJECT_CLASS(parent_class)->finalize(object);
193
307
GIOCondition condition,
194
308
gpointer user_data)
196
InfGtkIoWatch* watch;
197
watch = (InfGtkIoWatch*)user_data;
201
inf_gtk_io_inf_events_from_glib_events(condition),
310
InfGtkIoUserdata* userdata;
312
InfGtkIoPrivate* priv;
314
userdata = (InfGtkIoUserdata*)user_data;
315
g_mutex_lock(userdata->mutex);
316
if(!g_source_is_destroyed(g_main_current_source()))
318
/* At this point we now that InfGtkIo is still alive because otherwise
319
* the source would have been destroyed in _finalize. */
320
watch = userdata->shared.watch;
322
g_object_ref(watch->io);
323
priv = INF_GTK_IO_PRIVATE(watch->io);
325
g_assert(*priv->mutexref > 1); /* Both InfGtkIo and we have a reference */
326
g_assert(g_slist_find(priv->watches, watch) != NULL);
328
watch->executing = TRUE;
329
g_mutex_unlock(userdata->mutex);
331
/* Note that at this point the watch object could be removed from the
332
* list, but, since executing is set to TRUE, it is not freed. */
336
inf_gtk_io_inf_events_from_glib_events(condition),
340
g_mutex_lock(userdata->mutex);
341
watch->executing = FALSE;
342
g_object_unref(watch->io);
344
if(watch->disposed == TRUE)
346
g_mutex_unlock(userdata->mutex);
347
inf_gtk_io_watch_free(watch);
351
g_mutex_unlock(userdata->mutex);
356
g_mutex_unlock(userdata->mutex);
209
363
inf_gtk_io_timeout_func(gpointer user_data)
211
InfGtkIoTimeout* timeout;
212
InfGtkIoPrivate* priv;
214
timeout = (InfGtkIoTimeout*)user_data;
215
priv = INF_GTK_IO_PRIVATE(timeout->io);
216
timeout->id = 0; /* we return FALSE to stop the glib timeout */
218
priv->timeouts = g_slist_remove(priv->timeouts, timeout);
220
timeout->func(timeout->user_data);
221
inf_gtk_io_timeout_free(timeout);
226
inf_gtk_io_io_watch(InfIo* io,
227
InfNativeSocket* socket,
231
GDestroyNotify notify)
233
InfGtkIoPrivate* priv;
234
InfGtkIoWatch* watch;
365
InfIoTimeout* timeout;
366
InfGtkIoPrivate* priv;
367
InfGtkIoUserdata* userdata;
369
userdata = (InfGtkIoUserdata*)user_data;
370
g_mutex_lock(userdata->mutex);
371
if(!g_source_is_destroyed(g_main_current_source()))
373
/* At this point we now that InfGtkIo is still alive because otherwise
374
* the source would have been destroyed in _finalize. */
375
timeout = userdata->shared.timeout;
376
priv = INF_GTK_IO_PRIVATE(timeout->io);
378
g_assert(*priv->mutexref > 1); /* Both InfGtkIo and we have a reference */
379
g_assert(g_slist_find(priv->timeouts, timeout) != NULL);
380
priv->timeouts = g_slist_remove(priv->timeouts, timeout);
381
g_mutex_unlock(userdata->mutex);
383
timeout->func(timeout->user_data);
384
inf_gtk_io_timeout_free(timeout);
388
g_mutex_unlock(userdata->mutex);
395
inf_gtk_io_dispatch_func(gpointer user_data)
397
InfIoDispatch* dispatch;
398
InfGtkIoPrivate* priv;
399
InfGtkIoUserdata* userdata;
401
userdata = (InfGtkIoUserdata*)user_data;
402
g_mutex_lock(userdata->mutex);
403
if(!g_source_is_destroyed(g_main_current_source()))
405
/* At this point we now that InfGtkIo is still alive because otherwise
406
* the source would have been destroyed in _finalize. */
407
dispatch = userdata->shared.dispatch;
408
priv = INF_GTK_IO_PRIVATE(dispatch->io);
410
g_assert(*priv->mutexref > 1); /* Both InfGtkIo and we have a reference */
411
g_assert(g_slist_find(priv->dispatchs, dispatch) != NULL);
412
priv->dispatchs = g_slist_remove(priv->dispatchs, dispatch);
413
g_mutex_unlock(userdata->mutex);
415
dispatch->func(dispatch->user_data);
416
inf_gtk_io_dispatch_free(dispatch);
420
g_mutex_unlock(userdata->mutex);
427
inf_gtk_io_io_add_watch(InfIo* io,
428
InfNativeSocket* socket,
432
GDestroyNotify notify)
434
InfGtkIoPrivate* priv;
436
InfGtkIoUserdata* data;
235
437
GIOChannel* channel;
237
439
priv = INF_GTK_IO_PRIVATE(io);
441
g_mutex_lock(priv->mutex);
238
442
watch = inf_gtk_io_watch_lookup(INF_GTK_IO(io), socket);
244
watch = inf_gtk_io_watch_new(socket, func, user_data, notify);
245
priv->watches = g_slist_prepend(priv->watches, watch);
445
g_mutex_unlock(priv->mutex);
449
watch = inf_gtk_io_watch_new(
457
data = g_slice_new(InfGtkIoUserdata);
458
data->shared.watch = watch;
459
data->mutex = priv->mutex;
460
data->mutexref = priv->mutexref;
461
g_atomic_int_inc(data->mutexref);
464
channel = g_io_channel_win32_new_socket(*socket);
466
channel = g_io_channel_unix_new(*socket);
469
watch->id = g_io_add_watch_full(
472
inf_gtk_io_inf_events_to_glib_events(events),
473
inf_gtk_io_watch_func,
475
inf_gtk_io_userdata_free
478
g_io_channel_unref(channel);
480
priv->watches = g_slist_prepend(priv->watches, watch);
481
g_mutex_unlock(priv->mutex);
487
inf_gtk_io_io_update_watch(InfIo* io,
491
InfGtkIoPrivate* priv;
492
InfGtkIoUserdata* data;
495
priv = INF_GTK_IO_PRIVATE(io);
496
g_mutex_lock(priv->mutex);
498
g_assert(g_slist_find(priv->watches, watch) != NULL);
500
data = g_slice_new(InfGtkIoUserdata);
501
data->shared.watch = watch;
502
data->mutex = priv->mutex;
503
data->mutexref = priv->mutexref;
504
g_atomic_int_inc(data->mutexref);
505
g_mutex_unlock(priv->mutex);
507
g_source_remove(watch->id);
510
channel = g_io_channel_win32_new_socket(*watch->socket);
512
channel = g_io_channel_unix_new(*watch->socket);
515
watch->id = g_io_add_watch_full(
518
inf_gtk_io_inf_events_to_glib_events(events),
519
inf_gtk_io_watch_func,
521
inf_gtk_io_userdata_free
524
g_io_channel_unref(channel);
528
inf_gtk_io_io_remove_watch(InfIo* io,
531
InfGtkIoPrivate* priv;
533
priv = INF_GTK_IO_PRIVATE(io);
534
g_mutex_lock(priv->mutex);
536
g_assert(g_slist_find(priv->watches, watch) != NULL);
537
priv->watches = g_slist_remove(priv->watches, watch);
541
/* If we are currently running the watch callback then don't free the
542
* watch object right now, because this would destroy the userdata before
543
* the callback finished running. Instead, remember that the watch is
544
* going to be disposed and remove it in the watch func right after
545
* having called the callback. */
546
watch->disposed = TRUE;
547
g_mutex_unlock(priv->mutex);
252
g_source_remove(watch->id);
254
watch->user_data = user_data;
258
inf_gtk_io_watch_free(watch);
259
priv->watches = g_slist_remove(priv->watches, watch);
265
channel = g_io_channel_unix_new(*socket);
267
watch->id = g_io_add_watch(
269
inf_gtk_io_inf_events_to_glib_events(events),
270
inf_gtk_io_watch_func,
274
g_io_channel_unref(channel);
551
g_mutex_unlock(priv->mutex);
552
inf_gtk_io_watch_free(watch);
555
/* Note that we can do this safely without having locked the mutex because
556
* if the callback function is currently being invoked then its user_data
557
* will not be destroyed immediately. */
558
g_source_remove(watch->id);
279
562
inf_gtk_io_io_add_timeout(InfIo* io,
281
564
InfIoTimeoutFunc func,
283
566
GDestroyNotify notify)
285
568
InfGtkIoPrivate* priv;
286
InfGtkIoTimeout* timeout;
569
InfIoTimeout* timeout;
570
InfGtkIoUserdata* data;
288
572
priv = INF_GTK_IO_PRIVATE(io);
289
573
timeout = inf_gtk_io_timeout_new(INF_GTK_IO(io), func, user_data, notify);
290
timeout->id = g_timeout_add(msecs, inf_gtk_io_timeout_func, timeout);
575
data = g_slice_new(InfGtkIoUserdata);
576
data->shared.timeout = timeout;
577
data->mutex = priv->mutex;
578
data->mutexref = priv->mutexref;
580
g_mutex_lock(priv->mutex);
581
g_atomic_int_inc(data->mutexref);
583
timeout->id = g_timeout_add_full(
586
inf_gtk_io_timeout_func,
588
inf_gtk_io_userdata_free
291
591
priv->timeouts = g_slist_prepend(priv->timeouts, timeout);
592
g_mutex_unlock(priv->mutex);
297
598
inf_gtk_io_io_remove_timeout(InfIo* io,
298
gpointer timeout_handle)
599
InfIoTimeout* timeout)
300
601
InfGtkIoPrivate* priv;
301
InfGtkIoTimeout* timeout;
303
603
priv = INF_GTK_IO_PRIVATE(io);
304
timeout = (InfGtkIoTimeout*)timeout_handle;
605
g_mutex_lock(priv->mutex);
305
606
g_assert(g_slist_find(priv->timeouts, timeout) != NULL);
307
607
priv->timeouts = g_slist_remove(priv->timeouts, timeout);
608
g_mutex_unlock(priv->mutex);
610
/* Note that we can do this safely without having locked the mutex because
611
* if the callback function is currently being invoked then its user_data
612
* will not be destroyed immediately. */
613
g_source_remove(timeout->id);
309
615
inf_gtk_io_timeout_free(timeout);
618
static InfIoDispatch*
619
inf_gtk_io_io_add_dispatch(InfIo* io,
620
InfIoDispatchFunc func,
622
GDestroyNotify notify)
624
InfGtkIoPrivate* priv;
625
InfIoDispatch* dispatch;
626
InfGtkIoUserdata* data;
628
priv = INF_GTK_IO_PRIVATE(io);
629
dispatch = inf_gtk_io_dispatch_new(INF_GTK_IO(io), func, user_data, notify);
631
data = g_slice_new(InfGtkIoUserdata);
632
data->shared.dispatch = dispatch;
633
data->mutex = priv->mutex;
634
data->mutexref = priv->mutexref;
636
g_mutex_lock(priv->mutex);
637
g_atomic_int_inc(data->mutexref);
639
dispatch->id = g_idle_add_full(
640
G_PRIORITY_DEFAULT_IDLE,
641
inf_gtk_io_dispatch_func,
643
inf_gtk_io_userdata_free
646
priv->dispatchs = g_slist_prepend(priv->dispatchs, dispatch);
647
g_mutex_unlock(priv->mutex);
653
inf_gtk_io_io_remove_dispatch(InfIo* io,
654
InfIoDispatch* dispatch)
656
InfGtkIoPrivate* priv;
658
priv = INF_GTK_IO_PRIVATE(io);
660
g_mutex_lock(priv->mutex);
661
g_assert(g_slist_find(priv->dispatchs, dispatch) != NULL);
662
priv->dispatchs = g_slist_remove(priv->dispatchs, dispatch);
663
g_mutex_unlock(priv->mutex);
665
/* Note that we can do this safely without having locked the mutex because
666
* if the callback function is currently being invoked then its user_data
667
* will not be destroyed immediately. */
668
g_source_remove(dispatch->id);
670
inf_gtk_io_dispatch_free(dispatch);
313
674
inf_gtk_io_class_init(gpointer g_class,
314
675
gpointer class_data)