~ubuntu-branches/ubuntu/utopic/libinfinity/utopic-proposed

« back to all changes in this revision

Viewing changes to libinfgtk/inf-gtk-io.c

  • Committer: Bazaar Package Importer
  • Author(s): Philipp Kern
  • Date: 2011-04-01 10:44:57 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20110401104457-q7927ly61fr51tqs
Tags: 0.5.0-1
* New upstream release.
* Drop patches applied upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* libinfinity - a GObject-based infinote implementation
2
 
 * Copyright (C) 2007, 2008, 2009 Armin Burgmeier <armin@arbur.net>
 
2
 * Copyright (C) 2007-2011 Armin Burgmeier <armin@arbur.net>
3
3
 *
4
4
 * This library is free software; you can redistribute it and/or
5
5
 * modify it under the terms of the GNU Lesser General Public
20
20
#include <libinfgtk/inf-gtk-io.h>
21
21
#include <libinfinity/common/inf-io.h>
22
22
 
23
 
typedef struct _InfGtkIoWatch InfGtkIoWatch;
24
 
struct _InfGtkIoWatch {
 
23
struct _InfIoWatch {
 
24
  InfGtkIo* io;
25
25
  InfNativeSocket* socket;
26
26
  guint id;
27
 
  InfIoFunc func;
 
27
  InfIoWatchFunc func;
28
28
  gpointer user_data;
29
29
  GDestroyNotify notify;
 
30
 
 
31
  /* Additional state to avoid freeing the userdata while running
 
32
   * the callback */
 
33
  gboolean executing;
 
34
  gboolean disposed;
30
35
};
31
36
 
32
 
typedef struct _InfGtkIoTimeout InfGtkIoTimeout;
33
 
struct _InfGtkIoTimeout {
 
37
struct _InfIoTimeout {
34
38
  InfGtkIo* io;
35
39
  guint id;
36
40
  InfIoTimeoutFunc func;
38
42
  GDestroyNotify notify;
39
43
};
40
44
 
 
45
struct _InfIoDispatch {
 
46
  InfGtkIo* io;
 
47
  guint id;
 
48
  InfIoDispatchFunc func;
 
49
  gpointer user_data;
 
50
  GDestroyNotify notify;
 
51
};
 
52
 
 
53
typedef struct _InfGtkIoUserdata InfGtkIoUserdata;
 
54
struct _InfGtkIoUserdata {
 
55
  union {
 
56
    InfIoWatch* watch;
 
57
    InfIoTimeout* timeout;
 
58
    InfIoDispatch* dispatch;
 
59
  } shared;
 
60
 
 
61
  GMutex* mutex;
 
62
  int* mutexref;
 
63
};
 
64
 
41
65
typedef struct _InfGtkIoPrivate InfGtkIoPrivate;
42
66
struct _InfGtkIoPrivate {
43
67
  /* TODO: GMainContext */
44
68
 
 
69
  GMutex* mutex;
 
70
  int* mutexref; /* reference counter for the mutex */
 
71
 
45
72
  GSList* watches;
46
73
  GSList* timeouts;
 
74
  GSList* dispatchs;
47
75
};
48
76
 
49
77
#define INF_GTK_IO_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), INF_GTK_TYPE_IO, InfGtkIoPrivate))
50
78
 
51
79
static GObjectClass* parent_class;
52
80
 
53
 
static InfGtkIoWatch*
54
 
inf_gtk_io_watch_new(InfNativeSocket* socket,
55
 
                     InfIoFunc func,
 
81
static void
 
82
inf_gtk_io_userdata_free(gpointer data)
 
83
{
 
84
  InfGtkIoUserdata* userdata;
 
85
  userdata = (InfGtkIoUserdata*)data;
 
86
 
 
87
  /* Note that the shared members may already be invalid at this point */
 
88
 
 
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. */
 
92
 
 
93
  if(g_atomic_int_dec_and_test(userdata->mutexref) == TRUE)
 
94
  {
 
95
    g_mutex_free(userdata->mutex);
 
96
    g_free(userdata->mutexref);
 
97
  }
 
98
 
 
99
  g_slice_free(InfGtkIoUserdata, userdata);
 
100
}
 
101
 
 
102
static InfIoWatch*
 
103
inf_gtk_io_watch_new(InfGtkIo* io,
 
104
                     InfNativeSocket* socket,
 
105
                     InfIoWatchFunc func,
56
106
                     gpointer user_data,
57
107
                     GDestroyNotify notify)
58
108
{
59
 
  InfGtkIoWatch* watch;
60
 
  watch = g_slice_new(InfGtkIoWatch);
 
109
  InfIoWatch* watch;
 
110
  watch = g_slice_new(InfIoWatch);
 
111
  watch->io = io;
61
112
  watch->socket = socket;
62
113
  watch->id = 0;
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;
66
119
  return watch;
67
120
}
68
121
 
69
122
static void
70
 
inf_gtk_io_watch_free(InfGtkIoWatch* watch)
 
123
inf_gtk_io_watch_free(InfIoWatch* watch)
71
124
{
72
 
  if(watch->id != 0)
73
 
    g_source_remove(watch->id);
74
125
  if(watch->notify)
75
126
    watch->notify(watch->user_data);
76
127
 
77
 
  g_slice_free(InfGtkIoWatch, watch);
 
128
  g_slice_free(InfIoWatch, watch);
78
129
}
79
130
 
80
 
static InfGtkIoTimeout*
 
131
static InfIoTimeout*
81
132
inf_gtk_io_timeout_new(InfGtkIo* io,
82
133
                       InfIoTimeoutFunc func,
83
134
                       gpointer user_data,
84
135
                       GDestroyNotify notify)
85
136
{
86
 
  InfGtkIoTimeout* timeout;
87
 
  timeout = g_slice_new(InfGtkIoTimeout);
 
137
  InfIoTimeout* timeout;
 
138
  timeout = g_slice_new(InfIoTimeout);
88
139
 
89
140
  timeout->io = io;
90
141
  timeout->id = 0;
95
146
}
96
147
 
97
148
static void
98
 
inf_gtk_io_timeout_free(InfGtkIoTimeout* timeout)
 
149
inf_gtk_io_timeout_free(InfIoTimeout* timeout)
99
150
{
100
 
  if(timeout->id != 0)
101
 
    g_source_remove(timeout->id);
102
151
  if(timeout->notify)
103
152
    timeout->notify(timeout->user_data);
104
153
 
105
 
  g_slice_free(InfGtkIoTimeout, timeout);
106
 
}
107
 
 
108
 
static InfGtkIoWatch*
 
154
  g_slice_free(InfIoTimeout, timeout);
 
155
}
 
156
 
 
157
static InfIoDispatch*
 
158
inf_gtk_io_dispatch_new(InfGtkIo* io,
 
159
                        InfIoDispatchFunc func,
 
160
                        gpointer user_data,
 
161
                        GDestroyNotify notify)
 
162
{
 
163
  InfIoDispatch* dispatch;
 
164
  dispatch = g_slice_new(InfIoDispatch);
 
165
 
 
166
  dispatch->io = io;
 
167
  dispatch->id = 0;
 
168
  dispatch->func = func;
 
169
  dispatch->user_data = user_data;
 
170
  dispatch->notify = notify;
 
171
  return dispatch;
 
172
}
 
173
 
 
174
static void
 
175
inf_gtk_io_dispatch_free(InfIoDispatch* dispatch)
 
176
{
 
177
  if(dispatch->notify)
 
178
    dispatch->notify(dispatch->user_data);
 
179
 
 
180
  g_slice_free(InfIoDispatch, dispatch);
 
181
}
 
182
 
 
183
static InfIoWatch*
109
184
inf_gtk_io_watch_lookup(InfGtkIo* io,
110
185
                        InfNativeSocket* socket)
111
186
{
115
190
  priv = INF_GTK_IO_PRIVATE(io);
116
191
 
117
192
  for(item = priv->watches; item != NULL; item = g_slist_next(item))
118
 
    if( ((InfGtkIoWatch*)item->data)->socket == socket)
119
 
      return (InfGtkIoWatch*)item->data;
 
193
    if( ((InfIoWatch*)item->data)->socket == socket)
 
194
      return (InfIoWatch*)item->data;
120
195
 
121
196
  return NULL;
122
197
}
131
206
  io = INF_GTK_IO(instance);
132
207
  priv = INF_GTK_IO_PRIVATE(io);
133
208
 
 
209
  priv->mutex = g_mutex_new();
 
210
  priv->mutexref = g_malloc(sizeof(int));
 
211
  *priv->mutexref = 1;
 
212
 
134
213
  priv->watches = NULL;
135
214
  priv->timeouts = NULL;
 
215
  priv->dispatchs = NULL;
136
216
}
137
217
 
138
218
static void
141
221
  InfGtkIo* io;
142
222
  InfGtkIoPrivate* priv;
143
223
  GSList* item;
 
224
  int mutexref;
144
225
 
145
226
  io = INF_GTK_IO(object);
146
227
  priv = INF_GTK_IO_PRIVATE(io);
147
228
 
 
229
  g_mutex_lock(priv->mutex);
 
230
 
148
231
  for(item = priv->watches; item != NULL; item = g_slist_next(item))
149
 
    inf_gtk_io_watch_free((InfGtkIoWatch*)item->data);
 
232
  {
 
233
    /* We have a stack-ref on the InfGtkIo when exeucting the callback */
 
234
    g_assert( ((InfIoWatch*)item->data)->executing == FALSE);
 
235
 
 
236
    if( ((InfIoWatch*)item->data)->id != 0)
 
237
      g_source_remove( ((InfIoWatch*)item->data)->id);
 
238
    inf_gtk_io_watch_free((InfIoWatch*)item->data);
 
239
  }
150
240
  g_slist_free(priv->watches);
151
241
 
152
242
  for(item = priv->timeouts; item != NULL; item = g_slist_next(item))
153
 
    inf_gtk_io_timeout_free((InfGtkIoTimeout*)item->data);
 
243
  {
 
244
    if( ((InfIoTimeout*)item->data)->id != 0)
 
245
      g_source_remove( ((InfIoTimeout*)item->data)->id);
 
246
    inf_gtk_io_timeout_free((InfIoTimeout*)item->data);
 
247
  }
154
248
  g_slist_free(priv->timeouts);
155
249
 
 
250
  for(item = priv->dispatchs; item != NULL; item = g_slist_next(item))
 
251
  {
 
252
    if( ((InfIoDispatch*)item->data)->id != 0)
 
253
      g_source_remove( ((InfIoDispatch*)item->data)->id);
 
254
    inf_gtk_io_dispatch_free((InfIoDispatch*)item->data);
 
255
  }
 
256
  g_slist_free(priv->dispatchs);
 
257
  g_mutex_unlock(priv->mutex);
 
258
 
 
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))
 
265
  {
 
266
    g_mutex_free(priv->mutex);
 
267
    g_free(priv->mutexref);
 
268
  }
 
269
 
156
270
  G_OBJECT_CLASS(parent_class)->finalize(object);
157
271
}
158
272
 
193
307
                      GIOCondition condition,
194
308
                      gpointer user_data)
195
309
{
196
 
  InfGtkIoWatch* watch;
197
 
  watch = (InfGtkIoWatch*)user_data;
198
 
 
199
 
  watch->func(
200
 
    watch->socket,
201
 
    inf_gtk_io_inf_events_from_glib_events(condition),
202
 
    watch->user_data
203
 
  );
 
310
  InfGtkIoUserdata* userdata;
 
311
  InfIoWatch* watch;
 
312
  InfGtkIoPrivate* priv;
 
313
 
 
314
  userdata = (InfGtkIoUserdata*)user_data;
 
315
  g_mutex_lock(userdata->mutex);
 
316
  if(!g_source_is_destroyed(g_main_current_source()))
 
317
  {
 
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;
 
321
 
 
322
    g_object_ref(watch->io);
 
323
    priv = INF_GTK_IO_PRIVATE(watch->io);
 
324
 
 
325
    g_assert(*priv->mutexref > 1); /* Both InfGtkIo and we have a reference */
 
326
    g_assert(g_slist_find(priv->watches, watch) != NULL);
 
327
 
 
328
    watch->executing = TRUE;
 
329
    g_mutex_unlock(userdata->mutex);
 
330
 
 
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. */
 
333
 
 
334
    watch->func(
 
335
      watch->socket,
 
336
      inf_gtk_io_inf_events_from_glib_events(condition),
 
337
      watch->user_data
 
338
    );
 
339
 
 
340
    g_mutex_lock(userdata->mutex);
 
341
    watch->executing = FALSE;
 
342
    g_object_unref(watch->io);
 
343
 
 
344
    if(watch->disposed == TRUE)
 
345
    {
 
346
      g_mutex_unlock(userdata->mutex);
 
347
      inf_gtk_io_watch_free(watch);
 
348
    }
 
349
    else
 
350
    {
 
351
      g_mutex_unlock(userdata->mutex);
 
352
    }
 
353
  }
 
354
  else
 
355
  {
 
356
    g_mutex_unlock(userdata->mutex);
 
357
  }
204
358
 
205
359
  return TRUE;
206
360
}
208
362
static gboolean
209
363
inf_gtk_io_timeout_func(gpointer user_data)
210
364
{
211
 
  InfGtkIoTimeout* timeout;
212
 
  InfGtkIoPrivate* priv;
213
 
 
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 */
217
 
 
218
 
  priv->timeouts = g_slist_remove(priv->timeouts, timeout); 
219
 
 
220
 
  timeout->func(timeout->user_data);
221
 
  inf_gtk_io_timeout_free(timeout);
222
 
  return FALSE;
223
 
}
224
 
 
225
 
static void
226
 
inf_gtk_io_io_watch(InfIo* io,
227
 
                    InfNativeSocket* socket,
228
 
                    InfIoEvent events,
229
 
                    InfIoFunc func,
230
 
                    gpointer user_data,
231
 
                    GDestroyNotify notify)
232
 
{
233
 
  InfGtkIoPrivate* priv;
234
 
  InfGtkIoWatch* watch;
 
365
  InfIoTimeout* timeout;
 
366
  InfGtkIoPrivate* priv;
 
367
  InfGtkIoUserdata* userdata;
 
368
 
 
369
  userdata = (InfGtkIoUserdata*)user_data;
 
370
  g_mutex_lock(userdata->mutex);
 
371
  if(!g_source_is_destroyed(g_main_current_source()))
 
372
  {
 
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);
 
377
 
 
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);
 
382
 
 
383
    timeout->func(timeout->user_data);
 
384
    inf_gtk_io_timeout_free(timeout);
 
385
  }
 
386
  else
 
387
  {
 
388
    g_mutex_unlock(userdata->mutex);
 
389
  }
 
390
 
 
391
  return FALSE;
 
392
}
 
393
 
 
394
static gboolean
 
395
inf_gtk_io_dispatch_func(gpointer user_data)
 
396
{
 
397
  InfIoDispatch* dispatch;
 
398
  InfGtkIoPrivate* priv;
 
399
  InfGtkIoUserdata* userdata;
 
400
 
 
401
  userdata = (InfGtkIoUserdata*)user_data;
 
402
  g_mutex_lock(userdata->mutex);
 
403
  if(!g_source_is_destroyed(g_main_current_source()))
 
404
  {
 
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);
 
409
 
 
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);
 
414
 
 
415
    dispatch->func(dispatch->user_data);
 
416
    inf_gtk_io_dispatch_free(dispatch);
 
417
  }
 
418
  else
 
419
  {
 
420
    g_mutex_unlock(userdata->mutex);
 
421
  }
 
422
 
 
423
  return FALSE;
 
424
}
 
425
 
 
426
static InfIoWatch*
 
427
inf_gtk_io_io_add_watch(InfIo* io,
 
428
                        InfNativeSocket* socket,
 
429
                        InfIoEvent events,
 
430
                        InfIoWatchFunc func,
 
431
                        gpointer user_data,
 
432
                        GDestroyNotify notify)
 
433
{
 
434
  InfGtkIoPrivate* priv;
 
435
  InfIoWatch* watch;
 
436
  InfGtkIoUserdata* data;
235
437
  GIOChannel* channel;
236
438
 
237
439
  priv = INF_GTK_IO_PRIVATE(io);
 
440
 
 
441
  g_mutex_lock(priv->mutex);
238
442
  watch = inf_gtk_io_watch_lookup(INF_GTK_IO(io), socket);
239
 
 
240
 
  if(watch == NULL)
241
 
  {
242
 
    if(events != 0)
243
 
    {
244
 
      watch = inf_gtk_io_watch_new(socket, func, user_data, notify);
245
 
      priv->watches = g_slist_prepend(priv->watches, watch);
246
 
    }
 
443
  if(watch != NULL)
 
444
  {
 
445
    g_mutex_unlock(priv->mutex);
 
446
    return NULL;
 
447
  }
 
448
 
 
449
  watch = inf_gtk_io_watch_new(
 
450
    INF_GTK_IO(io),
 
451
    socket,
 
452
    func,
 
453
    user_data,
 
454
    notify
 
455
  );
 
456
 
 
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);
 
462
 
 
463
#ifdef G_OS_WIN32
 
464
  channel = g_io_channel_win32_new_socket(*socket);
 
465
#else
 
466
  channel = g_io_channel_unix_new(*socket);
 
467
#endif
 
468
 
 
469
  watch->id = g_io_add_watch_full(
 
470
    channel,
 
471
    G_PRIORITY_DEFAULT,
 
472
    inf_gtk_io_inf_events_to_glib_events(events),
 
473
    inf_gtk_io_watch_func,
 
474
    data,
 
475
    inf_gtk_io_userdata_free
 
476
  );
 
477
 
 
478
  g_io_channel_unref(channel);
 
479
 
 
480
  priv->watches = g_slist_prepend(priv->watches, watch);
 
481
  g_mutex_unlock(priv->mutex);
 
482
 
 
483
  return watch;
 
484
}
 
485
 
 
486
static void
 
487
inf_gtk_io_io_update_watch(InfIo* io,
 
488
                           InfIoWatch* watch,
 
489
                           InfIoEvent events)
 
490
{
 
491
  InfGtkIoPrivate* priv;
 
492
  InfGtkIoUserdata* data;
 
493
  GIOChannel* channel;
 
494
 
 
495
  priv = INF_GTK_IO_PRIVATE(io);
 
496
  g_mutex_lock(priv->mutex);
 
497
 
 
498
  g_assert(g_slist_find(priv->watches, watch) != NULL);
 
499
 
 
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);
 
506
 
 
507
  g_source_remove(watch->id);
 
508
 
 
509
#ifdef G_OS_WIN32
 
510
  channel = g_io_channel_win32_new_socket(*watch->socket);
 
511
#else
 
512
  channel = g_io_channel_unix_new(*watch->socket);
 
513
#endif
 
514
 
 
515
  watch->id = g_io_add_watch_full(
 
516
    channel,
 
517
    G_PRIORITY_DEFAULT,
 
518
    inf_gtk_io_inf_events_to_glib_events(events),
 
519
    inf_gtk_io_watch_func,
 
520
    data,
 
521
    inf_gtk_io_userdata_free
 
522
  );
 
523
 
 
524
  g_io_channel_unref(channel);
 
525
}
 
526
 
 
527
static void
 
528
inf_gtk_io_io_remove_watch(InfIo* io,
 
529
                           InfIoWatch* watch)
 
530
{
 
531
  InfGtkIoPrivate* priv;
 
532
 
 
533
  priv = INF_GTK_IO_PRIVATE(io);
 
534
  g_mutex_lock(priv->mutex);
 
535
 
 
536
  g_assert(g_slist_find(priv->watches, watch) != NULL);
 
537
  priv->watches = g_slist_remove(priv->watches, watch);
 
538
 
 
539
  if(watch->executing)
 
540
  {
 
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);
247
548
  }
248
549
  else
249
550
  {
250
 
    if(events != 0)
251
 
    {
252
 
      g_source_remove(watch->id);
253
 
      watch->func = func;
254
 
      watch->user_data = user_data;
255
 
    }
256
 
    else
257
 
    {
258
 
      inf_gtk_io_watch_free(watch);
259
 
      priv->watches = g_slist_remove(priv->watches, watch);
260
 
    }
261
 
  }
262
 
 
263
 
  if(events != 0)
264
 
  {
265
 
    channel = g_io_channel_unix_new(*socket);
266
 
 
267
 
    watch->id = g_io_add_watch(
268
 
      channel,
269
 
      inf_gtk_io_inf_events_to_glib_events(events),
270
 
      inf_gtk_io_watch_func,
271
 
      watch
272
 
    );
273
 
 
274
 
    g_io_channel_unref(channel);
275
 
  }
 
551
    g_mutex_unlock(priv->mutex);
 
552
    inf_gtk_io_watch_free(watch);
 
553
  }
 
554
 
 
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);
276
559
}
277
560
 
278
 
static gpointer
 
561
static InfIoTimeout*
279
562
inf_gtk_io_io_add_timeout(InfIo* io,
280
563
                          guint msecs,
281
564
                          InfIoTimeoutFunc func,
283
566
                          GDestroyNotify notify)
284
567
{
285
568
  InfGtkIoPrivate* priv;
286
 
  InfGtkIoTimeout* timeout;
 
569
  InfIoTimeout* timeout;
 
570
  InfGtkIoUserdata* data;
287
571
 
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);
 
574
 
 
575
  data = g_slice_new(InfGtkIoUserdata);
 
576
  data->shared.timeout = timeout;
 
577
  data->mutex = priv->mutex;
 
578
  data->mutexref = priv->mutexref;
 
579
 
 
580
  g_mutex_lock(priv->mutex);
 
581
  g_atomic_int_inc(data->mutexref);
 
582
 
 
583
  timeout->id = g_timeout_add_full(
 
584
    G_PRIORITY_DEFAULT,
 
585
    msecs,
 
586
    inf_gtk_io_timeout_func,
 
587
    data,
 
588
    inf_gtk_io_userdata_free
 
589
  );
 
590
 
291
591
  priv->timeouts = g_slist_prepend(priv->timeouts, timeout);
 
592
  g_mutex_unlock(priv->mutex);
292
593
 
293
594
  return timeout;
294
595
}
295
596
 
296
597
static void
297
598
inf_gtk_io_io_remove_timeout(InfIo* io,
298
 
                             gpointer timeout_handle)
 
599
                             InfIoTimeout* timeout)
299
600
{
300
601
  InfGtkIoPrivate* priv;
301
 
  InfGtkIoTimeout* timeout;
302
602
 
303
603
  priv = INF_GTK_IO_PRIVATE(io);
304
 
  timeout = (InfGtkIoTimeout*)timeout_handle;
 
604
 
 
605
  g_mutex_lock(priv->mutex);
305
606
  g_assert(g_slist_find(priv->timeouts, timeout) != NULL);
306
 
 
307
607
  priv->timeouts = g_slist_remove(priv->timeouts, timeout);
 
608
  g_mutex_unlock(priv->mutex);
 
609
 
 
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);
308
614
 
309
615
  inf_gtk_io_timeout_free(timeout);
310
616
}
311
617
 
 
618
static InfIoDispatch*
 
619
inf_gtk_io_io_add_dispatch(InfIo* io,
 
620
                           InfIoDispatchFunc func,
 
621
                           gpointer user_data,
 
622
                           GDestroyNotify notify)
 
623
{
 
624
  InfGtkIoPrivate* priv;
 
625
  InfIoDispatch* dispatch;
 
626
  InfGtkIoUserdata* data;
 
627
 
 
628
  priv = INF_GTK_IO_PRIVATE(io);
 
629
  dispatch = inf_gtk_io_dispatch_new(INF_GTK_IO(io), func, user_data, notify);
 
630
 
 
631
  data = g_slice_new(InfGtkIoUserdata);
 
632
  data->shared.dispatch = dispatch;
 
633
  data->mutex = priv->mutex;
 
634
  data->mutexref = priv->mutexref;
 
635
 
 
636
  g_mutex_lock(priv->mutex);
 
637
  g_atomic_int_inc(data->mutexref);
 
638
 
 
639
  dispatch->id = g_idle_add_full(
 
640
    G_PRIORITY_DEFAULT_IDLE,
 
641
    inf_gtk_io_dispatch_func,
 
642
    data,
 
643
    inf_gtk_io_userdata_free
 
644
  );
 
645
 
 
646
  priv->dispatchs = g_slist_prepend(priv->dispatchs, dispatch);
 
647
  g_mutex_unlock(priv->mutex);
 
648
 
 
649
  return dispatch;
 
650
}
 
651
 
 
652
static void
 
653
inf_gtk_io_io_remove_dispatch(InfIo* io,
 
654
                              InfIoDispatch* dispatch)
 
655
{
 
656
  InfGtkIoPrivate* priv;
 
657
 
 
658
  priv = INF_GTK_IO_PRIVATE(io);
 
659
 
 
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);
 
664
 
 
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);
 
669
 
 
670
  inf_gtk_io_dispatch_free(dispatch);
 
671
}
 
672
 
312
673
static void
313
674
inf_gtk_io_class_init(gpointer g_class,
314
675
                      gpointer class_data)
329
690
  InfIoIface* iface;
330
691
  iface = (InfIoIface*)g_iface;
331
692
 
332
 
  iface->watch = inf_gtk_io_io_watch;
 
693
  iface->add_watch = inf_gtk_io_io_add_watch;
 
694
  iface->update_watch = inf_gtk_io_io_update_watch;
 
695
  iface->remove_watch = inf_gtk_io_io_remove_watch;
333
696
  iface->add_timeout = inf_gtk_io_io_add_timeout;
334
697
  iface->remove_timeout = inf_gtk_io_io_remove_timeout;
 
698
  iface->add_dispatch = inf_gtk_io_io_add_dispatch;
 
699
  iface->remove_dispatch = inf_gtk_io_io_remove_dispatch;
335
700
}
336
701
 
337
702
GType