Test that removing probes from within the probe functions works.
[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  * SECTION:gstsystemclock
24  * @short_description: Default clock that uses the current system time
25  * @see_also: #GstClock
26  *
27  * The System clock is an implementation of GstClock using the system time.
28  */
29
30 #include "gst_private.h"
31 #include "gstinfo.h"
32
33 #include "gstsystemclock.h"
34
35 /* the one instance of the systemclock */
36 static GstClock *_the_system_clock = NULL;
37
38 static void gst_system_clock_class_init (GstSystemClockClass * klass);
39 static void gst_system_clock_init (GstSystemClock * clock);
40 static void gst_system_clock_dispose (GObject * object);
41
42 static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
43 static guint64 gst_system_clock_get_resolution (GstClock * clock);
44 static GstClockReturn gst_system_clock_id_wait (GstClock * clock,
45     GstClockEntry * entry);
46 static GstClockReturn gst_system_clock_id_wait_unlocked
47     (GstClock * clock, GstClockEntry * entry);
48 static GstClockReturn gst_system_clock_id_wait_async (GstClock * clock,
49     GstClockEntry * entry);
50 static void gst_system_clock_id_unschedule (GstClock * clock,
51     GstClockEntry * entry);
52 static void gst_system_clock_async_thread (GstClock * clock);
53
54 static GStaticMutex _gst_sysclock_mutex = G_STATIC_MUTEX_INIT;
55
56 static GstClockClass *parent_class = NULL;
57
58 /* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
59
60 GType
61 gst_system_clock_get_type (void)
62 {
63   static GType clock_type = 0;
64
65   if (!clock_type) {
66     static const GTypeInfo clock_info = {
67       sizeof (GstSystemClockClass),
68       NULL,
69       NULL,
70       (GClassInitFunc) gst_system_clock_class_init,
71       NULL,
72       NULL,
73       sizeof (GstSystemClock),
74       0,
75       (GInstanceInitFunc) gst_system_clock_init,
76       NULL
77     };
78
79     clock_type = g_type_register_static (GST_TYPE_CLOCK, "GstSystemClock",
80         &clock_info, 0);
81   }
82   return clock_type;
83 }
84
85 static void
86 gst_system_clock_class_init (GstSystemClockClass * klass)
87 {
88   GObjectClass *gobject_class;
89   GstObjectClass *gstobject_class;
90   GstClockClass *gstclock_class;
91
92   gobject_class = (GObjectClass *) klass;
93   gstobject_class = (GstObjectClass *) klass;
94   gstclock_class = (GstClockClass *) klass;
95
96   parent_class = g_type_class_ref (GST_TYPE_CLOCK);
97
98   gobject_class->dispose = gst_system_clock_dispose;
99
100   gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
101   gstclock_class->get_resolution = gst_system_clock_get_resolution;
102   gstclock_class->wait = gst_system_clock_id_wait;
103   gstclock_class->wait_async = gst_system_clock_id_wait_async;
104   gstclock_class->unschedule = gst_system_clock_id_unschedule;
105 }
106
107 static void
108 gst_system_clock_init (GstSystemClock * clock)
109 {
110   GError *error = NULL;
111
112   GST_CLOCK_FLAGS (clock) =
113       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
114       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
115       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
116       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC;
117
118   GST_LOCK (clock);
119   clock->thread = g_thread_create ((GThreadFunc) gst_system_clock_async_thread,
120       clock, TRUE, &error);
121   if (error)
122     goto no_thread;
123
124   /* wait for it to spin up */
125   GST_CLOCK_WAIT (clock);
126   GST_UNLOCK (clock);
127   return;
128
129 no_thread:
130   {
131     g_warning ("could not create async clock thread: %s", error->message);
132     GST_UNLOCK (clock);
133   }
134 }
135
136 static void
137 gst_system_clock_dispose (GObject * object)
138 {
139   GstClock *clock = (GstClock *) object;
140
141   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
142   GList *entries;
143
144   /* else we have to stop the thread */
145   GST_LOCK (clock);
146   sysclock->stopping = TRUE;
147   /* unschedule all entries */
148   for (entries = clock->entries; entries; entries = g_list_next (entries)) {
149     GstClockEntry *entry = (GstClockEntry *) entries->data;
150
151     GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
152     entry->status = GST_CLOCK_UNSCHEDULED;
153   }
154   g_list_free (clock->entries);
155   clock->entries = NULL;
156   GST_CLOCK_BROADCAST (clock);
157   GST_UNLOCK (clock);
158
159   if (sysclock->thread)
160     g_thread_join (sysclock->thread);
161   sysclock->thread = NULL;
162   GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
163
164   G_OBJECT_CLASS (parent_class)->dispose (object);
165
166   if (_the_system_clock == clock) {
167     _the_system_clock = NULL;
168     GST_CAT_DEBUG (GST_CAT_CLOCK, "disposed system clock");
169   }
170 }
171
172 /**
173  * gst_system_clock_obtain:
174  *
175  * Get a handle to the default system clock. The refcount of the
176  * clock will be increased so you need to unref the clock after
177  * usage.
178  *
179  * Returns: the default clock.
180  *
181  * MT safe.
182  */
183 GstClock *
184 gst_system_clock_obtain (void)
185 {
186   GstClock *clock;
187
188   g_static_mutex_lock (&_gst_sysclock_mutex);
189   clock = _the_system_clock;
190
191   if (clock == NULL) {
192     GST_CAT_DEBUG (GST_CAT_CLOCK, "creating new static system clock");
193     clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
194         "name", "GstSystemClock", NULL);
195
196     /* we created the global clock; take ownership so
197      * we can hand out instances later */
198     gst_object_ref (clock);
199     gst_object_sink (GST_OBJECT (clock));
200
201     _the_system_clock = clock;
202     g_static_mutex_unlock (&_gst_sysclock_mutex);
203   } else {
204     g_static_mutex_unlock (&_gst_sysclock_mutex);
205     GST_CAT_DEBUG (GST_CAT_CLOCK, "returning static system clock");
206   }
207
208   /* we ref it since we are a clock factory. */
209   gst_object_ref (clock);
210   return clock;
211 }
212
213 /* this thread reads the sorted clock entries from the queue. 
214  *
215  * It waits on each of them and fires the callback when the timeout occurs.
216  *
217  * When an entry in the queue was canceled, it is simply skipped.
218  *
219  * When waiting for an entry, it can become canceled, in that case we don't 
220  * call the callback but move to the next item in the queue.
221  *
222  * MT safe.
223  */
224 static void
225 gst_system_clock_async_thread (GstClock * clock)
226 {
227   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
228
229   GST_CAT_DEBUG (GST_CAT_CLOCK, "enter system clock thread");
230   GST_LOCK (clock);
231   /* signal spinup */
232   GST_CLOCK_BROADCAST (clock);
233   /* now enter our infinite loop */
234   while (!sysclock->stopping) {
235     GstClockEntry *entry;
236     GstClockReturn res;
237
238     /* check if something to be done */
239     while (clock->entries == NULL) {
240       GST_CAT_DEBUG (GST_CAT_CLOCK, "nothing to wait for");
241       /* wait for work to do */
242       GST_CLOCK_WAIT (clock);
243       GST_CAT_DEBUG (GST_CAT_CLOCK, "got signal");
244       /* clock was stopping, exit */
245       if (sysclock->stopping)
246         goto exit;
247     }
248
249     /* pick the next entry */
250     entry = clock->entries->data;
251     /* if it was unscheduled, just move on to the next entry */
252     if (entry->status == GST_CLOCK_UNSCHEDULED) {
253       GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p was unscheduled", entry);
254       goto next_entry;
255     }
256
257     /* now wait for the entry, we already hold the lock */
258     res = gst_system_clock_id_wait_unlocked (clock, (GstClockID) entry);
259
260     switch (res) {
261       case GST_CLOCK_UNSCHEDULED:
262         /* entry was unscheduled, move to the next */
263         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unscheduled", entry);
264         goto next_entry;
265       case GST_CLOCK_OK:
266       case GST_CLOCK_EARLY:
267       {
268         /* entry timed out normally, fire the callback and move to the next
269          * entry */
270         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unlocked", entry);
271         if (entry->func) {
272           entry->func (clock, entry->time, (GstClockID) entry,
273               entry->user_data);
274         }
275         if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
276           /* adjust time now */
277           entry->time += entry->interval;
278           /* and resort the list now */
279           clock->entries =
280               g_list_sort (clock->entries, gst_clock_id_compare_func);
281           /* and restart */
282           continue;
283         } else {
284           goto next_entry;
285         }
286       }
287       case GST_CLOCK_BUSY:
288         /* somebody unlocked the entry but is was not canceled, This means that
289          * either a new entry was added in front of the queue or some other entry 
290          * was canceled. Whatever it is, pick the head entry of the list and
291          * continue waiting. */
292         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p needs restart", entry);
293         continue;
294       default:
295         GST_CAT_DEBUG (GST_CAT_CLOCK,
296             "strange result %d waiting for %p, skipping", res, entry);
297         goto next_entry;
298     }
299   next_entry:
300     /* we remove the current entry and unref it */
301     clock->entries = g_list_remove (clock->entries, entry);
302     gst_clock_id_unref ((GstClockID) entry);
303   }
304 exit:
305   /* signal exit */
306   GST_CLOCK_BROADCAST (clock);
307   GST_UNLOCK (clock);
308   GST_CAT_DEBUG (GST_CAT_CLOCK, "exit system clock thread");
309 }
310
311 /* MT safe */
312 static GstClockTime
313 gst_system_clock_get_internal_time (GstClock * clock)
314 {
315   GTimeVal timeval;
316
317   g_get_current_time (&timeval);
318
319   return GST_TIMEVAL_TO_TIME (timeval);
320 }
321
322 static guint64
323 gst_system_clock_get_resolution (GstClock * clock)
324 {
325   return 1 * GST_USECOND;
326 }
327
328 /* synchronously wait on the given GstClockEntry.
329  *
330  * We do this by blocking on the global clock GCond variable with
331  * the requested time as a timeout. This allows us to unblock the
332  * entry by signaling the GCond variable.
333  *
334  * Note that signaling the global GCond unlocks all waiting entries. So
335  * we need to check if an unlocked entry has changed when it unlocks.
336  *
337  * Entries that arrive too late are simply not waited on and a
338  * GST_CLOCK_EARLY result is returned.
339  *
340  * MT safe.
341  */
342 static GstClockReturn
343 gst_system_clock_id_wait_unlocked (GstClock * clock, GstClockEntry * entry)
344 {
345   GstClockTime entryt, real, now, target;
346   GstClockTimeDiff diff;
347
348   /* need to call the overridden method */
349   real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
350   entryt = GST_CLOCK_ENTRY_TIME (entry);
351
352   now = gst_clock_adjust_unlocked (clock, real);
353   diff = entryt - now;
354   target = gst_system_clock_get_internal_time (clock) + diff;
355
356   GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p"
357       " target %" GST_TIME_FORMAT
358       " entry %" GST_TIME_FORMAT
359       " now %" GST_TIME_FORMAT
360       " real %" GST_TIME_FORMAT
361       " diff %" G_GINT64_FORMAT,
362       entry,
363       GST_TIME_ARGS (target),
364       GST_TIME_ARGS (entryt), GST_TIME_ARGS (now), GST_TIME_ARGS (real), diff);
365
366   if (diff > 0) {
367     GTimeVal tv;
368
369     GST_TIME_TO_TIMEVAL (target, tv);
370
371     while (TRUE) {
372       /* now wait on the entry, it either times out or the cond is signaled. */
373       if (!GST_CLOCK_TIMED_WAIT (clock, &tv)) {
374         /* timeout, this is fine, we can report success now */
375         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked after timeout", entry);
376         entry->status = GST_CLOCK_OK;
377         break;
378       } else {
379         /* the waiting is interrupted because the GCond was signaled. This can
380          * be because this or some other entry was unscheduled. */
381         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked with signal", entry);
382         /* if the entry is unscheduled, we can stop waiting for it */
383         if (entry->status == GST_CLOCK_UNSCHEDULED)
384           break;
385       }
386     }
387   } else {
388     entry->status = GST_CLOCK_EARLY;
389   }
390   return entry->status;
391 }
392
393 static GstClockReturn
394 gst_system_clock_id_wait (GstClock * clock, GstClockEntry * entry)
395 {
396   GstClockReturn ret;
397
398   GST_LOCK (clock);
399   ret = gst_system_clock_id_wait_unlocked (clock, entry);
400   GST_UNLOCK (clock);
401
402   return ret;
403 }
404
405 /* Add an entry to the list of pending async waits. The entry is inserted
406  * in sorted order. If we inserted the entry at the head of the list, we
407  * need to signal the thread as it might either be waiting on it or waiting
408  * for a new entry. 
409  *
410  * MT safe.
411  */
412 static GstClockReturn
413 gst_system_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
414 {
415   GST_CAT_DEBUG (GST_CAT_CLOCK, "adding entry %p", entry);
416
417   GST_LOCK (clock);
418   /* need to take a ref */
419   gst_clock_id_ref ((GstClockID) entry);
420   /* insert the entry in sorted order */
421   clock->entries = g_list_insert_sorted (clock->entries, entry,
422       gst_clock_id_compare_func);
423
424   /* only need to send the signal if the entry was added to the
425    * front, else the thread is just waiting for another entry and
426    * will get to this entry automatically. */
427   if (clock->entries->data == entry) {
428     GST_CAT_DEBUG (GST_CAT_CLOCK, "send signal");
429     GST_CLOCK_BROADCAST (clock);
430   }
431   GST_UNLOCK (clock);
432
433   return GST_CLOCK_OK;
434 }
435
436 /* unschedule an entry. This will set the state of the entry to GST_CLOCK_UNSCHEDULED
437  * and will signal any thread waiting for entries to recheck their entry. 
438  * We cannot really decide if the signal is needed or not because the entry
439  * could be waited on in async or sync mode.
440  *
441  * MT safe.
442  */
443 static void
444 gst_system_clock_id_unschedule (GstClock * clock, GstClockEntry * entry)
445 {
446   GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
447
448   GST_LOCK (clock);
449   entry->status = GST_CLOCK_UNSCHEDULED;
450   GST_CAT_DEBUG (GST_CAT_CLOCK, "send signal");
451   GST_CLOCK_BROADCAST (clock);
452   GST_UNLOCK (clock);
453 }