/**
* SECTION:gstsystemclock
+ * @title: GstSystemClock
* @short_description: Default clock that uses the current system time
* @see_also: #GstClock
*
#ifdef G_OS_WIN32
LARGE_INTEGER start;
LARGE_INTEGER frequency;
+ guint64 ratio;
#endif /* G_OS_WIN32 */
#ifdef __APPLE__
struct mach_timebase_info mach_timebase;
#endif
};
-#define GST_SYSTEM_CLOCK_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_SYSTEM_CLOCK, \
- GstSystemClockPrivate))
-
#ifdef HAVE_POSIX_TIMERS
# ifdef HAVE_MONOTONIC_CLOCK
# define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_MONOTONIC
/* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
#define gst_system_clock_parent_class parent_class
-G_DEFINE_TYPE (GstSystemClock, gst_system_clock, GST_TYPE_CLOCK);
+G_DEFINE_TYPE_WITH_PRIVATE (GstSystemClock, gst_system_clock, GST_TYPE_CLOCK);
static void
gst_system_clock_class_init (GstSystemClockClass * klass)
gobject_class = (GObjectClass *) klass;
gstclock_class = (GstClockClass *) klass;
- g_type_class_add_private (klass, sizeof (GstSystemClockPrivate));
-
gobject_class->dispose = gst_system_clock_dispose;
gobject_class->set_property = gst_system_clock_set_property;
gobject_class->get_property = gst_system_clock_get_property;
GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
- clock->priv = priv = GST_SYSTEM_CLOCK_GET_PRIVATE (clock);
+ clock->priv = priv = gst_system_clock_get_instance_private (clock);
priv->clock_type = DEFAULT_CLOCK_TYPE;
priv->timer = gst_poll_new_timer ();
if (priv->frequency.QuadPart != 0)
/* we take a base time so that time starts from 0 to ease debugging */
QueryPerformanceCounter (&priv->start);
+ priv->ratio = GST_SECOND / priv->frequency.QuadPart;
#endif /* G_OS_WIN32 */
#ifdef __APPLE__
/**
* gst_system_clock_set_default:
- * @new_clock: a #GstClock
+ * @new_clock: (allow-none): a #GstClock
*
* Sets the default system clock that can be obtained with
* gst_system_clock_obtain().
clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
"name", "GstSystemClock", NULL);
- g_assert (!g_object_is_floating (G_OBJECT (clock)));
-
+ /* Clear floating flag */
+ gst_object_ref_sink (clock);
_the_system_clock = clock;
g_mutex_unlock (&_gst_sysclock_mutex);
} else {
g_return_if_fail (sysclock->priv->wakeup_count > 0);
sysclock->priv->wakeup_count--;
- if (sysclock->priv->wakeup_count == 0) {
- /* read the control socket byte when we removed the last wakeup count */
- GST_CAT_DEBUG (GST_CAT_CLOCK, "reading control");
- while (!gst_poll_read_control (sysclock->priv->timer)) {
- g_warning ("gstsystemclock: read control failed, trying again\n");
+ GST_CAT_DEBUG (GST_CAT_CLOCK, "reading control");
+ while (!gst_poll_read_control (sysclock->priv->timer)) {
+ if (errno == EWOULDBLOCK) {
+ /* Try again and give other threads the chance to do something */
+ g_thread_yield ();
+ continue;
+ } else {
+ /* Critical error, GstPoll will have printed a critical warning already */
+ break;
}
- GST_SYSTEM_CLOCK_BROADCAST (sysclock);
}
+ GST_SYSTEM_CLOCK_BROADCAST (sysclock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup count %d",
sysclock->priv->wakeup_count);
}
static void
gst_system_clock_add_wakeup (GstSystemClock * sysclock)
{
- /* only write the control socket for the first wakeup */
- if (sysclock->priv->wakeup_count == 0) {
- GST_CAT_DEBUG (GST_CAT_CLOCK, "writing control");
- while (!gst_poll_write_control (sysclock->priv->timer)) {
- if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
- g_warning
- ("gstsystemclock: write control failed in wakeup_async, trying again: %d:%s\n",
- errno, g_strerror (errno));
- } else {
- g_critical
- ("gstsystemclock: write control failed in wakeup_async: %d:%s\n",
- errno, g_strerror (errno));
- return;
- }
- }
- }
+ GST_CAT_DEBUG (GST_CAT_CLOCK, "writing control");
+ gst_poll_write_control (sysclock->priv->timer);
sysclock->priv->wakeup_count++;
GST_CAT_DEBUG (GST_CAT_CLOCK, "wakeup count %d",
sysclock->priv->wakeup_count);
/* we prefer the highly accurate performance counters on windows */
QueryPerformanceCounter (&now);
- return gst_util_uint64_scale (now.QuadPart - sysclock->priv->start.QuadPart,
- GST_SECOND, sysclock->priv->frequency.QuadPart);
+ return ((now.QuadPart -
+ sysclock->priv->start.QuadPart) * sysclock->priv->ratio);
} else
#endif /* G_OS_WIN32 */
#if !defined HAVE_POSIX_TIMERS || !defined HAVE_CLOCK_GETTIME
#endif /* __APPLE__ */
}
+static inline void
+gst_system_clock_cleanup_unscheduled (GstSystemClock * sysclock,
+ GstClockEntry * entry)
+{
+ /* try to clean up.
+ * The unschedule function managed to set the status to
+ * unscheduled. We now take the lock and mark the entry as unscheduled.
+ * This makes sure that the unschedule function doesn't perform a
+ * wakeup anymore. If the unschedule function has a change to perform
+ * the wakeup before us, we clean up here */
+ GST_OBJECT_LOCK (sysclock);
+ entry->unscheduled = TRUE;
+ if (entry->woken_up) {
+ gst_system_clock_remove_wakeup (sysclock);
+ }
+ GST_OBJECT_UNLOCK (sysclock);
+}
+
/* synchronously wait on the given GstClockEntry.
*
* We do this by blocking on the global GstPoll timer with
GstClockReturn status;
status = GET_ENTRY_STATUS (entry);
- if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED))
+ if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
+ gst_system_clock_cleanup_unscheduled (sysclock, entry);
return GST_CLOCK_UNSCHEDULED;
+ }
/* need to call the overridden method because we want to sync against the time
* of the clock, whatever the subclass uses as a clock. */
entry, status, pollret);
if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
- /* try to clean up The unschedule function managed to set the status to
- * unscheduled. We now take the lock and mark the entry as unscheduled.
- * This makes sure that the unschedule function doesn't perform a
- * wakeup anymore. If the unschedule function has a change to perform
- * the wakeup before us, we clean up here */
- GST_OBJECT_LOCK (sysclock);
- entry->unscheduled = TRUE;
- if (entry->woken_up) {
- gst_system_clock_remove_wakeup (sysclock);
- }
- GST_OBJECT_UNLOCK (sysclock);
+ gst_system_clock_cleanup_unscheduled (sysclock, entry);
goto done;
} else {
if (G_UNLIKELY (pollret != 0)) {
if (G_UNLIKELY (diff == 0)) {
if (G_UNLIKELY (!CAS_ENTRY_STATUS (entry, status, GST_CLOCK_OK))) {
status = GET_ENTRY_STATUS (entry);
- if (G_UNLIKELY (status != GST_CLOCK_UNSCHEDULED))
+ if (G_LIKELY (status == GST_CLOCK_UNSCHEDULED))
+ gst_system_clock_cleanup_unscheduled (sysclock, entry);
+ else
GST_CAT_ERROR (GST_CAT_CLOCK, "unexpected status %d for entry %p",
status, entry);
} else {
} else {
if (G_UNLIKELY (!CAS_ENTRY_STATUS (entry, status, GST_CLOCK_EARLY))) {
status = GET_ENTRY_STATUS (entry);
- if (G_UNLIKELY (status != GST_CLOCK_UNSCHEDULED))
+ if (G_LIKELY (status == GST_CLOCK_UNSCHEDULED))
+ gst_system_clock_cleanup_unscheduled (sysclock, entry);
+ else
GST_CAT_ERROR (GST_CAT_CLOCK, "unexpected status %d for entry %p",
status, entry);
} else {