gstreamer_core/gst/gstsystemclock.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     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 
       
    44 #include "gstsystemclock.h"
       
    45 
       
    46 #ifdef __SYMBIAN32__
       
    47 #include <glib_global.h>
       
    48 #endif
       
    49 
       
    50 /* Define this to get some extra debug about jitter from each clock_wait */
       
    51 #undef WAIT_DEBUGGING
       
    52 
       
    53 /* the one instance of the systemclock */
       
    54 static GstClock *_the_system_clock = NULL;
       
    55 
       
    56 static void gst_system_clock_class_init (GstSystemClockClass * klass);
       
    57 static void gst_system_clock_init (GstSystemClock * clock);
       
    58 static void gst_system_clock_dispose (GObject * object);
       
    59 
       
    60 static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
       
    61 static guint64 gst_system_clock_get_resolution (GstClock * clock);
       
    62 static GstClockReturn gst_system_clock_id_wait_jitter (GstClock * clock,
       
    63     GstClockEntry * entry, GstClockTimeDiff * jitter);
       
    64 static GstClockReturn gst_system_clock_id_wait_jitter_unlocked
       
    65     (GstClock * clock, GstClockEntry * entry, GstClockTimeDiff * jitter,
       
    66     gboolean restart);
       
    67 static GstClockReturn gst_system_clock_id_wait_async (GstClock * clock,
       
    68     GstClockEntry * entry);
       
    69 static void gst_system_clock_id_unschedule (GstClock * clock,
       
    70     GstClockEntry * entry);
       
    71 static void gst_system_clock_async_thread (GstClock * clock);
       
    72 static gboolean gst_system_clock_start_async (GstSystemClock * clock);
       
    73 
       
    74 static GStaticMutex _gst_sysclock_mutex = G_STATIC_MUTEX_INIT;
       
    75 
       
    76 static GstClockClass *parent_class = NULL;
       
    77 
       
    78 /* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
       
    79 #ifdef __SYMBIAN32__
       
    80 EXPORT_C
       
    81 #endif
       
    82 
       
    83 
       
    84 GType
       
    85 gst_system_clock_get_type (void)
       
    86 {
       
    87   static GType clock_type = 0;
       
    88 
       
    89   if (G_UNLIKELY (clock_type == 0)) {
       
    90     static const GTypeInfo clock_info = {
       
    91       sizeof (GstSystemClockClass),
       
    92       NULL,
       
    93       NULL,
       
    94       (GClassInitFunc) gst_system_clock_class_init,
       
    95       NULL,
       
    96       NULL,
       
    97       sizeof (GstSystemClock),
       
    98       0,
       
    99       (GInstanceInitFunc) gst_system_clock_init,
       
   100       NULL
       
   101     };
       
   102 
       
   103     clock_type = g_type_register_static (GST_TYPE_CLOCK, "GstSystemClock",
       
   104         &clock_info, 0);
       
   105   }
       
   106   return clock_type;
       
   107 }
       
   108 
       
   109 static void
       
   110 gst_system_clock_class_init (GstSystemClockClass * klass)
       
   111 {
       
   112   GObjectClass *gobject_class;
       
   113   GstObjectClass *gstobject_class;
       
   114   GstClockClass *gstclock_class;
       
   115 
       
   116   gobject_class = (GObjectClass *) klass;
       
   117   gstobject_class = (GstObjectClass *) klass;
       
   118   gstclock_class = (GstClockClass *) klass;
       
   119 
       
   120   parent_class = g_type_class_peek_parent (klass);
       
   121 
       
   122   gobject_class->dispose = gst_system_clock_dispose;
       
   123 
       
   124   gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
       
   125   gstclock_class->get_resolution = gst_system_clock_get_resolution;
       
   126   gstclock_class->wait_jitter = gst_system_clock_id_wait_jitter;
       
   127   gstclock_class->wait_async = gst_system_clock_id_wait_async;
       
   128   gstclock_class->unschedule = gst_system_clock_id_unschedule;
       
   129 }
       
   130 
       
   131 static void
       
   132 gst_system_clock_init (GstSystemClock * clock)
       
   133 {
       
   134   GST_OBJECT_FLAG_SET (clock,
       
   135       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
       
   136       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
       
   137       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
       
   138       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
       
   139 
       
   140 #if 0
       
   141   /* Uncomment this to start the async clock thread straight away */
       
   142   GST_CLOCK_LOCK (clock);
       
   143   gst_system_clock_start_async (clock);
       
   144   GST_CLOCK_UNLOCK (clock);
       
   145 #endif
       
   146 }
       
   147 
       
   148 static void
       
   149 gst_system_clock_dispose (GObject * object)
       
   150 {
       
   151   GstClock *clock = (GstClock *) object;
       
   152 
       
   153   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
       
   154   GList *entries;
       
   155 
       
   156   /* else we have to stop the thread */
       
   157   GST_OBJECT_LOCK (clock);
       
   158   sysclock->stopping = TRUE;
       
   159   /* unschedule all entries */
       
   160   for (entries = clock->entries; entries; entries = g_list_next (entries)) {
       
   161     GstClockEntry *entry = (GstClockEntry *) entries->data;
       
   162 
       
   163     GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
       
   164     entry->status = GST_CLOCK_UNSCHEDULED;
       
   165   }
       
   166   g_list_free (clock->entries);
       
   167   clock->entries = NULL;
       
   168   GST_CLOCK_BROADCAST (clock);
       
   169   GST_OBJECT_UNLOCK (clock);
       
   170 
       
   171   if (sysclock->thread)
       
   172     g_thread_join (sysclock->thread);
       
   173   sysclock->thread = NULL;
       
   174   GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
       
   175 
       
   176   G_OBJECT_CLASS (parent_class)->dispose (object);
       
   177 
       
   178   if (_the_system_clock == clock) {
       
   179     _the_system_clock = NULL;
       
   180     GST_CAT_DEBUG (GST_CAT_CLOCK, "disposed system clock");
       
   181   }
       
   182 }
       
   183 
       
   184 /**
       
   185  * gst_system_clock_obtain:
       
   186  *
       
   187  * Get a handle to the default system clock. The refcount of the
       
   188  * clock will be increased so you need to unref the clock after
       
   189  * usage.
       
   190  *
       
   191  * Returns: the default clock.
       
   192  *
       
   193  * MT safe.
       
   194  */
       
   195 #ifdef __SYMBIAN32__
       
   196 EXPORT_C
       
   197 #endif
       
   198 
       
   199 GstClock *
       
   200 gst_system_clock_obtain (void)
       
   201 {
       
   202   GstClock *clock;
       
   203 
       
   204   g_static_mutex_lock (&_gst_sysclock_mutex);
       
   205   clock = _the_system_clock;
       
   206 
       
   207   if (clock == NULL) {
       
   208     GST_CAT_DEBUG (GST_CAT_CLOCK, "creating new static system clock");
       
   209     clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
       
   210         "name", "GstSystemClock", NULL);
       
   211 
       
   212     /* we created the global clock; take ownership so
       
   213      * we can hand out instances later */
       
   214     gst_object_ref (clock);
       
   215     gst_object_sink (GST_OBJECT (clock));
       
   216 
       
   217     _the_system_clock = clock;
       
   218     g_static_mutex_unlock (&_gst_sysclock_mutex);
       
   219   } else {
       
   220     g_static_mutex_unlock (&_gst_sysclock_mutex);
       
   221     GST_CAT_DEBUG (GST_CAT_CLOCK, "returning static system clock");
       
   222   }
       
   223 
       
   224   /* we ref it since we are a clock factory. */
       
   225   gst_object_ref (clock);
       
   226   return clock;
       
   227 }
       
   228 
       
   229 /* this thread reads the sorted clock entries from the queue.
       
   230  *
       
   231  * It waits on each of them and fires the callback when the timeout occurs.
       
   232  *
       
   233  * When an entry in the queue was canceled before we wait for it, it is
       
   234  * simply skipped.
       
   235  *
       
   236  * When waiting for an entry, it can become canceled, in that case we don't
       
   237  * call the callback but move to the next item in the queue.
       
   238  *
       
   239  * MT safe.
       
   240  */
       
   241 static void
       
   242 gst_system_clock_async_thread (GstClock * clock)
       
   243 {
       
   244   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
       
   245 
       
   246   GST_CAT_DEBUG (GST_CAT_CLOCK, "enter system clock thread");
       
   247   GST_OBJECT_LOCK (clock);
       
   248   /* signal spinup */
       
   249   GST_CLOCK_BROADCAST (clock);
       
   250   /* now enter our (almost) infinite loop */
       
   251   while (!sysclock->stopping) {
       
   252     GstClockEntry *entry;
       
   253     GstClockTime requested;
       
   254     GstClockReturn res;
       
   255 
       
   256     /* check if something to be done */
       
   257     while (clock->entries == NULL) {
       
   258       GST_CAT_DEBUG (GST_CAT_CLOCK, "no clock entries, waiting..");
       
   259       /* wait for work to do */
       
   260       GST_CLOCK_WAIT (clock);
       
   261       GST_CAT_DEBUG (GST_CAT_CLOCK, "got signal");
       
   262       /* clock was stopping, exit */
       
   263       if (sysclock->stopping)
       
   264         goto exit;
       
   265     }
       
   266 
       
   267     /* pick the next entry */
       
   268     entry = clock->entries->data;
       
   269     /* if it was unscheduled, just move on to the next entry */
       
   270     if (entry->status == GST_CLOCK_UNSCHEDULED) {
       
   271       GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p was unscheduled", entry);
       
   272       goto next_entry;
       
   273     }
       
   274 
       
   275     requested = entry->time;
       
   276 
       
   277     /* now wait for the entry, we already hold the lock */
       
   278     res =
       
   279         gst_system_clock_id_wait_jitter_unlocked (clock, (GstClockID) entry,
       
   280         NULL, FALSE);
       
   281 
       
   282     switch (res) {
       
   283       case GST_CLOCK_UNSCHEDULED:
       
   284         /* entry was unscheduled, move to the next */
       
   285         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unscheduled", entry);
       
   286         goto next_entry;
       
   287       case GST_CLOCK_OK:
       
   288       case GST_CLOCK_EARLY:
       
   289       {
       
   290         /* entry timed out normally, fire the callback and move to the next
       
   291          * entry */
       
   292         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unlocked", entry);
       
   293         if (entry->func) {
       
   294           /* unlock before firing the callback */
       
   295           GST_OBJECT_UNLOCK (clock);
       
   296           entry->func (clock, entry->time, (GstClockID) entry,
       
   297               entry->user_data);
       
   298           GST_OBJECT_LOCK (clock);
       
   299         }
       
   300         if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
       
   301           /* adjust time now */
       
   302           entry->time = requested + entry->interval;
       
   303           /* and resort the list now */
       
   304           clock->entries =
       
   305               g_list_sort (clock->entries, gst_clock_id_compare_func);
       
   306           /* and restart */
       
   307           continue;
       
   308         } else {
       
   309           goto next_entry;
       
   310         }
       
   311       }
       
   312       case GST_CLOCK_BUSY:
       
   313         /* somebody unlocked the entry but is was not canceled, This means that
       
   314          * either a new entry was added in front of the queue or some other entry
       
   315          * was canceled. Whatever it is, pick the head entry of the list and
       
   316          * continue waiting. */
       
   317         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p needs restart", entry);
       
   318         continue;
       
   319       default:
       
   320         GST_CAT_DEBUG (GST_CAT_CLOCK,
       
   321             "strange result %d waiting for %p, skipping", res, entry);
       
   322         g_warning ("%s: strange result %d waiting for %p, skipping",
       
   323             GST_OBJECT_NAME (clock), res, entry);
       
   324         goto next_entry;
       
   325     }
       
   326   next_entry:
       
   327     /* we remove the current entry and unref it */
       
   328     clock->entries = g_list_remove (clock->entries, entry);
       
   329     gst_clock_id_unref ((GstClockID) entry);
       
   330   }
       
   331 exit:
       
   332   /* signal exit */
       
   333   GST_CLOCK_BROADCAST (clock);
       
   334   GST_OBJECT_UNLOCK (clock);
       
   335   GST_CAT_DEBUG (GST_CAT_CLOCK, "exit system clock thread");
       
   336 }
       
   337 
       
   338 /* MT safe */
       
   339 static GstClockTime
       
   340 gst_system_clock_get_internal_time (GstClock * clock)
       
   341 {
       
   342   GTimeVal timeval;
       
   343 
       
   344   g_get_current_time (&timeval);
       
   345 
       
   346   return GST_TIMEVAL_TO_TIME (timeval);
       
   347 }
       
   348 
       
   349 static guint64
       
   350 gst_system_clock_get_resolution (GstClock * clock)
       
   351 {
       
   352   return 1 * GST_USECOND;
       
   353 }
       
   354 
       
   355 /* synchronously wait on the given GstClockEntry.
       
   356  *
       
   357  * We do this by blocking on the global clock GCond variable with
       
   358  * the requested time as a timeout. This allows us to unblock the
       
   359  * entry by signaling the GCond variable.
       
   360  *
       
   361  * Note that signaling the global GCond unlocks all waiting entries. So
       
   362  * we need to check if an unlocked entry has changed when it unlocks.
       
   363  *
       
   364  * Entries that arrive too late are simply not waited on and a
       
   365  * GST_CLOCK_EARLY result is returned.
       
   366  *
       
   367  * should be called with LOCK held.
       
   368  *
       
   369  * MT safe.
       
   370  */
       
   371 static GstClockReturn
       
   372 gst_system_clock_id_wait_jitter_unlocked (GstClock * clock,
       
   373     GstClockEntry * entry, GstClockTimeDiff * jitter, gboolean restart)
       
   374 {
       
   375   GstClockTime entryt, real, now, target;
       
   376   GstClockTimeDiff diff;
       
   377 
       
   378   /* need to call the overridden method because we want to sync against the time
       
   379    * of the clock, whatever the subclass uses as a clock. */
       
   380   real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
       
   381   entryt = GST_CLOCK_ENTRY_TIME (entry);
       
   382 
       
   383   now = gst_clock_adjust_unlocked (clock, real);
       
   384   if (jitter) {
       
   385     *jitter = GST_CLOCK_DIFF (entryt, now);
       
   386   }
       
   387   /* the diff of the entry with the clock is the amount of time we have to
       
   388    * wait */
       
   389   diff = entryt - now;
       
   390   /* Our GCond implementation expects an absolute time against the system clock
       
   391    * as a timeout value. We use our internal time to get the system time and add
       
   392    * the expected timeout to it, this gives us the absolute time of the
       
   393    * timeout. */
       
   394   target = gst_system_clock_get_internal_time (clock) + diff;
       
   395 
       
   396   GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p"
       
   397       " target %" GST_TIME_FORMAT
       
   398       " entry %" GST_TIME_FORMAT
       
   399       " now %" GST_TIME_FORMAT
       
   400       " real %" GST_TIME_FORMAT
       
   401       " diff (entry-now) %" G_GINT64_FORMAT,
       
   402       entry,
       
   403       GST_TIME_ARGS (target),
       
   404       GST_TIME_ARGS (entryt), GST_TIME_ARGS (now), GST_TIME_ARGS (real), diff);
       
   405 
       
   406   if (diff > 0) {
       
   407     GTimeVal tv;
       
   408 
       
   409 #ifdef WAIT_DEBUGGING
       
   410     GstClockTime result, final;
       
   411 #endif
       
   412 
       
   413     GST_TIME_TO_TIMEVAL (target, tv);
       
   414 
       
   415     while (TRUE) {
       
   416       /* now wait on the entry, it either times out or the cond is signaled. */
       
   417       if (!GST_CLOCK_TIMED_WAIT (clock, &tv)) {
       
   418         /* timeout, this is fine, we can report success now */
       
   419         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked after timeout", entry);
       
   420         entry->status = GST_CLOCK_OK;
       
   421 
       
   422 #ifdef WAIT_DEBUGGING
       
   423         real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
       
   424         result = gst_clock_adjust_unlocked (clock, real);
       
   425         final = gst_system_clock_get_internal_time (clock);
       
   426         GST_CAT_DEBUG (GST_CAT_CLOCK, "Waited for %" G_GINT64_FORMAT
       
   427             " got %" G_GINT64_FORMAT " diff %" G_GINT64_FORMAT
       
   428             " %g target-offset %" G_GINT64_FORMAT " %g", entryt, result,
       
   429             result - entryt,
       
   430             (double) (GstClockTimeDiff) (result - entryt) / GST_SECOND,
       
   431             (final - target),
       
   432             ((double) (GstClockTimeDiff) (final - target)) / GST_SECOND);
       
   433 #endif
       
   434         break;
       
   435       } else {
       
   436         /* the waiting is interrupted because the GCond was signaled. This can
       
   437          * be because this or some other entry was unscheduled. */
       
   438         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked with signal", entry);
       
   439         /* if the entry is unscheduled, we can stop waiting for it, else we
       
   440          * continue our while loop. */
       
   441         if (entry->status == GST_CLOCK_UNSCHEDULED)
       
   442           break;
       
   443         /* else restart if we must */
       
   444         if (!restart)
       
   445           break;
       
   446 
       
   447         /* this can happen if the entry got unlocked because of an async entry
       
   448          * was added to the head of the async queue. */
       
   449         GST_CAT_DEBUG (GST_CAT_CLOCK, "continue waiting for entry %p", entry);
       
   450       }
       
   451     }
       
   452   } else if (diff == 0) {
       
   453     entry->status = GST_CLOCK_OK;
       
   454   } else {
       
   455     entry->status = GST_CLOCK_EARLY;
       
   456   }
       
   457   return entry->status;
       
   458 }
       
   459 
       
   460 static GstClockReturn
       
   461 gst_system_clock_id_wait_jitter (GstClock * clock, GstClockEntry * entry,
       
   462     GstClockTimeDiff * jitter)
       
   463 {
       
   464   GstClockReturn ret;
       
   465 
       
   466   GST_OBJECT_LOCK (clock);
       
   467   ret = gst_system_clock_id_wait_jitter_unlocked (clock, entry, jitter, TRUE);
       
   468   GST_OBJECT_UNLOCK (clock);
       
   469 
       
   470   return ret;
       
   471 }
       
   472 
       
   473 /* Start the async clock thread. Must be called with the object lock
       
   474  * held */
       
   475 static gboolean
       
   476 gst_system_clock_start_async (GstSystemClock * clock)
       
   477 {
       
   478   GError *error = NULL;
       
   479 
       
   480   if (clock->thread != NULL)
       
   481     return TRUE;                /* Thread already running. Nothing to do */
       
   482 
       
   483   clock->thread = g_thread_create ((GThreadFunc) gst_system_clock_async_thread,
       
   484       clock, TRUE, &error);
       
   485   if (error)
       
   486     goto no_thread;
       
   487 
       
   488   /* wait for it to spin up */
       
   489   GST_CLOCK_WAIT (clock);
       
   490 
       
   491   return TRUE;
       
   492 
       
   493   /* ERRORS */
       
   494 no_thread:
       
   495   {
       
   496     g_warning ("could not create async clock thread: %s", error->message);
       
   497   }
       
   498   return FALSE;
       
   499 }
       
   500 
       
   501 /* Add an entry to the list of pending async waits. The entry is inserted
       
   502  * in sorted order. If we inserted the entry at the head of the list, we
       
   503  * need to signal the thread as it might either be waiting on it or waiting
       
   504  * for a new entry.
       
   505  *
       
   506  * MT safe.
       
   507  */
       
   508 static GstClockReturn
       
   509 gst_system_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
       
   510 {
       
   511   GST_CAT_DEBUG (GST_CAT_CLOCK, "adding async entry %p", entry);
       
   512 
       
   513   GST_OBJECT_LOCK (clock);
       
   514 
       
   515   /* Start the clock async thread if needed */
       
   516   if (!gst_system_clock_start_async (GST_SYSTEM_CLOCK (clock)))
       
   517     goto thread_error;
       
   518 
       
   519   /* need to take a ref */
       
   520   gst_clock_id_ref ((GstClockID) entry);
       
   521   /* insert the entry in sorted order */
       
   522   clock->entries = g_list_insert_sorted (clock->entries, entry,
       
   523       gst_clock_id_compare_func);
       
   524 
       
   525   /* only need to send the signal if the entry was added to the
       
   526    * front, else the thread is just waiting for another entry and
       
   527    * will get to this entry automatically. */
       
   528   if (clock->entries->data == entry) {
       
   529     GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry added to head, sending signal");
       
   530     /* this will wake up _all_ entries waiting for the clock because we have
       
   531      * only one cond for all entries (makes allocation faster). Entries that
       
   532      * have not timed out will have their status set to BUSY and should continue
       
   533      * to wait. In the case of the async ones, the new head entry should be
       
   534      * taken and waited for. */
       
   535     GST_CLOCK_BROADCAST (clock);
       
   536   }
       
   537   GST_OBJECT_UNLOCK (clock);
       
   538 
       
   539   return GST_CLOCK_OK;
       
   540 
       
   541 thread_error:
       
   542   /* Could not start the async clock thread */
       
   543   return GST_CLOCK_ERROR;
       
   544 }
       
   545 
       
   546 /* unschedule an entry. This will set the state of the entry to GST_CLOCK_UNSCHEDULED
       
   547  * and will signal any thread waiting for entries to recheck their entry.
       
   548  * We cannot really decide if the signal is needed or not because the entry
       
   549  * could be waited on in async or sync mode.
       
   550  *
       
   551  * MT safe.
       
   552  */
       
   553 static void
       
   554 gst_system_clock_id_unschedule (GstClock * clock, GstClockEntry * entry)
       
   555 {
       
   556   GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
       
   557 
       
   558   GST_OBJECT_LOCK (clock);
       
   559   /* mark entry as unscheduled, then wake up all entries. The entries that did
       
   560    * not timeout will be woken up but immediatly go to sleep again because their
       
   561    * status would still be busy. */
       
   562   entry->status = GST_CLOCK_UNSCHEDULED;
       
   563   GST_CAT_DEBUG (GST_CAT_CLOCK, "sending signal");
       
   564   GST_CLOCK_BROADCAST (clock);
       
   565   GST_OBJECT_UNLOCK (clock);
       
   566 }