docs: gst: more gobject introspection annotations
[platform/upstream/gstreamer.git] / gst / gstsystemclock.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2004 Wim Taymans <wim@fluendo.com>
4  *
5  * gstsystemclock.c: Default clock, uses the system clock
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /**
24  * SECTION:gstsystemclock
25  * @short_description: Default clock that uses the current system time
26  * @see_also: #GstClock
27  *
28  * The GStreamer core provides a GstSystemClock based on the system time.
29  * Asynchronous callbacks are scheduled from an internal thread.
30  *
31  * Clock implementors are encouraged to subclass this systemclock as it
32  * implements the async notification.
33  *
34  * Subclasses can however override all of the important methods for sync and
35  * async notifications to implement their own callback methods or blocking
36  * wait operations.
37  *
38  * Last reviewed on 2006-03-08 (0.10.4)
39  */
40
41 #include "gst_private.h"
42 #include "gstinfo.h"
43 #include "gstsystemclock.h"
44 #include "gstenumtypes.h"
45 #include "gstpoll.h"
46 #include "gstutils.h"
47
48 #include <errno.h>
49
50 #ifdef G_OS_WIN32
51 #  define WIN32_LEAN_AND_MEAN   /* prevents from including too many things */
52 #  include <windows.h>          /* QueryPerformance* stuff */
53 #  undef WIN32_LEAN_AND_MEAN
54 #endif /* G_OS_WIN32 */
55
56 #define GET_ENTRY_STATUS(e)          (g_atomic_int_get(&GST_CLOCK_ENTRY_STATUS(e)))
57 #define SET_ENTRY_STATUS(e,val)      (g_atomic_int_set(&GST_CLOCK_ENTRY_STATUS(e),(val)))
58 #define CAS_ENTRY_STATUS(e,old,val)  (g_atomic_int_compare_and_exchange(\
59                                        ((volatile gint *)&GST_CLOCK_ENTRY_STATUS(e)), (old), (val)))
60
61 /* Define this to get some extra debug about jitter from each clock_wait */
62 #undef WAIT_DEBUGGING
63
64 struct _GstSystemClockPrivate
65 {
66   GstClockType clock_type;
67   GstPoll *timer;
68   gint wakeup_count;            /* the number of entries with a pending wakeup */
69   gboolean async_wakeup;        /* if the wakeup was because of a async list change */
70
71 #ifdef G_OS_WIN32
72   LARGE_INTEGER start;
73   LARGE_INTEGER frequency;
74 #endif                          /* G_OS_WIN32 */
75 };
76
77 #define GST_SYSTEM_CLOCK_GET_PRIVATE(obj)  \
78    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_SYSTEM_CLOCK, \
79         GstSystemClockPrivate))
80
81 #ifdef HAVE_POSIX_TIMERS
82 # ifdef HAVE_MONOTONIC_CLOCK
83 #  define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_MONOTONIC
84 # else
85 #  define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_REALTIME
86 # endif
87 #else
88 #define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_REALTIME
89 #endif
90
91 enum
92 {
93   PROP_0,
94   PROP_CLOCK_TYPE,
95   /* FILL ME */
96 };
97
98 /* the one instance of the systemclock */
99 static GstClock *_the_system_clock = NULL;
100
101 static void gst_system_clock_dispose (GObject * object);
102 static void gst_system_clock_set_property (GObject * object, guint prop_id,
103     const GValue * value, GParamSpec * pspec);
104 static void gst_system_clock_get_property (GObject * object, guint prop_id,
105     GValue * value, GParamSpec * pspec);
106
107 static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
108 static guint64 gst_system_clock_get_resolution (GstClock * clock);
109 static GstClockReturn gst_system_clock_id_wait_jitter (GstClock * clock,
110     GstClockEntry * entry, GstClockTimeDiff * jitter);
111 static GstClockReturn gst_system_clock_id_wait_jitter_unlocked
112     (GstClock * clock, GstClockEntry * entry, GstClockTimeDiff * jitter,
113     gboolean restart);
114 static GstClockReturn gst_system_clock_id_wait_async (GstClock * clock,
115     GstClockEntry * entry);
116 static void gst_system_clock_id_unschedule (GstClock * clock,
117     GstClockEntry * entry);
118 static void gst_system_clock_async_thread (GstClock * clock);
119 static gboolean gst_system_clock_start_async (GstSystemClock * clock);
120 static void gst_system_clock_add_wakeup (GstSystemClock * sysclock);
121
122 static GStaticMutex _gst_sysclock_mutex = G_STATIC_MUTEX_INIT;
123
124 static GstClockClass *parent_class = NULL;
125
126 /* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
127
128 G_DEFINE_TYPE (GstSystemClock, gst_system_clock, GST_TYPE_CLOCK);
129
130 static void
131 gst_system_clock_class_init (GstSystemClockClass * klass)
132 {
133   GObjectClass *gobject_class;
134   GstClockClass *gstclock_class;
135
136   gobject_class = (GObjectClass *) klass;
137   gstclock_class = (GstClockClass *) klass;
138
139   parent_class = g_type_class_peek_parent (klass);
140
141   g_type_class_add_private (klass, sizeof (GstSystemClockPrivate));
142
143   gobject_class->dispose = gst_system_clock_dispose;
144   gobject_class->set_property = gst_system_clock_set_property;
145   gobject_class->get_property = gst_system_clock_get_property;
146
147   g_object_class_install_property (gobject_class, PROP_CLOCK_TYPE,
148       g_param_spec_enum ("clock-type", "Clock type",
149           "The type of underlying clock implementation used",
150           GST_TYPE_CLOCK_TYPE, DEFAULT_CLOCK_TYPE,
151           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152
153   gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
154   gstclock_class->get_resolution = gst_system_clock_get_resolution;
155   gstclock_class->wait_jitter = gst_system_clock_id_wait_jitter;
156   gstclock_class->wait_async = gst_system_clock_id_wait_async;
157   gstclock_class->unschedule = gst_system_clock_id_unschedule;
158 }
159
160 static void
161 gst_system_clock_init (GstSystemClock * clock)
162 {
163   GST_OBJECT_FLAG_SET (clock,
164       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
165       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
166       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
167       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
168
169   clock->priv = GST_SYSTEM_CLOCK_GET_PRIVATE (clock);
170
171   clock->priv->clock_type = DEFAULT_CLOCK_TYPE;
172   clock->priv->timer = gst_poll_new_timer ();
173
174 #ifdef G_OS_WIN32
175   QueryPerformanceFrequency (&clock->priv->frequency);
176   /* can be 0 if the hardware does not have hardware support */
177   if (clock->priv->frequency.QuadPart != 0)
178     /* we take a base time so that time starts from 0 to ease debugging */
179     QueryPerformanceCounter (&clock->priv->start);
180 #endif /* G_OS_WIN32 */
181
182 #if 0
183   /* Uncomment this to start the async clock thread straight away */
184   GST_OBJECT_LOCK (clock);
185   gst_system_clock_start_async (clock);
186   GST_OBJECT_UNLOCK (clock);
187 #endif
188 }
189
190 static void
191 gst_system_clock_dispose (GObject * object)
192 {
193   GstClock *clock = (GstClock *) object;
194   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
195   GList *entries;
196
197   /* else we have to stop the thread */
198   GST_OBJECT_LOCK (clock);
199   sysclock->stopping = TRUE;
200   /* unschedule all entries */
201   for (entries = clock->entries; entries; entries = g_list_next (entries)) {
202     GstClockEntry *entry = (GstClockEntry *) entries->data;
203
204     GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
205     SET_ENTRY_STATUS (entry, GST_CLOCK_UNSCHEDULED);
206   }
207   GST_CLOCK_BROADCAST (clock);
208   gst_system_clock_add_wakeup (sysclock);
209   GST_OBJECT_UNLOCK (clock);
210
211   if (sysclock->thread)
212     g_thread_join (sysclock->thread);
213   sysclock->thread = NULL;
214   GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
215
216   g_list_foreach (clock->entries, (GFunc) gst_clock_id_unref, NULL);
217   g_list_free (clock->entries);
218   clock->entries = NULL;
219
220   gst_poll_free (sysclock->priv->timer);
221
222   G_OBJECT_CLASS (parent_class)->dispose (object);
223
224   if (_the_system_clock == clock) {
225     _the_system_clock = NULL;
226     GST_CAT_DEBUG (GST_CAT_CLOCK, "disposed system clock");
227   }
228 }
229
230 static void
231 gst_system_clock_set_property (GObject * object, guint prop_id,
232     const GValue * value, GParamSpec * pspec)
233 {
234   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (object);
235
236   switch (prop_id) {
237     case PROP_CLOCK_TYPE:
238       sysclock->priv->clock_type = g_value_get_enum (value);
239       GST_CAT_DEBUG (GST_CAT_CLOCK, "clock-type set to %d",
240           sysclock->priv->clock_type);
241       break;
242     default:
243       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
244       break;
245   }
246 }
247
248 static void
249 gst_system_clock_get_property (GObject * object, guint prop_id, GValue * value,
250     GParamSpec * pspec)
251 {
252   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (object);
253
254   switch (prop_id) {
255     case PROP_CLOCK_TYPE:
256       g_value_set_enum (value, sysclock->priv->clock_type);
257       break;
258     default:
259       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
260       break;
261   }
262 }
263
264 /**
265  * gst_system_clock_obtain:
266  *
267  * Get a handle to the default system clock. The refcount of the
268  * clock will be increased so you need to unref the clock after
269  * usage.
270  *
271  * Returns: (transfer full): the default clock.
272  *
273  * MT safe.
274  */
275 GstClock *
276 gst_system_clock_obtain (void)
277 {
278   GstClock *clock;
279
280   g_static_mutex_lock (&_gst_sysclock_mutex);
281   clock = _the_system_clock;
282
283   if (clock == NULL) {
284     GST_CAT_DEBUG (GST_CAT_CLOCK, "creating new static system clock");
285     clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
286         "name", "GstSystemClock", NULL);
287
288     /* we created the global clock; take ownership so
289      * we can hand out instances later */
290     gst_object_ref_sink (clock);
291
292     _the_system_clock = clock;
293     g_static_mutex_unlock (&_gst_sysclock_mutex);
294   } else {
295     g_static_mutex_unlock (&_gst_sysclock_mutex);
296     GST_CAT_DEBUG (GST_CAT_CLOCK, "returning static system clock");
297   }
298
299   /* we ref it since we are a clock factory. */
300   gst_object_ref (clock);
301   return clock;
302 }
303
304 static void
305 gst_system_clock_remove_wakeup (GstSystemClock * sysclock)
306 {
307   g_return_if_fail (sysclock->priv->wakeup_count > 0);
308
309   sysclock->priv->wakeup_count--;
310   if (sysclock->priv->wakeup_count == 0) {
311     /* read the control socket byte when we removed the last wakeup count */
312     GST_CAT_DEBUG (GST_CAT_CLOCK, "reading control");
313     while (!gst_poll_read_control (sysclock->priv->timer)) {
314       g_warning ("gstsystemclock: read control failed, trying again\n");
315     }
316     GST_CLOCK_BROADCAST (sysclock);
317   }
318   GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup count %d",
319       sysclock->priv->wakeup_count);
320 }
321
322 static void
323 gst_system_clock_add_wakeup (GstSystemClock * sysclock)
324 {
325   /* only write the control socket for the first wakeup */
326   if (sysclock->priv->wakeup_count == 0) {
327     GST_CAT_DEBUG (GST_CAT_CLOCK, "writing control");
328     while (!gst_poll_write_control (sysclock->priv->timer)) {
329       g_warning
330           ("gstsystemclock: write control failed in wakeup_async, trying again : %d:%s\n",
331           errno, g_strerror (errno));
332     }
333   }
334   sysclock->priv->wakeup_count++;
335   GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup count %d",
336       sysclock->priv->wakeup_count);
337 }
338
339 static void
340 gst_system_clock_wait_wakeup (GstSystemClock * sysclock)
341 {
342   while (sysclock->priv->wakeup_count) {
343     GST_CLOCK_WAIT (sysclock);
344   }
345 }
346
347 /* this thread reads the sorted clock entries from the queue.
348  *
349  * It waits on each of them and fires the callback when the timeout occurs.
350  *
351  * When an entry in the queue was canceled before we wait for it, it is
352  * simply skipped.
353  *
354  * When waiting for an entry, it can become canceled, in that case we don't
355  * call the callback but move to the next item in the queue.
356  *
357  * MT safe.
358  */
359 static void
360 gst_system_clock_async_thread (GstClock * clock)
361 {
362   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
363
364   GST_CAT_DEBUG (GST_CAT_CLOCK, "enter system clock thread");
365   GST_OBJECT_LOCK (clock);
366   /* signal spinup */
367   GST_CLOCK_BROADCAST (clock);
368   /* now enter our (almost) infinite loop */
369   while (!sysclock->stopping) {
370     GstClockEntry *entry;
371     GstClockTime requested;
372     GstClockReturn res;
373
374     /* check if something to be done */
375     while (clock->entries == NULL) {
376       GST_CAT_DEBUG (GST_CAT_CLOCK, "no clock entries, waiting..");
377       /* wait for work to do */
378       GST_CLOCK_WAIT (clock);
379       GST_CAT_DEBUG (GST_CAT_CLOCK, "got signal");
380       /* clock was stopping, exit */
381       if (sysclock->stopping)
382         goto exit;
383     }
384
385     /* see if we have a pending wakeup because the order of the list
386      * changed. */
387     if (sysclock->priv->async_wakeup) {
388       GST_CAT_DEBUG (GST_CAT_CLOCK, "clear async wakeup");
389       gst_system_clock_remove_wakeup (sysclock);
390       sysclock->priv->async_wakeup = FALSE;
391     }
392
393     /* pick the next entry */
394     entry = clock->entries->data;
395     GST_OBJECT_UNLOCK (clock);
396
397     requested = entry->time;
398
399     /* now wait for the entry, we already hold the lock */
400     res =
401         gst_system_clock_id_wait_jitter_unlocked (clock, (GstClockID) entry,
402         NULL, FALSE);
403
404     GST_OBJECT_LOCK (clock);
405
406     switch (res) {
407       case GST_CLOCK_UNSCHEDULED:
408         /* entry was unscheduled, move to the next */
409         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unscheduled", entry);
410         goto next_entry;
411       case GST_CLOCK_OK:
412       case GST_CLOCK_EARLY:
413       {
414         /* entry timed out normally, fire the callback and move to the next
415          * entry */
416         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p timed out", entry);
417         if (entry->func) {
418           /* unlock before firing the callback */
419           GST_OBJECT_UNLOCK (clock);
420           entry->func (clock, entry->time, (GstClockID) entry,
421               entry->user_data);
422           GST_OBJECT_LOCK (clock);
423         }
424         if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
425           GST_CAT_DEBUG (GST_CAT_CLOCK, "updating periodic entry %p", entry);
426           /* adjust time now */
427           entry->time = requested + entry->interval;
428           /* and resort the list now */
429           clock->entries =
430               g_list_sort (clock->entries, gst_clock_id_compare_func);
431           /* and restart */
432           continue;
433         } else {
434           GST_CAT_DEBUG (GST_CAT_CLOCK, "moving to next entry");
435           goto next_entry;
436         }
437       }
438       case GST_CLOCK_BUSY:
439         /* somebody unlocked the entry but is was not canceled, This means that
440          * either a new entry was added in front of the queue or some other entry
441          * was canceled. Whatever it is, pick the head entry of the list and
442          * continue waiting. */
443         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p needs restart", entry);
444
445         /* we set the entry back to the OK state. This is needed so that the
446          * _unschedule() code can see if an entry is currently being waited
447          * on (when its state is BUSY). */
448         SET_ENTRY_STATUS (entry, GST_CLOCK_OK);
449         continue;
450       default:
451         GST_CAT_DEBUG (GST_CAT_CLOCK,
452             "strange result %d waiting for %p, skipping", res, entry);
453         g_warning ("%s: strange result %d waiting for %p, skipping",
454             GST_OBJECT_NAME (clock), res, entry);
455         goto next_entry;
456     }
457   next_entry:
458     /* we remove the current entry and unref it */
459     clock->entries = g_list_remove (clock->entries, entry);
460     gst_clock_id_unref ((GstClockID) entry);
461   }
462 exit:
463   /* signal exit */
464   GST_CLOCK_BROADCAST (clock);
465   GST_OBJECT_UNLOCK (clock);
466   GST_CAT_DEBUG (GST_CAT_CLOCK, "exit system clock thread");
467 }
468
469 #ifdef HAVE_POSIX_TIMERS
470 static inline clockid_t
471 clock_type_to_posix_id (GstClockType clock_type)
472 {
473 #ifdef HAVE_MONOTONIC_CLOCK
474   if (clock_type == GST_CLOCK_TYPE_MONOTONIC)
475     return CLOCK_MONOTONIC;
476   else
477 #endif
478     return CLOCK_REALTIME;
479 }
480 #endif
481
482 /* MT safe */
483 static GstClockTime
484 gst_system_clock_get_internal_time (GstClock * clock)
485 {
486 #ifdef G_OS_WIN32
487   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
488
489   if (sysclock->priv->frequency.QuadPart != 0) {
490     LARGE_INTEGER now;
491
492     /* we prefer the highly accurate performance counters on windows */
493     QueryPerformanceCounter (&now);
494
495     return gst_util_uint64_scale (now.QuadPart - sysclock->priv->start.QuadPart,
496         GST_SECOND, sysclock->priv->frequency.QuadPart);
497   } else
498 #endif /* G_OS_WIN32 */
499 #if !defined HAVE_POSIX_TIMERS
500   {
501     GTimeVal timeval;
502
503     g_get_current_time (&timeval);
504
505     return GST_TIMEVAL_TO_TIME (timeval);
506   }
507 #else
508   {
509     GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
510     clockid_t ptype;
511     struct timespec ts;
512
513     ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
514
515     if (G_UNLIKELY (clock_gettime (ptype, &ts)))
516       return GST_CLOCK_TIME_NONE;
517
518     return GST_TIMESPEC_TO_TIME (ts);
519   }
520 #endif
521 }
522
523 static guint64
524 gst_system_clock_get_resolution (GstClock * clock)
525 {
526 #ifdef G_OS_WIN32
527   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
528
529   if (sysclock->priv->frequency.QuadPart != 0) {
530     return GST_SECOND / sysclock->priv->frequency.QuadPart;
531   } else
532 #endif /* G_OS_WIN32 */
533 #ifdef HAVE_POSIX_TIMERS
534   {
535     GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
536     clockid_t ptype;
537     struct timespec ts;
538
539     ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
540
541     if (G_UNLIKELY (clock_getres (ptype, &ts)))
542       return GST_CLOCK_TIME_NONE;
543
544     return GST_TIMESPEC_TO_TIME (ts);
545   }
546 #else
547   {
548     return 1 * GST_USECOND;
549   }
550 #endif
551 }
552
553 /* synchronously wait on the given GstClockEntry.
554  *
555  * We do this by blocking on the global GstPoll timer with
556  * the requested timeout. This allows us to unblock the
557  * entry by writing on the control fd.
558  *
559  * Note that writing the global GstPoll unlocks all waiting entries. So
560  * we need to check if an unlocked entry has changed when it unlocks.
561  *
562  * Entries that arrive too late are simply not waited on and a
563  * GST_CLOCK_EARLY result is returned.
564  *
565  * MT safe.
566  */
567 static GstClockReturn
568 gst_system_clock_id_wait_jitter_unlocked (GstClock * clock,
569     GstClockEntry * entry, GstClockTimeDiff * jitter, gboolean restart)
570 {
571   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
572   GstClockTime entryt, now;
573   GstClockTimeDiff diff;
574   GstClockReturn status;
575
576   if (G_UNLIKELY (GET_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED))
577     return GST_CLOCK_UNSCHEDULED;
578
579   /* need to call the overridden method because we want to sync against the time
580    * of the clock, whatever the subclass uses as a clock. */
581   now = gst_clock_get_time (clock);
582
583   /* get the time of the entry */
584   entryt = GST_CLOCK_ENTRY_TIME (entry);
585
586   /* the diff of the entry with the clock is the amount of time we have to
587    * wait */
588   diff = GST_CLOCK_DIFF (now, entryt);
589   if (G_LIKELY (jitter))
590     *jitter = -diff;
591
592   GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p"
593       " time %" GST_TIME_FORMAT
594       " now %" GST_TIME_FORMAT
595       " diff (time-now) %" G_GINT64_FORMAT,
596       entry, GST_TIME_ARGS (entryt), GST_TIME_ARGS (now), diff);
597
598   if (G_LIKELY (diff > 0)) {
599 #ifdef WAIT_DEBUGGING
600     GstClockTime final;
601 #endif
602
603     while (TRUE) {
604       gint pollret;
605
606       do {
607         status = GET_ENTRY_STATUS (entry);
608
609         /* stop when we are unscheduled */
610         if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED))
611           goto done;
612
613         /* mark the entry as busy but watch out for intermediate unscheduled
614          * statuses */
615       } while (G_UNLIKELY (!CAS_ENTRY_STATUS (entry, status, GST_CLOCK_BUSY)));
616
617       /* now wait on the entry, it either times out or the fd is written. The
618        * status of the entry is only BUSY around the poll. */
619       pollret = gst_poll_wait (sysclock->priv->timer, diff);
620
621       /* get the new status, mark as DONE. We do this so that the unschedule
622        * function knows when we left the poll and doesn't need to wakeup the
623        * poll anymore. */
624       do {
625         status = GET_ENTRY_STATUS (entry);
626         /* we were unscheduled, exit immediately */
627         if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED))
628           break;
629       } while (G_UNLIKELY (!CAS_ENTRY_STATUS (entry, status, GST_CLOCK_DONE)));
630
631       GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked, status %d, ret %d",
632           entry, status, pollret);
633
634       if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
635         /* try to clean up The unschedule function managed to set the status to
636          * unscheduled. We now take the lock and mark the entry as unscheduled.
637          * This makes sure that the unschedule function doesn't perform a
638          * wakeup anymore. If the unschedule function has a change to perform
639          * the wakeup before us, we clean up here */
640         GST_OBJECT_LOCK (sysclock);
641         entry->unscheduled = TRUE;
642         if (entry->woken_up) {
643           gst_system_clock_remove_wakeup (sysclock);
644         }
645         GST_OBJECT_UNLOCK (sysclock);
646         goto done;
647       } else {
648         if (G_UNLIKELY (pollret != 0)) {
649           /* some other id got unlocked */
650           if (!restart) {
651             /* this can happen if the entry got unlocked because of an async
652              * entry was added to the head of the async queue. */
653             GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup waiting for entry %p", entry);
654             goto done;
655           }
656
657           /* wait till all the entries got woken up */
658           GST_OBJECT_LOCK (sysclock);
659           gst_system_clock_wait_wakeup (sysclock);
660           GST_OBJECT_UNLOCK (sysclock);
661
662           GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p needs to be restarted",
663               entry);
664         } else {
665           GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked after timeout",
666               entry);
667         }
668
669         /* reschedule if gst_poll_wait returned early or we have to reschedule after
670          * an unlock*/
671         now = gst_clock_get_time (clock);
672         diff = GST_CLOCK_DIFF (now, entryt);
673
674         if (diff <= 0) {
675           /* timeout, this is fine, we can report success now */
676           status = GST_CLOCK_OK;
677           SET_ENTRY_STATUS (entry, status);
678
679           GST_CAT_DEBUG (GST_CAT_CLOCK,
680               "entry %p finished, diff %" G_GINT64_FORMAT, entry, diff);
681
682 #ifdef WAIT_DEBUGGING
683           final = gst_system_clock_get_internal_time (clock);
684           GST_CAT_DEBUG (GST_CAT_CLOCK, "Waited for %" G_GINT64_FORMAT
685               " got %" G_GINT64_FORMAT " diff %" G_GINT64_FORMAT
686               " %g target-offset %" G_GINT64_FORMAT " %g", entryt, now,
687               now - entryt,
688               (double) (GstClockTimeDiff) (now - entryt) / GST_SECOND,
689               (final - target),
690               ((double) (GstClockTimeDiff) (final - target)) / GST_SECOND);
691 #endif
692           goto done;
693         } else {
694           GST_CAT_DEBUG (GST_CAT_CLOCK,
695               "entry %p restart, diff %" G_GINT64_FORMAT, entry, diff);
696         }
697       }
698     }
699   } else {
700     /* we are right on time or too late */
701     if (G_UNLIKELY (diff == 0))
702       status = GST_CLOCK_OK;
703     else
704       status = GST_CLOCK_EARLY;
705
706     SET_ENTRY_STATUS (entry, status);
707   }
708 done:
709   return status;
710 }
711
712 static GstClockReturn
713 gst_system_clock_id_wait_jitter (GstClock * clock, GstClockEntry * entry,
714     GstClockTimeDiff * jitter)
715 {
716   return gst_system_clock_id_wait_jitter_unlocked (clock, entry, jitter, TRUE);
717 }
718
719 /* Start the async clock thread. Must be called with the object lock
720  * held */
721 static gboolean
722 gst_system_clock_start_async (GstSystemClock * clock)
723 {
724   GError *error = NULL;
725
726   if (G_LIKELY (clock->thread != NULL))
727     return TRUE;                /* Thread already running. Nothing to do */
728
729   clock->thread = g_thread_create ((GThreadFunc) gst_system_clock_async_thread,
730       clock, TRUE, &error);
731   if (G_UNLIKELY (error))
732     goto no_thread;
733
734   /* wait for it to spin up */
735   GST_CLOCK_WAIT (clock);
736
737   return TRUE;
738
739   /* ERRORS */
740 no_thread:
741   {
742     g_warning ("could not create async clock thread: %s", error->message);
743     g_error_free (error);
744   }
745   return FALSE;
746 }
747
748 /* Add an entry to the list of pending async waits. The entry is inserted
749  * in sorted order. If we inserted the entry at the head of the list, we
750  * need to signal the thread as it might either be waiting on it or waiting
751  * for a new entry.
752  *
753  * MT safe.
754  */
755 static GstClockReturn
756 gst_system_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
757 {
758   GstSystemClock *sysclock;
759   GstClockEntry *head;
760
761   sysclock = GST_SYSTEM_CLOCK_CAST (clock);
762
763   GST_CAT_DEBUG (GST_CAT_CLOCK, "adding async entry %p", entry);
764
765   GST_OBJECT_LOCK (clock);
766   /* Start the clock async thread if needed */
767   if (G_UNLIKELY (!gst_system_clock_start_async (sysclock)))
768     goto thread_error;
769
770   if (G_UNLIKELY (GET_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED))
771     goto was_unscheduled;
772
773   if (clock->entries)
774     head = clock->entries->data;
775   else
776     head = NULL;
777
778   /* need to take a ref */
779   gst_clock_id_ref ((GstClockID) entry);
780   /* insert the entry in sorted order */
781   clock->entries = g_list_insert_sorted (clock->entries, entry,
782       gst_clock_id_compare_func);
783
784   /* only need to send the signal if the entry was added to the
785    * front, else the thread is just waiting for another entry and
786    * will get to this entry automatically. */
787   if (clock->entries->data == entry) {
788     GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry added to head %p", head);
789     if (head == NULL) {
790       /* the list was empty before, signal the cond so that the async thread can
791        * start taking a look at the queue */
792       GST_CAT_DEBUG (GST_CAT_CLOCK, "first entry, sending signal");
793       GST_CLOCK_BROADCAST (clock);
794     } else {
795       GstClockReturn status;
796
797       status = GET_ENTRY_STATUS (head);
798       GST_CAT_DEBUG (GST_CAT_CLOCK, "head entry %p status %d", head, status);
799
800       if (status == GST_CLOCK_BUSY) {
801         GST_CAT_DEBUG (GST_CAT_CLOCK, "head entry is busy");
802         /* the async thread was waiting for an entry, unlock the wait so that it
803          * looks at the new head entry instead, we only need to do this once */
804         if (!sysclock->priv->async_wakeup) {
805           GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup async thread");
806           sysclock->priv->async_wakeup = TRUE;
807           gst_system_clock_add_wakeup (sysclock);
808         }
809       }
810     }
811   }
812   GST_OBJECT_UNLOCK (clock);
813
814   return GST_CLOCK_OK;
815
816   /* ERRORS */
817 thread_error:
818   {
819     /* Could not start the async clock thread */
820     GST_OBJECT_UNLOCK (clock);
821     return GST_CLOCK_ERROR;
822   }
823 was_unscheduled:
824   {
825     GST_OBJECT_UNLOCK (clock);
826     return GST_CLOCK_UNSCHEDULED;
827   }
828 }
829
830 /* unschedule an entry. This will set the state of the entry to GST_CLOCK_UNSCHEDULED
831  * and will signal any thread waiting for entries to recheck their entry.
832  * We cannot really decide if the signal is needed or not because the entry
833  * could be waited on in async or sync mode.
834  *
835  * MT safe.
836  */
837 static void
838 gst_system_clock_id_unschedule (GstClock * clock, GstClockEntry * entry)
839 {
840   GstSystemClock *sysclock;
841   GstClockReturn status;
842
843   sysclock = GST_SYSTEM_CLOCK_CAST (clock);
844
845   GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
846
847   GST_OBJECT_LOCK (clock);
848   /* change the entry status to unscheduled */
849   do {
850     status = GET_ENTRY_STATUS (entry);
851   } while (G_UNLIKELY (!CAS_ENTRY_STATUS (entry, status,
852               GST_CLOCK_UNSCHEDULED)));
853
854   if (G_LIKELY (status == GST_CLOCK_BUSY)) {
855     /* the entry was being busy, wake up all entries so that they recheck their
856      * status. We cannot wake up just one entry because allocating such a
857      * datastructure for each entry would be too heavy and unlocking an entry
858      * is usually done when shutting down or some other exceptional case. */
859     GST_CAT_DEBUG (GST_CAT_CLOCK, "entry was BUSY, doing wakeup");
860     if (!entry->unscheduled && !entry->woken_up) {
861       gst_system_clock_add_wakeup (sysclock);
862       entry->woken_up = TRUE;
863     }
864   }
865   GST_OBJECT_UNLOCK (clock);
866 }