PROP_TIMEOUT
};
+struct _GstClockPrivate
+{
+ gint pre_count;
+ gint post_count;
+};
+
+/* seqlocks */
+#define read_seqbegin(clock) \
+ g_atomic_int_get (&clock->priv->post_count);
+
+static inline gboolean
+read_seqretry (GstClock * clock, gint seq)
+{
+ /* no retry if the seqnum did not change */
+ if (G_LIKELY (seq == g_atomic_int_get (&clock->priv->pre_count)))
+ return FALSE;
+
+ /* wait for the writer to finish and retry */
+ GST_OBJECT_LOCK (clock);
+ GST_OBJECT_UNLOCK (clock);
+ return TRUE;
+}
+
+#define write_seqlock(clock) \
+G_STMT_START { \
+ GST_OBJECT_LOCK (clock); \
+ g_atomic_int_inc (&clock->priv->pre_count); \
+} G_STMT_END;
+
+#define write_sequnlock(clock) \
+G_STMT_START { \
+ g_atomic_int_inc (&clock->priv->post_count); \
+ GST_OBJECT_UNLOCK (clock); \
+} G_STMT_END;
+
static void gst_clock_class_init (GstClockClass * klass);
static void gst_clock_init (GstClock * clock);
static void gst_clock_dispose (GObject * object);
if (entry->type == GST_CLOCK_ENTRY_PERIODIC)
entry->time = requested + entry->interval;
- if (clock->stats)
+ if (G_UNLIKELY (clock->stats))
gst_clock_update_stats (clock);
return res;
"The amount of time, in nanoseconds, to sample master and slave clocks",
0, G_MAXUINT64, DEFAULT_TIMEOUT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (klass, sizeof (GstClockPrivate));
}
static void
clock->entries_changed = g_cond_new ();
clock->stats = FALSE;
+ clock->priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (clock, GST_TYPE_CLOCK, GstClockPrivate);
+
clock->internal_calibration = 0;
clock->external_calibration = 0;
clock->rate_numerator = 1;
cdenom = clock->rate_denominator;
/* avoid divide by 0 */
- if (cdenom == 0)
+ if (G_UNLIKELY (cdenom == 0))
cnum = cdenom = 1;
/* The formula is (internal - cinternal) * cnum / cdenom + cexternal
* though.
*/
if (G_LIKELY (internal >= cinternal)) {
- ret = gst_util_uint64_scale (internal - cinternal, cnum, cdenom);
+ ret = internal - cinternal;
+ ret = gst_util_uint64_scale (ret, cnum, cdenom);
ret += cexternal;
} else {
- ret = gst_util_uint64_scale (cinternal - internal, cnum, cdenom);
+ ret = cinternal - internal;
+ ret = gst_util_uint64_scale (ret, cnum, cdenom);
/* clamp to 0 */
- if (cexternal > ret)
+ if (G_LIKELY (cexternal > ret))
ret = cexternal - ret;
else
ret = 0;
cdenom = clock->rate_denominator;
/* avoid divide by 0 */
- if (cnum == 0)
+ if (G_UNLIKELY (cnum == 0))
cnum = cdenom = 1;
/* The formula is (external - cexternal) * cdenom / cnum + cinternal */
- if (external >= cexternal) {
- ret = gst_util_uint64_scale (external - cexternal, cdenom, cnum);
+ if (G_LIKELY (external >= cexternal)) {
+ ret = external - cexternal;
+ ret = gst_util_uint64_scale (ret, cdenom, cnum);
ret += cinternal;
} else {
- ret = gst_util_uint64_scale (cexternal - external, cdenom, cnum);
- if (cinternal > ret)
+ ret = cexternal - external;
+ ret = gst_util_uint64_scale (ret, cdenom, cnum);
+ if (G_LIKELY (cinternal > ret))
ret = cinternal - ret;
else
ret = 0;
gst_clock_get_time (GstClock * clock)
{
GstClockTime ret;
+ gint seq;
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
- ret = gst_clock_get_internal_time (clock);
+ do {
+ /* reget the internal time when we retry to get the most current
+ * timevalue */
+ ret = gst_clock_get_internal_time (clock);
- GST_OBJECT_LOCK (clock);
- /* this will scale for rate and offset */
- ret = gst_clock_adjust_unlocked (clock, ret);
- GST_OBJECT_UNLOCK (clock);
+ seq = read_seqbegin (clock);
+ /* this will scale for rate and offset */
+ ret = gst_clock_adjust_unlocked (clock, ret);
+ } while (read_seqretry (clock, seq));
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "adjusted time %" GST_TIME_FORMAT,
GST_TIME_ARGS (ret));
g_return_if_fail (rate_denom > 0 && rate_denom != GST_CLOCK_TIME_NONE);
g_return_if_fail (internal <= gst_clock_get_internal_time (clock));
- GST_OBJECT_LOCK (clock);
+ write_seqlock (clock);
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
"internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %"
G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f", GST_TIME_ARGS (internal),
clock->external_calibration = external;
clock->rate_numerator = rate_num;
clock->rate_denominator = rate_denom;
- GST_OBJECT_UNLOCK (clock);
+ write_sequnlock (clock);
}
/**
gst_clock_get_calibration (GstClock * clock, GstClockTime * internal,
GstClockTime * external, GstClockTime * rate_num, GstClockTime * rate_denom)
{
+ gint seq;
+
g_return_if_fail (GST_IS_CLOCK (clock));
- GST_OBJECT_LOCK (clock);
- if (rate_num)
- *rate_num = clock->rate_numerator;
- if (rate_denom)
- *rate_denom = clock->rate_denominator;
- if (external)
- *external = clock->external_calibration;
- if (internal)
- *internal = clock->internal_calibration;
- GST_OBJECT_UNLOCK (clock);
+ do {
+ seq = read_seqbegin (clock);
+ if (rate_num)
+ *rate_num = clock->rate_numerator;
+ if (rate_denom)
+ *rate_denom = clock->rate_denominator;
+ if (external)
+ *external = clock->external_calibration;
+ if (internal)
+ *internal = clock->internal_calibration;
+ } while (read_seqretry (clock, seq));
}
/* will be called repeatedly to sample the master and slave clock