gmain.c 101 KB
Newer Older
1 2 3 4 5 6 7
/* GLIB - Library of useful routines for C programming
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * gmain.c: Main loop abstraction, timeouts, and idle functions
 * Copyright 1998 Owen Taylor
 *
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9 10 11 12 13 14
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18 19 20 21 22
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

23
/*
24
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
25 26 27 28 29
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
 */

30 31 32 33
/* 
 * MT safe
 */

34 35
#include "config.h"

36 37 38
/* uncomment the next line to get poll() debugging info */
/* #define G_MAIN_POLL_DEBUG */

39
#include "glib.h"
40
#include "gthreadprivate.h"
41
#include <signal.h>
42
#include <sys/types.h>
43
#include <time.h>
44
#include <stdlib.h>
45
#ifdef HAVE_SYS_TIME_H
46
#include <sys/time.h>
47 48
#endif /* HAVE_SYS_TIME_H */
#ifdef GLIB_HAVE_SYS_POLL_H
49 50 51
#  include <sys/poll.h>
#  undef events	 /* AIX 4.1.5 & 4.3.2 define this for SVR3,4 compatibility */
#  undef revents /* AIX 4.1.5 & 4.3.2 define this for SVR3,4 compatibility */
52 53 54 55 56 57 58 59

/* The poll() emulation on OS/X doesn't handle fds=NULL, nfds=0,
 * so we prefer our own poll emulation.
 */
#ifdef _POLL_EMUL_H_
#undef HAVE_POLL
#endif
   
60
#endif /* GLIB_HAVE_SYS_POLL_H */
61
#ifdef HAVE_UNISTD_H
62
#include <unistd.h>
63
#endif /* HAVE_UNISTD_H */
64
#include <errno.h>
65

66
#ifdef G_OS_WIN32
67 68
#define STRICT
#include <windows.h>
69
#endif /* G_OS_WIN32 */
70

71
#ifdef G_OS_BEOS
72 73
#include <sys/socket.h>
#include <sys/wait.h>
74
#endif /* G_OS_BEOS */
75

76 77 78 79
#ifdef G_OS_UNIX
#include <fcntl.h>
#include <sys/wait.h>
#endif
80 81 82

#include "galias.h"

83 84
/* Types */

85
typedef struct _GTimeoutSource GTimeoutSource;
86
typedef struct _GChildWatchSource GChildWatchSource;
87
typedef struct _GPollRec GPollRec;
88
typedef struct _GSourceCallback GSourceCallback;
89

90 91
typedef enum
{
92 93 94 95
  G_SOURCE_READY = 1 << G_HOOK_FLAG_USER_SHIFT,
  G_SOURCE_CAN_RECURSE = 1 << (G_HOOK_FLAG_USER_SHIFT + 1)
} GSourceFlags;

96 97 98 99 100 101 102 103 104 105
#ifdef G_THREADS_ENABLED
typedef struct _GMainWaiter GMainWaiter;

struct _GMainWaiter
{
  GCond *cond;
  GMutex *mutex;
};
#endif  

106 107 108 109 110
typedef struct _GMainDispatch GMainDispatch;

struct _GMainDispatch
{
  gint depth;
111
  GSList *source; /* stack of current sources */
112 113
};

114
struct _GMainContext
115
{
116 117 118 119
#ifdef G_THREADS_ENABLED
  /* The following lock is used for both the list of sources
   * and the list of poll records
   */
120 121 122 123 124
  GStaticMutex mutex;
  GCond *cond;
  GThread *owner;
  guint owner_count;
  GSList *waiters;
125 126
#endif  

127
  gint ref_count;
128

129 130 131 132 133 134 135 136 137 138
  GPtrArray *pending_dispatches;
  gint timeout;			/* Timeout for current iteration */

  guint next_id;
  GSource *source_list;
  gint in_check_or_prepare;

  GPollRec *poll_records;
  guint n_poll_records;
  GPollFD *cached_poll_array;
139
  guint cached_poll_array_size;
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

#ifdef G_THREADS_ENABLED  
#ifndef G_OS_WIN32
/* this pipe is used to wake up the main loop when a source is added.
 */
  gint wake_up_pipe[2];
#else /* G_OS_WIN32 */
  HANDLE wake_up_semaphore;
#endif /* G_OS_WIN32 */

  GPollFD wake_up_rec;
  gboolean poll_waiting;

/* Flag indicating whether the set of fd's changed during a poll */
  gboolean poll_changed;
#endif /* G_THREADS_ENABLED */

  GPollFunc poll_func;

  GTimeVal current_time;
  gboolean time_is_current;
};

struct _GSourceCallback
{
  guint ref_count;
  GSourceFunc func;
  gpointer    data;
  GDestroyNotify notify;
169 170
};

171 172
struct _GMainLoop
{
173
  GMainContext *context;
174
  gboolean is_running;
175
  gint ref_count;
176 177
};

178
struct _GTimeoutSource
179
{
180
  GSource     source;
181
  GTimeVal    expiration;
182
  guint       interval;
183
  guint	      granularity;
184 185
};

186 187 188 189 190
struct _GChildWatchSource
{
  GSource     source;
  GPid        pid;
  gint        child_status;
191 192 193
#ifdef G_OS_WIN32
  GPollFD     poll;
#else /* G_OS_WIN32 */
194 195
  gint        count;
  gboolean    child_exited;
196
#endif /* G_OS_WIN32 */
197 198
};

199 200
struct _GPollRec
{
201
  GPollFD *fd;
202
  GPollRec *next;
203
  gint priority;
204 205
};

206
#ifdef G_THREADS_ENABLED
207 208 209
#define LOCK_CONTEXT(context) g_static_mutex_lock (&context->mutex)
#define UNLOCK_CONTEXT(context) g_static_mutex_unlock (&context->mutex)
#define G_THREAD_SELF g_thread_self ()
210 211 212
#else
#define LOCK_CONTEXT(context) (void)0
#define UNLOCK_CONTEXT(context) (void)0
213
#define G_THREAD_SELF NULL
214 215 216
#endif

#define SOURCE_DESTROYED(source) (((source)->flags & G_HOOK_FLAG_ACTIVE) == 0)
217 218
#define SOURCE_BLOCKED(source) (((source)->flags & G_HOOK_FLAG_IN_CALL) != 0 && \
		                ((source)->flags & G_SOURCE_CAN_RECURSE) == 0)
219 220 221 222 223 224 225 226 227 228

#define SOURCE_UNREF(source, context)                       \
   G_STMT_START {                                           \
    if ((source)->ref_count > 1)                            \
      (source)->ref_count--;                                \
    else                                                    \
      g_source_unref_internal ((source), (context), TRUE);  \
   } G_STMT_END


229 230
/* Forward declarations */

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
static void g_source_unref_internal             (GSource      *source,
						 GMainContext *context,
						 gboolean      have_lock);
static void g_source_destroy_internal           (GSource      *source,
						 GMainContext *context,
						 gboolean      have_lock);
static void g_main_context_poll                 (GMainContext *context,
						 gint          timeout,
						 gint          priority,
						 GPollFD      *fds,
						 gint          n_fds);
static void g_main_context_add_poll_unlocked    (GMainContext *context,
						 gint          priority,
						 GPollFD      *fd);
static void g_main_context_remove_poll_unlocked (GMainContext *context,
						 GPollFD      *fd);
247
static void g_main_context_wakeup_unlocked      (GMainContext *context);
248 249 250 251 252 253 254

static gboolean g_timeout_prepare  (GSource     *source,
				    gint        *timeout);
static gboolean g_timeout_check    (GSource     *source);
static gboolean g_timeout_dispatch (GSource     *source,
				    GSourceFunc  callback,
				    gpointer     user_data);
255 256 257 258 259 260
static gboolean g_child_watch_prepare  (GSource     *source,
				        gint        *timeout);
static gboolean g_child_watch_check    (GSource     *source);
static gboolean g_child_watch_dispatch (GSource     *source,
					GSourceFunc  callback,
					gpointer     user_data);
261 262 263 264 265 266 267
static gboolean g_idle_prepare     (GSource     *source,
				    gint        *timeout);
static gboolean g_idle_check       (GSource     *source);
static gboolean g_idle_dispatch    (GSource     *source,
				    GSourceFunc  callback,
				    gpointer     user_data);

268
G_LOCK_DEFINE_STATIC (main_loop);
269
static GMainContext *default_main_context;
270
static GSList *main_contexts_without_pipe = NULL;
271

272
#ifndef G_OS_WIN32
273 274 275 276 277 278 279
/* Child status monitoring code */
enum {
  CHILD_WATCH_UNINITIALIZED,
  CHILD_WATCH_INITIALIZED_SINGLE,
  CHILD_WATCH_INITIALIZED_THREADED
};
static gint child_watch_init_state = CHILD_WATCH_UNINITIALIZED;
280
static gint child_watch_count = 1;
281
static gint child_watch_wake_up_pipe[2] = {0, 0};
282
#endif /* !G_OS_WIN32 */
283 284 285
G_LOCK_DEFINE_STATIC (main_context_list);
static GSList *main_context_list = NULL;

286 287
static gint timer_perturb = -1;

288
GSourceFuncs g_timeout_funcs =
289
{
290 291 292
  g_timeout_prepare,
  g_timeout_check,
  g_timeout_dispatch,
293
  NULL
294 295
};

296 297 298 299 300 301 302 303
GSourceFuncs g_child_watch_funcs =
{
  g_child_watch_prepare,
  g_child_watch_check,
  g_child_watch_dispatch,
  NULL
};

304
GSourceFuncs g_idle_funcs =
305
{
306 307 308
  g_idle_prepare,
  g_idle_check,
  g_idle_dispatch,
309
  NULL
310 311 312
};

#ifdef HAVE_POLL
313 314 315 316
/* SunOS has poll, but doesn't provide a prototype. */
#  if defined (sun) && !defined (__SVR4)
extern gint poll (GPollFD *ufds, guint nfsd, gint timeout);
#  endif  /* !sun */
317
#else	/* !HAVE_POLL */
318

319
#ifdef G_OS_WIN32
320 321

static gint
322 323 324
g_poll (GPollFD *fds,
	guint    nfds,
	gint     timeout)
325 326
{
  HANDLE handles[MAXIMUM_WAIT_OBJECTS];
327
  gboolean poll_msgs = FALSE;
328 329 330 331 332 333 334 335 336
  GPollFD *f;
  DWORD ready;
  MSG msg;
  UINT timer;
  gint nhandles = 0;

  for (f = fds; f < &fds[nfds]; ++f)
    if (f->fd >= 0)
      {
337 338
	if (f->fd == G_WIN32_MSG_HANDLE)
	  poll_msgs = TRUE;
339 340 341 342 343
	else if (nhandles == MAXIMUM_WAIT_OBJECTS)
	  {
	    g_warning (G_STRLOC ": Too many handles to wait for!\n");
	    break;
	  }
344
	else
345 346
	  {
#ifdef G_MAIN_POLL_DEBUG
347
	    g_print ("g_poll: waiting for %#x\n", f->fd);
348
#endif
349
	    handles[nhandles++] = (HANDLE) f->fd;
350
	  }
351 352 353 354 355
      }

  if (timeout == -1)
    timeout = INFINITE;

356
  if (poll_msgs)
357
    {
358 359 360
      /* Waiting for messages, and maybe events
       * -> First PeekMessage
       */
361
#ifdef G_MAIN_POLL_DEBUG
362
      g_print ("PeekMessage\n");
363
#endif
364 365 366 367 368
      if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
	ready = WAIT_OBJECT_0 + nhandles;
      else
	{
	  if (nhandles == 0)
369
	    {
370 371 372 373 374 375
	      /* Waiting just for messages */
	      if (timeout == INFINITE)
		{
		  /* Infinite timeout
		   * -> WaitMessage
		   */
376
#ifdef G_MAIN_POLL_DEBUG
377
		  g_print ("WaitMessage\n");
378
#endif
379
		  if (!WaitMessage ())
380 381 382 383 384
		    {
		      gchar *emsg = g_win32_error_message (GetLastError ());
		      g_warning (G_STRLOC ": WaitMessage() failed: %s", emsg);
		      g_free (emsg);
		    }
385 386 387 388 389 390 391 392 393
		  ready = WAIT_OBJECT_0 + nhandles;
		}
	      else if (timeout == 0)
		{
		  /* Waiting just for messages, zero timeout.
		   * If we got here, there was no message
		   */
		  ready = WAIT_TIMEOUT;
		}
394
	      else
395 396 397 398 399
		{
		  /* Waiting just for messages, some timeout
		   * -> Set a timer, wait for message,
		   * kill timer, use PeekMessage
		   */
400 401
		  timer = SetTimer (NULL, 0, timeout, NULL);
		  if (timer == 0)
402
		    {
403 404 405
		      gchar *emsg = g_win32_error_message (GetLastError ());
		      g_warning (G_STRLOC ": SetTimer() failed: %s", emsg);
		      g_free (emsg);
406 407
		      ready = WAIT_TIMEOUT;
		    }
408 409
		  else
		    {
410
#ifdef G_MAIN_POLL_DEBUG
411
		      g_print ("WaitMessage\n");
412
#endif
413 414
		      WaitMessage ();
		      KillTimer (NULL, timer);
415
#ifdef G_MAIN_POLL_DEBUG
416
		      g_print ("PeekMessage\n");
417
#endif
418 419 420 421 422 423
		      if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)
			  && msg.message != WM_TIMER)
			ready = WAIT_OBJECT_0;
		      else
			ready = WAIT_TIMEOUT;
		    }
424 425
		}
	    }
426 427 428 429 430
	  else
	    {
	      /* Wait for either message or event
	       * -> Use MsgWaitForMultipleObjects
	       */
431
#ifdef G_MAIN_POLL_DEBUG
432
	      g_print ("MsgWaitForMultipleObjects(%d, %d)\n", nhandles, timeout);
433
#endif
434 435
	      ready = MsgWaitForMultipleObjects (nhandles, handles, FALSE,
						 timeout, QS_ALLINPUT);
436

437
	      if (ready == WAIT_FAILED)
438 439 440 441 442
		{
		  gchar *emsg = g_win32_error_message (GetLastError ());
		  g_warning (G_STRLOC ": MsgWaitForMultipleObjects() failed: %s", emsg);
		  g_free (emsg);
		}
443
	    }
444 445 446 447 448 449 450 451 452 453 454 455
	}
    }
  else if (nhandles == 0)
    {
      /* Wait for nothing (huh?) */
      return 0;
    }
  else
    {
      /* Wait for just events
       * -> Use WaitForMultipleObjects
       */
456 457 458
#ifdef G_MAIN_POLL_DEBUG
      g_print ("WaitForMultipleObjects(%d, %d)\n", nhandles, timeout);
#endif
459 460
      ready = WaitForMultipleObjects (nhandles, handles, FALSE, timeout);
      if (ready == WAIT_FAILED)
461 462 463 464 465
	{
	  gchar *emsg = g_win32_error_message (GetLastError ());
	  g_warning (G_STRLOC ": WaitForMultipleObjects() failed: %s", emsg);
	  g_free (emsg);
	}
466 467
    }

468
#ifdef G_MAIN_POLL_DEBUG
469
  g_print ("wait returns %ld%s\n",
470 471 472 473 474
	   ready,
	   (ready == WAIT_FAILED ? " (WAIT_FAILED)" :
	    (ready == WAIT_TIMEOUT ? " (WAIT_TIMEOUT)" :
	     (poll_msgs && ready == WAIT_OBJECT_0 + nhandles ? " (msg)" : ""))));
#endif
475 476 477 478 479
  for (f = fds; f < &fds[nfds]; ++f)
    f->revents = 0;

  if (ready == WAIT_FAILED)
    return -1;
480 481 482
  else if (ready == WAIT_TIMEOUT)
    return 0;
  else if (poll_msgs && ready == WAIT_OBJECT_0 + nhandles)
483
    {
484 485 486 487 488 489 490
      for (f = fds; f < &fds[nfds]; ++f)
	if (f->fd >= 0)
	  {
	    if (f->events & G_IO_IN)
	      if (f->fd == G_WIN32_MSG_HANDLE)
		f->revents |= G_IO_IN;
	  }
491 492 493 494
    }
  else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles)
    for (f = fds; f < &fds[nfds]; ++f)
      {
495
	if (f->fd == (gint) handles[ready - WAIT_OBJECT_0])
496
	  {
497
	    f->revents = f->events;
498 499 500
#ifdef G_MAIN_POLL_DEBUG
	    g_print ("g_poll: got event %#x\n", f->fd);
#endif
501 502 503
	  }
      }
    
504
  return 1;
505 506
}

507
#else  /* !G_OS_WIN32 */
508 509 510 511 512

/* The following implementation of poll() comes from the GNU C Library.
 * Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
 */

Manish Singh's avatar
Manish Singh committed
513 514
#include <string.h> /* for bzero on BSD systems */

515 516
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
517
#endif /* HAVE_SYS_SELECT_H */
518

519
#ifdef G_OS_BEOS
520
#undef NO_FD_SET
521
#endif /* G_OS_BEOS */
522

523 524
#ifndef NO_FD_SET
#  define SELECT_MASK fd_set
525
#else /* !NO_FD_SET */
526 527 528
#  ifndef _AIX
typedef long fd_mask;
#  endif /* _AIX */
529
#  ifdef _IBMR2
530
#    define SELECT_MASK void
531
#  else /* !_IBMR2 */
532
#    define SELECT_MASK int
533 534
#  endif /* !_IBMR2 */
#endif /* !NO_FD_SET */
535 536

static gint 
537 538 539
g_poll (GPollFD *fds,
	guint    nfds,
	gint     timeout)
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
{
  struct timeval tv;
  SELECT_MASK rset, wset, xset;
  GPollFD *f;
  int ready;
  int maxfd = 0;

  FD_ZERO (&rset);
  FD_ZERO (&wset);
  FD_ZERO (&xset);

  for (f = fds; f < &fds[nfds]; ++f)
    if (f->fd >= 0)
      {
	if (f->events & G_IO_IN)
	  FD_SET (f->fd, &rset);
	if (f->events & G_IO_OUT)
	  FD_SET (f->fd, &wset);
	if (f->events & G_IO_PRI)
	  FD_SET (f->fd, &xset);
Manish Singh's avatar
Manish Singh committed
560
	if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI)))
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
	  maxfd = f->fd;
      }

  tv.tv_sec = timeout / 1000;
  tv.tv_usec = (timeout % 1000) * 1000;

  ready = select (maxfd + 1, &rset, &wset, &xset,
		  timeout == -1 ? NULL : &tv);
  if (ready > 0)
    for (f = fds; f < &fds[nfds]; ++f)
      {
	f->revents = 0;
	if (f->fd >= 0)
	  {
	    if (FD_ISSET (f->fd, &rset))
	      f->revents |= G_IO_IN;
	    if (FD_ISSET (f->fd, &wset))
	      f->revents |= G_IO_OUT;
	    if (FD_ISSET (f->fd, &xset))
	      f->revents |= G_IO_PRI;
	  }
      }

  return ready;
}
586

587
#endif /* !G_OS_WIN32 */
588

589
#endif	/* !HAVE_POLL */
590

591 592
/**
 * g_main_context_ref:
Owen Taylor's avatar
Owen Taylor committed
593
 * @context: a #GMainContext
594 595
 * 
 * Increases the reference count on a #GMainContext object by one.
596 597
 *
 * Returns: the @context that was passed in (since 2.6)
598
 **/
599
GMainContext *
600
g_main_context_ref (GMainContext *context)
601
{
602 603
  g_return_val_if_fail (context != NULL, NULL);
  g_return_val_if_fail (g_atomic_int_get (&context->ref_count) > 0, NULL); 
604

605
  g_atomic_int_inc (&context->ref_count);
606 607

  return context;
608 609
}

610
static inline void
611 612 613
poll_rec_list_free (GMainContext *context,
		    GPollRec     *list)
{
614
  g_slice_free_chain (GPollRec, list, next);
615 616
}

617 618 619 620 621 622 623 624 625
/**
 * g_main_context_unref:
 * @context: a #GMainContext
 * 
 * Decreases the reference count on a #GMainContext object by one. If
 * the result is zero, free the context and free all associated memory.
 **/
void
g_main_context_unref (GMainContext *context)
626 627
{
  GSource *source;
628 629
  g_return_if_fail (context != NULL);
  g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0); 
630

631 632
  if (!g_atomic_int_dec_and_test (&context->ref_count))
    return;
633

634 635 636 637
  G_LOCK (main_context_list);
  main_context_list = g_slist_remove (main_context_list, context);
  G_UNLOCK (main_context_list);

638 639 640 641
  source = context->source_list;
  while (source)
    {
      GSource *next = source->next;
642
      g_source_destroy_internal (source, context, FALSE);
643 644
      source = next;
    }
645

646
#ifdef G_THREADS_ENABLED  
647
  g_static_mutex_free (&context->mutex);
648
#endif
649

650 651
  g_ptr_array_free (context->pending_dispatches, TRUE);
  g_free (context->cached_poll_array);
652 653 654

  poll_rec_list_free (context, context->poll_records);
  
655
#ifdef G_THREADS_ENABLED
656 657 658 659 660 661 662 663
  if (g_thread_supported())
    {
#ifndef G_OS_WIN32
      close (context->wake_up_pipe[0]);
      close (context->wake_up_pipe[1]);
#else
      CloseHandle (context->wake_up_semaphore);
#endif
664 665 666 667
    } 
  else
    main_contexts_without_pipe = g_slist_remove (main_contexts_without_pipe, 
						 context);
668
#endif
669 670
  
  g_free (context);
671 672
}

673 674 675 676
#ifdef G_THREADS_ENABLED
static void 
g_main_context_init_pipe (GMainContext *context)
{
677
# ifndef G_OS_WIN32
678 679
  if (context->wake_up_pipe[0] != -1)
    return;
680 681 682 683 684 685 686
  if (pipe (context->wake_up_pipe) < 0)
    g_error ("Cannot create pipe main loop wake-up: %s\n",
	     g_strerror (errno));
  
  context->wake_up_rec.fd = context->wake_up_pipe[0];
  context->wake_up_rec.events = G_IO_IN;
# else
687 688
  if (context->wake_up_semaphore != NULL)
    return;
689 690 691 692 693 694 695 696 697 698 699 700 701 702
  context->wake_up_semaphore = CreateSemaphore (NULL, 0, 100, NULL);
  if (context->wake_up_semaphore == NULL)
    g_error ("Cannot create wake-up semaphore: %s",
	     g_win32_error_message (GetLastError ()));
  context->wake_up_rec.fd = (gint) context->wake_up_semaphore;
  context->wake_up_rec.events = G_IO_IN;
#  ifdef G_MAIN_POLL_DEBUG
  g_print ("wake-up semaphore: %#x\n", (guint) context->wake_up_semaphore);
#  endif
# endif
  g_main_context_add_poll_unlocked (context, 0, &context->wake_up_rec);
}

void
703
_g_main_thread_init (void)
704 705 706 707 708 709 710 711 712 713 714 715
{
  GSList *curr = main_contexts_without_pipe;
  while (curr)
    {
      g_main_context_init_pipe ((GMainContext *)curr->data);
      curr = curr->next;
    }
  g_slist_free (main_contexts_without_pipe);
  main_contexts_without_pipe = NULL;  
}
#endif /* G_THREADS_ENABLED */

716
/**
717
 * g_main_context_new:
718
 * 
719
 * Creates a new #GMainContext strcuture
720
 * 
721
 * Return value: the new #GMainContext
722 723
 **/
GMainContext *
724
g_main_context_new (void)
725
{
726
  GMainContext *context = g_new0 (GMainContext, 1);
Owen Taylor's avatar
Owen Taylor committed
727 728

#ifdef G_THREADS_ENABLED
729
  g_static_mutex_init (&context->mutex);
Owen Taylor's avatar
Owen Taylor committed
730

731 732
  context->owner = NULL;
  context->waiters = NULL;
733

734
# ifndef G_OS_WIN32
735 736
  context->wake_up_pipe[0] = -1;
  context->wake_up_pipe[1] = -1;
737 738 739
# else
  context->wake_up_semaphore = NULL;
# endif
740
#endif
741

742 743
  context->ref_count = 1;

744 745 746 747
  context->next_id = 1;
  
  context->source_list = NULL;
  
748
#if HAVE_POLL
749
  context->poll_func = (GPollFunc)poll;
750
#else
751
  context->poll_func = g_poll;
752
#endif
753 754 755 756 757 758 759 760
  
  context->cached_poll_array = NULL;
  context->cached_poll_array_size = 0;
  
  context->pending_dispatches = g_ptr_array_new ();
  
  context->time_is_current = FALSE;
  
761
#ifdef G_THREADS_ENABLED
762 763 764 765 766
  if (g_thread_supported ())
    g_main_context_init_pipe (context);
  else
    main_contexts_without_pipe = g_slist_prepend (main_contexts_without_pipe, 
						  context);
767 768
#endif

769 770 771 772
  G_LOCK (main_context_list);
  main_context_list = g_slist_append (main_context_list, context);
  G_UNLOCK (main_context_list);

773
  return context;
774 775
}

776 777 778
/**
 * g_main_context_default:
 * 
Matthias Clasen's avatar
Matthias Clasen committed
779
 * Returns the default main context. This is the main context used
780 781 782 783 784 785 786
 * for main loop functions when a main loop is not explicitly
 * specified.
 * 
 * Return value: the default main context.
 **/
GMainContext *
g_main_context_default (void)
787
{
788 789
  /* Slow, but safe */
  
790
  G_LOCK (main_loop);
791

792
  if (!default_main_context)
793
    default_main_context = g_main_context_new ();
794

795
  G_UNLOCK (main_loop);
796

797
  return default_main_context;
798 799
}

800 801 802 803 804 805
/* Hooks for adding to the main loop */

/**
 * g_source_new:
 * @source_funcs: structure containing functions that implement
 *                the sources behavior.
Matthias Clasen's avatar
Matthias Clasen committed
806
 * @struct_size: size of the #GSource structure to create.
807
 * 
Matthias Clasen's avatar
Matthias Clasen committed
808 809
 * Creates a new #GSource structure. The size is specified to
 * allow creating structures derived from #GSource that contain
810
 * additional data. The size passed in must be at least
Matthias Clasen's avatar
Matthias Clasen committed
811
 * <literal>sizeof (GSource)</literal>.
812 813
 * 
 * The source will not initially be associated with any #GMainContext
814
 * and must be added to one with g_source_attach() before it will be
815 816
 * executed.
 * 
Matthias Clasen's avatar
Matthias Clasen committed
817
 * Return value: the newly-created #GSource.
818 819 820 821
 **/
GSource *
g_source_new (GSourceFuncs *source_funcs,
	      guint         struct_size)
822
{
823 824 825 826
  GSource *source;

  g_return_val_if_fail (source_funcs != NULL, NULL);
  g_return_val_if_fail (struct_size >= sizeof (GSource), NULL);
827
  
828 829 830 831
  source = (GSource*) g_malloc0 (struct_size);

  source->source_funcs = source_funcs;
  source->ref_count = 1;
832
  
833
  source->priority = G_PRIORITY_DEFAULT;
834

835
  source->flags = G_HOOK_FLAG_ACTIVE;
836

837 838 839
  /* NULL/0 initialization for all other fields */
  
  return source;
840 841
}

842 843 844 845 846
/* Holds context's lock
 */
static void
g_source_list_add (GSource      *source,
		   GMainContext *context)
847
{
848 849 850 851 852 853 854 855 856
  GSource *tmp_source, *last_source;
  
  last_source = NULL;
  tmp_source = context->source_list;
  while (tmp_source && tmp_source->priority <= source->priority)
    {
      last_source = tmp_source;
      tmp_source = tmp_source->next;
    }
857

858 859 860 861 862 863 864 865 866
  source->next = tmp_source;
  if (tmp_source)
    tmp_source->prev = source;
  
  source->prev = last_source;
  if (last_source)
    last_source->next = source;
  else
    context->source_list = source;
867 868
}

869 870 871 872 873
/* Holds context's lock
 */
static void
g_source_list_remove (GSource      *source,
		      GMainContext *context)
874
{
875 876 877 878
  if (source->prev)
    source->prev->next = source->next;
  else
    context->source_list = source->next;
879

880 881
  if (source->next)
    source->next->prev = source->prev;
882

883 884
  source->prev = NULL;
  source->next = NULL;
885 886
}

887 888 889 890 891 892 893 894
/**
 * g_source_attach:
 * @source: a #GSource
 * @context: a #GMainContext (if %NULL, the default context will be used)
 * 
 * Adds a #GSource to a @context so that it will be executed within
 * that context.
 *
895 896
 * Return value: the ID (greater than 0) for the source within the 
 *   #GMainContext. 
897 898 899 900
 **/
guint
g_source_attach (GSource      *source,
		 GMainContext *context)
901
{
902 903
  guint result = 0;
  GSList *tmp_list;
904

905 906 907 908 909
  g_return_val_if_fail (source->context == NULL, 0);
  g_return_val_if_fail (!SOURCE_DESTROYED (source), 0);
  
  if (!context)
    context = g_main_context_default ();
910

911
  LOCK_CONTEXT (context);
912

913
  source->context = context;
914
  result = source->source_id = context->next_id++;
915

Owen Taylor's avatar
Owen Taylor committed
916
  source->ref_count++;
917
  g_source_list_add (source, context);
918

919 920 921 922 923 924
  tmp_list = source->poll_fds;
  while (tmp_list)
    {
      g_main_context_add_poll_unlocked (context, source->priority, tmp_list->data);
      tmp_list = tmp_list->next;
    }
925

926 927
#ifdef G_THREADS_ENABLED
  /* Now wake up the main loop if it is waiting in the poll() */
928
  g_main_context_wakeup_unlocked (context);
929
#endif
930

931
  UNLOCK_CONTEXT (context);
932

933
  return result;
934 935
}

936 937 938 939
static void
g_source_destroy_internal (GSource      *source,
			   GMainContext *context,
			   gboolean      have_lock)
940
{
941 942 943 944 945
  if (!have_lock)
    LOCK_CONTEXT (context);
  
  if (!SOURCE_DESTROYED (source))
    {
946
      GSList *tmp_list;
947 948 949 950
      gpointer old_cb_data;
      GSourceCallbackFuncs *old_cb_funcs;
      
      source->flags &= ~G_HOOK_FLAG_ACTIVE;
951

952 953
      old_cb_data = source->callback_data;
      old_cb_funcs = source->callback_funcs;
954

955 956
      source->callback_data = NULL;
      source->callback_funcs = NULL;
957

958 959 960 961 962 963
      if (old_cb_funcs)
	{
	  UNLOCK_CONTEXT (context);
	  old_cb_funcs->unref (old_cb_data);
	  LOCK_CONTEXT (context);
	}
964 965

      if (!SOURCE_BLOCKED (source))
966
	{
967 968 969 970 971 972
	  tmp_list = source->poll_fds;
	  while (tmp_list)
	    {
	      g_main_context_remove_poll_unlocked (context, tmp_list->data);
	      tmp_list = tmp_list->next;
	    }
973
	}
974
	  
975 976
      g_source_unref_internal (source, context, TRUE);
    }
977

978 979
  if (!have_lock)
    UNLOCK_CONTEXT (context);
980 981
}

Owen Taylor's avatar