gstreamer_core/gst/gstsystemclock.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
    38  * Last reviewed on 2006-03-08 (0.10.4)
    38  * Last reviewed on 2006-03-08 (0.10.4)
    39  */
    39  */
    40 
    40 
    41 #include "gst_private.h"
    41 #include "gst_private.h"
    42 #include "gstinfo.h"
    42 #include "gstinfo.h"
       
    43 
    43 #include "gstsystemclock.h"
    44 #include "gstsystemclock.h"
    44 #include "gstenumtypes.h"
       
    45 #include "gstpoll.h"
       
    46 
       
    47 #include <errno.h>
       
    48 
    45 
    49 #ifdef __SYMBIAN32__
    46 #ifdef __SYMBIAN32__
    50 #include <glib_global.h>
    47 #include <glib_global.h>
    51 #endif
    48 #endif
    52 
    49 
    53 /* Define this to get some extra debug about jitter from each clock_wait */
    50 /* Define this to get some extra debug about jitter from each clock_wait */
    54 #undef WAIT_DEBUGGING
    51 #undef WAIT_DEBUGGING
    55 
    52 
    56 struct _GstSystemClockPrivate
       
    57 {
       
    58   GstClockType clock_type;
       
    59   GstPoll *timer;
       
    60   gint wakeup_count;            /* the number of entries with a pending wakeup */
       
    61   gboolean async_wakeup;        /* if the wakeup was because of a async list change */
       
    62 };
       
    63 
       
    64 #define GST_SYSTEM_CLOCK_GET_PRIVATE(obj)  \
       
    65    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_SYSTEM_CLOCK, \
       
    66         GstSystemClockPrivate))
       
    67 
       
    68 #ifdef HAVE_POSIX_TIMERS
       
    69 # ifdef HAVE_MONOTONIC_CLOCK
       
    70 #  define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_MONOTONIC
       
    71 # else
       
    72 #  define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_REALTIME
       
    73 # endif
       
    74 #else
       
    75 #define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_REALTIME
       
    76 #endif
       
    77 
       
    78 enum
       
    79 {
       
    80   PROP_0,
       
    81   PROP_CLOCK_TYPE,
       
    82   /* FILL ME */
       
    83 };
       
    84 
       
    85 /* the one instance of the systemclock */
    53 /* the one instance of the systemclock */
    86 static GstClock *_the_system_clock = NULL;
    54 static GstClock *_the_system_clock = NULL;
    87 
    55 
    88 static void gst_system_clock_class_init (GstSystemClockClass * klass);
    56 static void gst_system_clock_class_init (GstSystemClockClass * klass);
    89 static void gst_system_clock_init (GstSystemClock * clock);
    57 static void gst_system_clock_init (GstSystemClock * clock);
    90 static void gst_system_clock_dispose (GObject * object);
    58 static void gst_system_clock_dispose (GObject * object);
    91 static void gst_system_clock_set_property (GObject * object, guint prop_id,
       
    92     const GValue * value, GParamSpec * pspec);
       
    93 static void gst_system_clock_get_property (GObject * object, guint prop_id,
       
    94     GValue * value, GParamSpec * pspec);
       
    95 
    59 
    96 static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
    60 static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
    97 static guint64 gst_system_clock_get_resolution (GstClock * clock);
    61 static guint64 gst_system_clock_get_resolution (GstClock * clock);
    98 static GstClockReturn gst_system_clock_id_wait_jitter (GstClock * clock,
    62 static GstClockReturn gst_system_clock_id_wait_jitter (GstClock * clock,
    99     GstClockEntry * entry, GstClockTimeDiff * jitter);
    63     GstClockEntry * entry, GstClockTimeDiff * jitter);
   104     GstClockEntry * entry);
    68     GstClockEntry * entry);
   105 static void gst_system_clock_id_unschedule (GstClock * clock,
    69 static void gst_system_clock_id_unschedule (GstClock * clock,
   106     GstClockEntry * entry);
    70     GstClockEntry * entry);
   107 static void gst_system_clock_async_thread (GstClock * clock);
    71 static void gst_system_clock_async_thread (GstClock * clock);
   108 static gboolean gst_system_clock_start_async (GstSystemClock * clock);
    72 static gboolean gst_system_clock_start_async (GstSystemClock * clock);
   109 static void gst_system_clock_add_wakeup (GstSystemClock * sysclock);
       
   110 
    73 
   111 static GStaticMutex _gst_sysclock_mutex = G_STATIC_MUTEX_INIT;
    74 static GStaticMutex _gst_sysclock_mutex = G_STATIC_MUTEX_INIT;
   112 
    75 
   113 static GstClockClass *parent_class = NULL;
    76 static GstClockClass *parent_class = NULL;
   114 
    77 
   115 /* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
    78 /* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
   116 
    79 #ifdef __SYMBIAN32__
   117 G_DEFINE_TYPE (GstSystemClock, gst_system_clock, GST_TYPE_CLOCK);
    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 }
   118 
   108 
   119 static void
   109 static void
   120 gst_system_clock_class_init (GstSystemClockClass * klass)
   110 gst_system_clock_class_init (GstSystemClockClass * klass)
   121 {
   111 {
   122   GObjectClass *gobject_class;
   112   GObjectClass *gobject_class;
       
   113   GstObjectClass *gstobject_class;
   123   GstClockClass *gstclock_class;
   114   GstClockClass *gstclock_class;
   124 
   115 
   125   gobject_class = (GObjectClass *) klass;
   116   gobject_class = (GObjectClass *) klass;
       
   117   gstobject_class = (GstObjectClass *) klass;
   126   gstclock_class = (GstClockClass *) klass;
   118   gstclock_class = (GstClockClass *) klass;
   127 
   119 
   128   parent_class = g_type_class_peek_parent (klass);
   120   parent_class = g_type_class_peek_parent (klass);
   129 
   121 
   130   g_type_class_add_private (klass, sizeof (GstSystemClockPrivate));
       
   131 
       
   132   gobject_class->dispose = gst_system_clock_dispose;
   122   gobject_class->dispose = gst_system_clock_dispose;
   133   gobject_class->set_property = gst_system_clock_set_property;
       
   134   gobject_class->get_property = gst_system_clock_get_property;
       
   135 
       
   136   g_object_class_install_property (gobject_class, PROP_CLOCK_TYPE,
       
   137       g_param_spec_enum ("clock-type", "Clock type",
       
   138           "The type of underlying clock implementation used",
       
   139           GST_TYPE_CLOCK_TYPE, DEFAULT_CLOCK_TYPE, G_PARAM_READWRITE));
       
   140 
   123 
   141   gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
   124   gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
   142   gstclock_class->get_resolution = gst_system_clock_get_resolution;
   125   gstclock_class->get_resolution = gst_system_clock_get_resolution;
   143   gstclock_class->wait_jitter = gst_system_clock_id_wait_jitter;
   126   gstclock_class->wait_jitter = gst_system_clock_id_wait_jitter;
   144   gstclock_class->wait_async = gst_system_clock_id_wait_async;
   127   gstclock_class->wait_async = gst_system_clock_id_wait_async;
   152       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
   135       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
   153       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
   136       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
   154       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
   137       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
   155       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
   138       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
   156 
   139 
   157   clock->priv = GST_SYSTEM_CLOCK_GET_PRIVATE (clock);
       
   158 
       
   159   clock->priv->clock_type = DEFAULT_CLOCK_TYPE;
       
   160   clock->priv->timer = gst_poll_new_timer ();
       
   161 
       
   162 #if 0
   140 #if 0
   163   /* Uncomment this to start the async clock thread straight away */
   141   /* Uncomment this to start the async clock thread straight away */
   164   GST_OBJECT_LOCK (clock);
   142   GST_CLOCK_LOCK (clock);
   165   gst_system_clock_start_async (clock);
   143   gst_system_clock_start_async (clock);
   166   GST_OBJECT_UNLOCK (clock);
   144   GST_CLOCK_UNLOCK (clock);
   167 #endif
   145 #endif
   168 }
   146 }
   169 
   147 
   170 static void
   148 static void
   171 gst_system_clock_dispose (GObject * object)
   149 gst_system_clock_dispose (GObject * object)
   172 {
   150 {
   173   GstClock *clock = (GstClock *) object;
   151   GstClock *clock = (GstClock *) object;
   174   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
   152 
       
   153   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
   175   GList *entries;
   154   GList *entries;
   176 
   155 
   177   /* else we have to stop the thread */
   156   /* else we have to stop the thread */
   178   GST_OBJECT_LOCK (clock);
   157   GST_OBJECT_LOCK (clock);
   179   sysclock->stopping = TRUE;
   158   sysclock->stopping = TRUE;
   185     entry->status = GST_CLOCK_UNSCHEDULED;
   164     entry->status = GST_CLOCK_UNSCHEDULED;
   186   }
   165   }
   187   g_list_free (clock->entries);
   166   g_list_free (clock->entries);
   188   clock->entries = NULL;
   167   clock->entries = NULL;
   189   GST_CLOCK_BROADCAST (clock);
   168   GST_CLOCK_BROADCAST (clock);
   190   gst_system_clock_add_wakeup (sysclock);
       
   191   GST_OBJECT_UNLOCK (clock);
   169   GST_OBJECT_UNLOCK (clock);
   192 
   170 
   193   if (sysclock->thread)
   171   if (sysclock->thread)
   194     g_thread_join (sysclock->thread);
   172     g_thread_join (sysclock->thread);
   195   sysclock->thread = NULL;
   173   sysclock->thread = NULL;
   196   GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
   174   GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
   197 
   175 
   198   gst_poll_free (sysclock->priv->timer);
       
   199 
       
   200   G_OBJECT_CLASS (parent_class)->dispose (object);
   176   G_OBJECT_CLASS (parent_class)->dispose (object);
   201 
   177 
   202   if (_the_system_clock == clock) {
   178   if (_the_system_clock == clock) {
   203     _the_system_clock = NULL;
   179     _the_system_clock = NULL;
   204     GST_CAT_DEBUG (GST_CAT_CLOCK, "disposed system clock");
   180     GST_CAT_DEBUG (GST_CAT_CLOCK, "disposed system clock");
   205   }
       
   206 }
       
   207 
       
   208 static void
       
   209 gst_system_clock_set_property (GObject * object, guint prop_id,
       
   210     const GValue * value, GParamSpec * pspec)
       
   211 {
       
   212   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (object);
       
   213 
       
   214   switch (prop_id) {
       
   215     case PROP_CLOCK_TYPE:
       
   216       sysclock->priv->clock_type = g_value_get_enum (value);
       
   217       GST_CAT_DEBUG (GST_CAT_CLOCK, "clock-type set to %d",
       
   218           sysclock->priv->clock_type);
       
   219       break;
       
   220     default:
       
   221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   222       break;
       
   223   }
       
   224 }
       
   225 
       
   226 static void
       
   227 gst_system_clock_get_property (GObject * object, guint prop_id, GValue * value,
       
   228     GParamSpec * pspec)
       
   229 {
       
   230   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (object);
       
   231 
       
   232   switch (prop_id) {
       
   233     case PROP_CLOCK_TYPE:
       
   234       g_value_set_enum (value, sysclock->priv->clock_type);
       
   235       break;
       
   236     default:
       
   237       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   238       break;
       
   239   }
   181   }
   240 }
   182 }
   241 
   183 
   242 /**
   184 /**
   243  * gst_system_clock_obtain:
   185  * gst_system_clock_obtain:
   267     clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
   209     clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
   268         "name", "GstSystemClock", NULL);
   210         "name", "GstSystemClock", NULL);
   269 
   211 
   270     /* we created the global clock; take ownership so
   212     /* we created the global clock; take ownership so
   271      * we can hand out instances later */
   213      * we can hand out instances later */
   272     gst_object_ref_sink (clock);
   214     gst_object_ref (clock);
       
   215     gst_object_sink (GST_OBJECT (clock));
   273 
   216 
   274     _the_system_clock = clock;
   217     _the_system_clock = clock;
   275     g_static_mutex_unlock (&_gst_sysclock_mutex);
   218     g_static_mutex_unlock (&_gst_sysclock_mutex);
   276   } else {
   219   } else {
   277     g_static_mutex_unlock (&_gst_sysclock_mutex);
   220     g_static_mutex_unlock (&_gst_sysclock_mutex);
   281   /* we ref it since we are a clock factory. */
   224   /* we ref it since we are a clock factory. */
   282   gst_object_ref (clock);
   225   gst_object_ref (clock);
   283   return clock;
   226   return clock;
   284 }
   227 }
   285 
   228 
   286 static void
       
   287 gst_system_clock_remove_wakeup (GstSystemClock * sysclock)
       
   288 {
       
   289   g_return_if_fail (sysclock->priv->wakeup_count > 0);
       
   290 
       
   291   sysclock->priv->wakeup_count--;
       
   292   if (sysclock->priv->wakeup_count == 0) {
       
   293     /* read the control socket byte when we removed the last wakeup count */
       
   294     GST_CAT_DEBUG (GST_CAT_CLOCK, "reading control");
       
   295     while (!gst_poll_read_control (sysclock->priv->timer)) {
       
   296       g_warning ("gstsystemclock: read control failed, trying again\n");
       
   297     }
       
   298     GST_CLOCK_BROADCAST (sysclock);
       
   299   }
       
   300   GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup count %d",
       
   301       sysclock->priv->wakeup_count);
       
   302 }
       
   303 
       
   304 static void
       
   305 gst_system_clock_add_wakeup (GstSystemClock * sysclock)
       
   306 {
       
   307   /* only write the control socket for the first wakeup */
       
   308   if (sysclock->priv->wakeup_count == 0) {
       
   309     GST_CAT_DEBUG (GST_CAT_CLOCK, "writing control");
       
   310     while (!gst_poll_write_control (sysclock->priv->timer)) {
       
   311       g_warning
       
   312           ("gstsystemclock: write control failed in wakeup_async, trying again : %d:%s\n",
       
   313           errno, g_strerror (errno));
       
   314     }
       
   315   }
       
   316   sysclock->priv->wakeup_count++;
       
   317   GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup count %d",
       
   318       sysclock->priv->wakeup_count);
       
   319 }
       
   320 
       
   321 static void
       
   322 gst_system_clock_wait_wakeup (GstSystemClock * sysclock)
       
   323 {
       
   324   while (sysclock->priv->wakeup_count > 0) {
       
   325     GST_CLOCK_WAIT (sysclock);
       
   326   }
       
   327 }
       
   328 
       
   329 /* this thread reads the sorted clock entries from the queue.
   229 /* this thread reads the sorted clock entries from the queue.
   330  *
   230  *
   331  * It waits on each of them and fires the callback when the timeout occurs.
   231  * It waits on each of them and fires the callback when the timeout occurs.
   332  *
   232  *
   333  * When an entry in the queue was canceled before we wait for it, it is
   233  * When an entry in the queue was canceled before we wait for it, it is
   339  * MT safe.
   239  * MT safe.
   340  */
   240  */
   341 static void
   241 static void
   342 gst_system_clock_async_thread (GstClock * clock)
   242 gst_system_clock_async_thread (GstClock * clock)
   343 {
   243 {
   344   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
   244   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
   345 
   245 
   346   GST_CAT_DEBUG (GST_CAT_CLOCK, "enter system clock thread");
   246   GST_CAT_DEBUG (GST_CAT_CLOCK, "enter system clock thread");
   347   GST_OBJECT_LOCK (clock);
   247   GST_OBJECT_LOCK (clock);
   348   /* signal spinup */
   248   /* signal spinup */
   349   GST_CLOCK_BROADCAST (clock);
   249   GST_CLOCK_BROADCAST (clock);
   362       /* clock was stopping, exit */
   262       /* clock was stopping, exit */
   363       if (sysclock->stopping)
   263       if (sysclock->stopping)
   364         goto exit;
   264         goto exit;
   365     }
   265     }
   366 
   266 
   367     /* see if we have a pending wakeup because the order of the list
       
   368      * changed. */
       
   369     if (sysclock->priv->async_wakeup) {
       
   370       GST_CAT_DEBUG (GST_CAT_CLOCK, "clear async wakeup");
       
   371       gst_system_clock_remove_wakeup (sysclock);
       
   372       sysclock->priv->async_wakeup = FALSE;
       
   373     }
       
   374 
       
   375     /* pick the next entry */
   267     /* pick the next entry */
   376     entry = clock->entries->data;
   268     entry = clock->entries->data;
   377     /* if it was unscheduled, just move on to the next entry */
   269     /* if it was unscheduled, just move on to the next entry */
   378     if (entry->status == GST_CLOCK_UNSCHEDULED) {
   270     if (entry->status == GST_CLOCK_UNSCHEDULED) {
   379       GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p was unscheduled", entry);
   271       GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p was unscheduled", entry);
   395       case GST_CLOCK_OK:
   287       case GST_CLOCK_OK:
   396       case GST_CLOCK_EARLY:
   288       case GST_CLOCK_EARLY:
   397       {
   289       {
   398         /* entry timed out normally, fire the callback and move to the next
   290         /* entry timed out normally, fire the callback and move to the next
   399          * entry */
   291          * entry */
   400         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p timed out", entry);
   292         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unlocked", entry);
   401         if (entry->func) {
   293         if (entry->func) {
   402           /* unlock before firing the callback */
   294           /* unlock before firing the callback */
   403           GST_OBJECT_UNLOCK (clock);
   295           GST_OBJECT_UNLOCK (clock);
   404           entry->func (clock, entry->time, (GstClockID) entry,
   296           entry->func (clock, entry->time, (GstClockID) entry,
   405               entry->user_data);
   297               entry->user_data);
   406           GST_OBJECT_LOCK (clock);
   298           GST_OBJECT_LOCK (clock);
   407         }
   299         }
   408         if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
   300         if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
   409           GST_CAT_DEBUG (GST_CAT_CLOCK, "updating periodic entry %p", entry);
       
   410           /* adjust time now */
   301           /* adjust time now */
   411           entry->time = requested + entry->interval;
   302           entry->time = requested + entry->interval;
   412           /* and resort the list now */
   303           /* and resort the list now */
   413           clock->entries =
   304           clock->entries =
   414               g_list_sort (clock->entries, gst_clock_id_compare_func);
   305               g_list_sort (clock->entries, gst_clock_id_compare_func);
   415           /* and restart */
   306           /* and restart */
   416           continue;
   307           continue;
   417         } else {
   308         } else {
   418           GST_CAT_DEBUG (GST_CAT_CLOCK, "moving to next entry");
       
   419           goto next_entry;
   309           goto next_entry;
   420         }
   310         }
   421       }
   311       }
   422       case GST_CLOCK_BUSY:
   312       case GST_CLOCK_BUSY:
   423         /* somebody unlocked the entry but is was not canceled, This means that
   313         /* somebody unlocked the entry but is was not canceled, This means that
   424          * either a new entry was added in front of the queue or some other entry
   314          * either a new entry was added in front of the queue or some other entry
   425          * was canceled. Whatever it is, pick the head entry of the list and
   315          * was canceled. Whatever it is, pick the head entry of the list and
   426          * continue waiting. */
   316          * continue waiting. */
   427         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p needs restart", entry);
   317         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p needs restart", entry);
   428 
       
   429         /* we set the entry back to the OK state. This is needed so that the
       
   430          * _unschedule() code can see if an entry is currently being waited
       
   431          * on (when its state is BUSY). */
       
   432         entry->status = GST_CLOCK_OK;
       
   433         continue;
   318         continue;
   434       default:
   319       default:
   435         GST_CAT_DEBUG (GST_CAT_CLOCK,
   320         GST_CAT_DEBUG (GST_CAT_CLOCK,
   436             "strange result %d waiting for %p, skipping", res, entry);
   321             "strange result %d waiting for %p, skipping", res, entry);
   437         g_warning ("%s: strange result %d waiting for %p, skipping",
   322         g_warning ("%s: strange result %d waiting for %p, skipping",
   448   GST_CLOCK_BROADCAST (clock);
   333   GST_CLOCK_BROADCAST (clock);
   449   GST_OBJECT_UNLOCK (clock);
   334   GST_OBJECT_UNLOCK (clock);
   450   GST_CAT_DEBUG (GST_CAT_CLOCK, "exit system clock thread");
   335   GST_CAT_DEBUG (GST_CAT_CLOCK, "exit system clock thread");
   451 }
   336 }
   452 
   337 
   453 #ifdef HAVE_POSIX_TIMERS
       
   454 static inline clockid_t
       
   455 clock_type_to_posix_id (GstClockType clock_type)
       
   456 {
       
   457 #ifdef HAVE_MONOTONIC_CLOCK
       
   458   if (clock_type == GST_CLOCK_TYPE_MONOTONIC)
       
   459     return CLOCK_MONOTONIC;
       
   460   else
       
   461 #endif
       
   462     return CLOCK_REALTIME;
       
   463 }
       
   464 #endif
       
   465 
       
   466 /* MT safe */
   338 /* MT safe */
   467 static GstClockTime
   339 static GstClockTime
   468 gst_system_clock_get_internal_time (GstClock * clock)
   340 gst_system_clock_get_internal_time (GstClock * clock)
   469 {
   341 {
   470 #ifdef HAVE_POSIX_TIMERS
       
   471   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
       
   472   clockid_t ptype;
       
   473   struct timespec ts;
       
   474 
       
   475   ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
       
   476 
       
   477   if (G_UNLIKELY (clock_gettime (ptype, &ts)))
       
   478     return GST_CLOCK_TIME_NONE;
       
   479 
       
   480   return GST_TIMESPEC_TO_TIME (ts);
       
   481 #else
       
   482   GTimeVal timeval;
   342   GTimeVal timeval;
   483 
   343 
   484   g_get_current_time (&timeval);
   344   g_get_current_time (&timeval);
   485 
   345 
   486   return GST_TIMEVAL_TO_TIME (timeval);
   346   return GST_TIMEVAL_TO_TIME (timeval);
   487 #endif
       
   488 }
   347 }
   489 
   348 
   490 static guint64
   349 static guint64
   491 gst_system_clock_get_resolution (GstClock * clock)
   350 gst_system_clock_get_resolution (GstClock * clock)
   492 {
   351 {
   493 #ifdef HAVE_POSIX_TIMERS
       
   494   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
       
   495   clockid_t ptype;
       
   496   struct timespec ts;
       
   497 
       
   498   ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
       
   499 
       
   500   if (G_UNLIKELY (clock_getres (ptype, &ts)))
       
   501     return GST_CLOCK_TIME_NONE;
       
   502 
       
   503   return GST_TIMESPEC_TO_TIME (ts);
       
   504 #else
       
   505   return 1 * GST_USECOND;
   352   return 1 * GST_USECOND;
   506 #endif
       
   507 }
   353 }
   508 
   354 
   509 /* synchronously wait on the given GstClockEntry.
   355 /* synchronously wait on the given GstClockEntry.
   510  *
   356  *
   511  * We do this by blocking on the global clock GCond variable with
   357  * We do this by blocking on the global clock GCond variable with
   524  */
   370  */
   525 static GstClockReturn
   371 static GstClockReturn
   526 gst_system_clock_id_wait_jitter_unlocked (GstClock * clock,
   372 gst_system_clock_id_wait_jitter_unlocked (GstClock * clock,
   527     GstClockEntry * entry, GstClockTimeDiff * jitter, gboolean restart)
   373     GstClockEntry * entry, GstClockTimeDiff * jitter, gboolean restart)
   528 {
   374 {
   529   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
   375   GstClockTime entryt, real, now, target;
   530   GstClockTime entryt, real, now;
       
   531   GstClockTimeDiff diff;
   376   GstClockTimeDiff diff;
   532 
   377 
   533   /* need to call the overridden method because we want to sync against the time
   378   /* need to call the overridden method because we want to sync against the time
   534    * of the clock, whatever the subclass uses as a clock. */
   379    * of the clock, whatever the subclass uses as a clock. */
   535   real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
   380   real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
       
   381   entryt = GST_CLOCK_ENTRY_TIME (entry);
       
   382 
   536   now = gst_clock_adjust_unlocked (clock, real);
   383   now = gst_clock_adjust_unlocked (clock, real);
   537 
       
   538   /* get the time of the entry */
       
   539   entryt = GST_CLOCK_ENTRY_TIME (entry);
       
   540 
       
   541   if (jitter) {
   384   if (jitter) {
   542     *jitter = GST_CLOCK_DIFF (entryt, now);
   385     *jitter = GST_CLOCK_DIFF (entryt, now);
   543   }
   386   }
   544   /* the diff of the entry with the clock is the amount of time we have to
   387   /* the diff of the entry with the clock is the amount of time we have to
   545    * wait */
   388    * wait */
   546   diff = entryt - now;
   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;
   547 
   395 
   548   GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p"
   396   GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p"
   549       " time %" GST_TIME_FORMAT
   397       " target %" GST_TIME_FORMAT
       
   398       " entry %" GST_TIME_FORMAT
   550       " now %" GST_TIME_FORMAT
   399       " now %" GST_TIME_FORMAT
   551       " real %" GST_TIME_FORMAT
   400       " real %" GST_TIME_FORMAT
   552       " diff (time-now) %" G_GINT64_FORMAT,
   401       " diff (entry-now) %" G_GINT64_FORMAT,
   553       entry,
   402       entry,
       
   403       GST_TIME_ARGS (target),
   554       GST_TIME_ARGS (entryt), GST_TIME_ARGS (now), GST_TIME_ARGS (real), diff);
   404       GST_TIME_ARGS (entryt), GST_TIME_ARGS (now), GST_TIME_ARGS (real), diff);
   555 
   405 
   556   if (diff > 0) {
   406   if (diff > 0) {
       
   407     GTimeVal tv;
       
   408 
   557 #ifdef WAIT_DEBUGGING
   409 #ifdef WAIT_DEBUGGING
   558     GstClockTime final;
   410     GstClockTime result, final;
   559 #endif
   411 #endif
   560 
   412 
   561     while (entry->status != GST_CLOCK_UNSCHEDULED) {
   413     GST_TIME_TO_TIMEVAL (target, tv);
   562       gint pollret;
   414 
   563 
   415     while (TRUE) {
   564       /* mark the entry as busy */
   416       /* now wait on the entry, it either times out or the cond is signaled. */
   565       entry->status = GST_CLOCK_BUSY;
   417       if (!GST_CLOCK_TIMED_WAIT (clock, &tv)) {
   566       GST_OBJECT_UNLOCK (clock);
   418         /* timeout, this is fine, we can report success now */
   567 
   419         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked after timeout", entry);
   568       /* now wait on the entry, it either times out or the fd is written. */
   420         entry->status = GST_CLOCK_OK;
   569       pollret = gst_poll_wait (sysclock->priv->timer, diff);
   421 
   570 
   422 #ifdef WAIT_DEBUGGING
   571       /* another thread can read the fd before we get the lock */
   423         real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
   572       GST_OBJECT_LOCK (clock);
   424         result = gst_clock_adjust_unlocked (clock, real);
   573       if (entry->status == GST_CLOCK_UNSCHEDULED) {
   425         final = gst_system_clock_get_internal_time (clock);
   574         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked", entry);
   426         GST_CAT_DEBUG (GST_CAT_CLOCK, "Waited for %" G_GINT64_FORMAT
   575         gst_system_clock_remove_wakeup (sysclock);
   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;
   576       } else {
   435       } else {
   577         if (pollret != 0) {
   436         /* the waiting is interrupted because the GCond was signaled. This can
   578           /* some other id got unlocked */
   437          * be because this or some other entry was unscheduled. */
   579           if (!restart) {
   438         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked with signal", entry);
   580             /* this can happen if the entry got unlocked because of an async
   439         /* if the entry is unscheduled, we can stop waiting for it, else we
   581              * entry was added to the head of the async queue. */
   440          * continue our while loop. */
   582             GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup waiting for entry %p", entry);
   441         if (entry->status == GST_CLOCK_UNSCHEDULED)
   583             break;
       
   584           }
       
   585 
       
   586           /* mark ourselves as EARLY, we release the lock and we could be
       
   587            * unscheduled ourselves but we don't want the unscheduling thread
       
   588            * to write on the control socket (it does that when an entry has a
       
   589            * BUSY status). */
       
   590           entry->status = GST_CLOCK_EARLY;
       
   591 
       
   592           /* wait till all the entries got woken up */
       
   593           gst_system_clock_wait_wakeup (sysclock);
       
   594 
       
   595           /* we released the lock in the wait, recheck our status, we don't need
       
   596            * to remove the wakeup count because we marked the entry as EARLY
       
   597            * before releasing the object lock. */
       
   598           if (entry->status == GST_CLOCK_UNSCHEDULED) {
       
   599             GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p got unscheduled", entry);
       
   600             break;
       
   601           }
       
   602 
       
   603           GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p needs to be restarted",
       
   604               entry);
       
   605         } else {
       
   606           GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked after timeout",
       
   607               entry);
       
   608         }
       
   609 
       
   610         /* reschedule if gst_poll_wait returned early or we have to reschedule after
       
   611          * an unlock*/
       
   612         real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
       
   613         now = gst_clock_adjust_unlocked (clock, real);
       
   614         diff = entryt - now;
       
   615 
       
   616         if (diff <= 0) {
       
   617           /* timeout, this is fine, we can report success now */
       
   618           entry->status = GST_CLOCK_OK;
       
   619 
       
   620           GST_CAT_DEBUG (GST_CAT_CLOCK,
       
   621               "entry %p finished, diff %" G_GINT64_FORMAT, entry, diff);
       
   622 
       
   623 #ifdef WAIT_DEBUGGING
       
   624           final = gst_system_clock_get_internal_time (clock);
       
   625           GST_CAT_DEBUG (GST_CAT_CLOCK, "Waited for %" G_GINT64_FORMAT
       
   626               " got %" G_GINT64_FORMAT " diff %" G_GINT64_FORMAT
       
   627               " %g target-offset %" G_GINT64_FORMAT " %g", entryt, now,
       
   628               now - entryt,
       
   629               (double) (GstClockTimeDiff) (now - entryt) / GST_SECOND,
       
   630               (final - target),
       
   631               ((double) (GstClockTimeDiff) (final - target)) / GST_SECOND);
       
   632 #endif
       
   633           break;
   442           break;
   634         } else {
   443         /* else restart if we must */
   635           GST_CAT_DEBUG (GST_CAT_CLOCK,
   444         if (!restart)
   636               "entry %p restart, diff %" G_GINT64_FORMAT, entry, diff);
   445           break;
   637         }
   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);
   638       }
   450       }
   639     }
   451     }
   640   } else if (diff == 0) {
   452   } else if (diff == 0) {
   641     entry->status = GST_CLOCK_OK;
   453     entry->status = GST_CLOCK_OK;
   642   } else {
   454   } else {
   650     GstClockTimeDiff * jitter)
   462     GstClockTimeDiff * jitter)
   651 {
   463 {
   652   GstClockReturn ret;
   464   GstClockReturn ret;
   653 
   465 
   654   GST_OBJECT_LOCK (clock);
   466   GST_OBJECT_LOCK (clock);
   655   if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
       
   656     goto was_unscheduled;
       
   657 
       
   658   ret = gst_system_clock_id_wait_jitter_unlocked (clock, entry, jitter, TRUE);
   467   ret = gst_system_clock_id_wait_jitter_unlocked (clock, entry, jitter, TRUE);
   659   GST_OBJECT_UNLOCK (clock);
   468   GST_OBJECT_UNLOCK (clock);
   660 
   469 
   661   return ret;
   470   return ret;
   662 
       
   663   /* ERRORS */
       
   664 was_unscheduled:
       
   665   {
       
   666     GST_OBJECT_UNLOCK (clock);
       
   667     return GST_CLOCK_UNSCHEDULED;
       
   668   }
       
   669 }
   471 }
   670 
   472 
   671 /* Start the async clock thread. Must be called with the object lock
   473 /* Start the async clock thread. Must be called with the object lock
   672  * held */
   474  * held */
   673 static gboolean
   475 static gboolean
   674 gst_system_clock_start_async (GstSystemClock * clock)
   476 gst_system_clock_start_async (GstSystemClock * clock)
   675 {
   477 {
   676   GError *error = NULL;
   478   GError *error = NULL;
   677 
   479 
   678   if (G_LIKELY (clock->thread != NULL))
   480   if (clock->thread != NULL)
   679     return TRUE;                /* Thread already running. Nothing to do */
   481     return TRUE;                /* Thread already running. Nothing to do */
   680 
   482 
   681   clock->thread = g_thread_create ((GThreadFunc) gst_system_clock_async_thread,
   483   clock->thread = g_thread_create ((GThreadFunc) gst_system_clock_async_thread,
   682       clock, TRUE, &error);
   484       clock, TRUE, &error);
   683   if (G_UNLIKELY (error))
   485   if (error)
   684     goto no_thread;
   486     goto no_thread;
   685 
   487 
   686   /* wait for it to spin up */
   488   /* wait for it to spin up */
   687   GST_CLOCK_WAIT (clock);
   489   GST_CLOCK_WAIT (clock);
   688 
   490 
   690 
   492 
   691   /* ERRORS */
   493   /* ERRORS */
   692 no_thread:
   494 no_thread:
   693   {
   495   {
   694     g_warning ("could not create async clock thread: %s", error->message);
   496     g_warning ("could not create async clock thread: %s", error->message);
   695     g_error_free (error);
       
   696   }
   497   }
   697   return FALSE;
   498   return FALSE;
   698 }
   499 }
   699 
   500 
   700 /* Add an entry to the list of pending async waits. The entry is inserted
   501 /* Add an entry to the list of pending async waits. The entry is inserted
   705  * MT safe.
   506  * MT safe.
   706  */
   507  */
   707 static GstClockReturn
   508 static GstClockReturn
   708 gst_system_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
   509 gst_system_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
   709 {
   510 {
   710   GstSystemClock *sysclock;
       
   711   GstClockEntry *head;
       
   712 
       
   713   sysclock = GST_SYSTEM_CLOCK_CAST (clock);
       
   714 
       
   715   GST_CAT_DEBUG (GST_CAT_CLOCK, "adding async entry %p", entry);
   511   GST_CAT_DEBUG (GST_CAT_CLOCK, "adding async entry %p", entry);
   716 
   512 
   717   GST_OBJECT_LOCK (clock);
   513   GST_OBJECT_LOCK (clock);
       
   514 
   718   /* Start the clock async thread if needed */
   515   /* Start the clock async thread if needed */
   719   if (G_UNLIKELY (!gst_system_clock_start_async (sysclock)))
   516   if (!gst_system_clock_start_async (GST_SYSTEM_CLOCK (clock)))
   720     goto thread_error;
   517     goto thread_error;
   721 
       
   722   if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
       
   723     goto was_unscheduled;
       
   724 
       
   725   if (clock->entries)
       
   726     head = clock->entries->data;
       
   727   else
       
   728     head = NULL;
       
   729 
   518 
   730   /* need to take a ref */
   519   /* need to take a ref */
   731   gst_clock_id_ref ((GstClockID) entry);
   520   gst_clock_id_ref ((GstClockID) entry);
   732   /* insert the entry in sorted order */
   521   /* insert the entry in sorted order */
   733   clock->entries = g_list_insert_sorted (clock->entries, entry,
   522   clock->entries = g_list_insert_sorted (clock->entries, entry,
   735 
   524 
   736   /* only need to send the signal if the entry was added to the
   525   /* only need to send the signal if the entry was added to the
   737    * front, else the thread is just waiting for another entry and
   526    * front, else the thread is just waiting for another entry and
   738    * will get to this entry automatically. */
   527    * will get to this entry automatically. */
   739   if (clock->entries->data == entry) {
   528   if (clock->entries->data == entry) {
   740     GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry added to head");
   529     GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry added to head, sending signal");
   741     if (head == NULL) {
   530     /* this will wake up _all_ entries waiting for the clock because we have
   742       /* the list was empty before, signal the cond so that the async thread can
   531      * only one cond for all entries (makes allocation faster). Entries that
   743        * start taking a look at the queue */
   532      * have not timed out will have their status set to BUSY and should continue
   744       GST_CAT_DEBUG (GST_CAT_CLOCK, "first entry, sending signal");
   533      * to wait. In the case of the async ones, the new head entry should be
   745       GST_CLOCK_BROADCAST (clock);
   534      * taken and waited for. */
   746     } else {
   535     GST_CLOCK_BROADCAST (clock);
   747       if (head->status == GST_CLOCK_BUSY) {
       
   748         /* the async thread was waiting for an entry, unlock the wait so that it
       
   749          * looks at the new head entry instead, we only need to do this once */
       
   750         if (!sysclock->priv->async_wakeup) {
       
   751           GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup async thread");
       
   752           sysclock->priv->async_wakeup = TRUE;
       
   753           gst_system_clock_add_wakeup (sysclock);
       
   754         }
       
   755       }
       
   756     }
       
   757   }
   536   }
   758   GST_OBJECT_UNLOCK (clock);
   537   GST_OBJECT_UNLOCK (clock);
   759 
   538 
   760   return GST_CLOCK_OK;
   539   return GST_CLOCK_OK;
   761 
   540 
   762   /* ERRORS */
       
   763 thread_error:
   541 thread_error:
   764   {
   542   /* Could not start the async clock thread */
   765     /* Could not start the async clock thread */
   543   return GST_CLOCK_ERROR;
   766     GST_OBJECT_UNLOCK (clock);
       
   767     return GST_CLOCK_ERROR;
       
   768   }
       
   769 was_unscheduled:
       
   770   {
       
   771     GST_OBJECT_UNLOCK (clock);
       
   772     return GST_CLOCK_UNSCHEDULED;
       
   773   }
       
   774 }
   544 }
   775 
   545 
   776 /* unschedule an entry. This will set the state of the entry to GST_CLOCK_UNSCHEDULED
   546 /* unschedule an entry. This will set the state of the entry to GST_CLOCK_UNSCHEDULED
   777  * and will signal any thread waiting for entries to recheck their entry.
   547  * and will signal any thread waiting for entries to recheck their entry.
   778  * We cannot really decide if the signal is needed or not because the entry
   548  * We cannot really decide if the signal is needed or not because the entry
   781  * MT safe.
   551  * MT safe.
   782  */
   552  */
   783 static void
   553 static void
   784 gst_system_clock_id_unschedule (GstClock * clock, GstClockEntry * entry)
   554 gst_system_clock_id_unschedule (GstClock * clock, GstClockEntry * entry)
   785 {
   555 {
   786   GstSystemClock *sysclock;
       
   787 
       
   788   sysclock = GST_SYSTEM_CLOCK_CAST (clock);
       
   789 
       
   790   GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
   556   GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
   791 
   557 
   792   GST_OBJECT_LOCK (clock);
   558   GST_OBJECT_LOCK (clock);
   793   if (entry->status == GST_CLOCK_BUSY) {
   559   /* mark entry as unscheduled, then wake up all entries. The entries that did
   794     /* the entry was being busy, wake up all entries so that they recheck their
   560    * not timeout will be woken up but immediatly go to sleep again because their
   795      * status. We cannot wake up just one entry because allocating such a
   561    * status would still be busy. */
   796      * datastructure for each entry would be too heavy and unlocking an entry
       
   797      * is usually done when shutting down or some other exceptional case. */
       
   798     GST_CAT_DEBUG (GST_CAT_CLOCK, "entry was BUSY, doing wakeup");
       
   799     gst_system_clock_add_wakeup (sysclock);
       
   800   }
       
   801   /* when it leaves the poll, it'll detect the unscheduled */
       
   802   entry->status = GST_CLOCK_UNSCHEDULED;
   562   entry->status = GST_CLOCK_UNSCHEDULED;
       
   563   GST_CAT_DEBUG (GST_CAT_CLOCK, "sending signal");
       
   564   GST_CLOCK_BROADCAST (clock);
   803   GST_OBJECT_UNLOCK (clock);
   565   GST_OBJECT_UNLOCK (clock);
   804 }
   566 }