/* In prepare, we're just checking the monotonic time against
 * our projected wakeup.
 */
static gboolean
g_datetime_source_prepare (GSource *source,
			   gint    *timeout)
{
	GDateTimeSource *datetime_source = (GDateTimeSource*)source;
	gint64 monotonic_now;

#ifdef HAVE_TIMERFD
	if (datetime_source->pollfd.fd != -1) {
		*timeout = -1;
		return datetime_source->initially_expired;  /* Should be TRUE at most one time, FALSE forever after */
	}
#endif

	monotonic_now = g_source_get_time (source);

	if (monotonic_now < datetime_source->wakeup_expiration) {
		/* Round up to ensure that we don't try again too early */
		*timeout = (datetime_source->wakeup_expiration - monotonic_now + 999) / 1000;
		return FALSE;
	}

	*timeout = 0;
	return g_datetime_source_is_expired (datetime_source);
}
Exemplo n.º 2
0
/** FD event source dispatch() method.
 * This is called if either prepare() or check() returned TRUE.
 */
static gboolean fd_source_dispatch(GSource *source,
		GSourceFunc callback, void *user_data)
{
	struct fd_source *fsource;
	const char *name;
	unsigned int revents;
	gboolean keep;

	fsource = (struct fd_source *)source;
	name = g_source_get_name(source);
	revents = fsource->pollfd.revents;

	if (revents != 0) {
		sr_spew("%s: %s " G_POLLFD_FORMAT ", revents 0x%.2X",
			__func__, name, fsource->pollfd.fd, revents);
	} else {
		sr_spew("%s: %s " G_POLLFD_FORMAT ", timed out",
			__func__, name, fsource->pollfd.fd);
	}
	if (!callback) {
		sr_err("Callback not set, cannot dispatch event.");
		return G_SOURCE_REMOVE;
	}
	keep = (*(sr_receive_data_callback)callback)
			(fsource->pollfd.fd, revents, user_data);

	if (fsource->timeout_us >= 0 && G_LIKELY(keep)
			&& G_LIKELY(!g_source_is_destroyed(source)))
		fsource->due_us = g_source_get_time(source)
				+ fsource->timeout_us;
	return keep;
}
static gint
master_clock_get_swap_wait_time (ClutterMasterClockDefault *master_clock)
{
  ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
  const GSList *stages, *l;
  gint64 min_update_time = -1;

  stages = clutter_stage_manager_peek_stages (stage_manager);

  for (l = stages; l != NULL; l = l->next)
    {
      gint64 update_time = _clutter_stage_get_update_time (l->data);
      if (min_update_time == -1 ||
          (update_time != -1 && update_time < min_update_time))
        min_update_time = update_time;
    }

  if (min_update_time == -1)
    {
      return -1;
    }
  else
    {
      gint64 now = g_source_get_time (master_clock->source);
      if (min_update_time < now)
        {
          return 0;
        }
      else
        {
          gint64 delay_us = min_update_time - now;
          return (delay_us + 999) / 1000;
        }
    }
}
static gboolean
clutter_clock_dispatch (GSource     *source,
                        GSourceFunc  callback,
                        gpointer     user_data)
{
  ClutterClockSource *clock_source = (ClutterClockSource *) source;
  ClutterMasterClockDefault *master_clock = clock_source->master_clock;
  gboolean stages_updated = FALSE;
  GSList *stages;

  CLUTTER_NOTE (SCHEDULER, "Master clock [tick]");

  _clutter_threads_acquire_lock ();

  /* Get the time to use for this frame */
  master_clock->cur_tick = g_source_get_time (source);

#ifdef CLUTTER_ENABLE_DEBUG
  master_clock->remaining_budget = master_clock->frame_budget;
#endif

  /* We need to protect ourselves against stages being destroyed during
   * event handling - master_clock_list_ready_stages() returns a
   * list of referenced that we'll unref afterwards.
   */
  stages = master_clock_list_ready_stages (master_clock);

  master_clock->idle = FALSE;

  /* Each frame is split into three separate phases: */

  /* 1. process all the events; each stage goes through its events queue
   *    and processes each event according to its type, then emits the
   *    various signals that are associated with the event
   */
  master_clock_process_events (master_clock, stages);

  /* 2. advance the timelines */
  master_clock_advance_timelines (master_clock);

  /* 3. relayout and redraw the stages */
  stages_updated = master_clock_update_stages (master_clock, stages);

  /* The master clock goes idle if no stages were updated and falls back
   * to polling for timeline progressions... */
  if (!stages_updated)
    master_clock->idle = TRUE;

  master_clock_reschedule_stage_updates (master_clock, stages);

  g_slist_foreach (stages, (GFunc) g_object_unref, NULL);
  g_slist_free (stages);

  master_clock->prev_tick = master_clock->cur_tick;

  _clutter_threads_release_lock ();

  return TRUE;
}
Exemplo n.º 5
0
static gboolean
sleep_source_prepare (GSource *source,
                      gint    *timeout)
{
  sleep_source_prepare_time = g_source_get_time (source);
  *timeout = -1;
  return FALSE;
}
Exemplo n.º 6
0
static gboolean
sleep_source_check (GSource *source)
{
  if (g_source_get_time (source) != sleep_source_prepare_time)
    sleep_serial++;

  return FALSE;
}
Exemplo n.º 7
0
/** FD event source check() method.
 * This is called after poll() returns to check whether an event fired.
 */
static gboolean fd_source_check(GSource *source)
{
	struct fd_source *fsource;
	unsigned int revents;

	fsource = (struct fd_source *)source;
	revents = fsource->pollfd.revents;

	return (revents != 0 || (fsource->timeout_us >= 0
			&& fsource->due_us <= g_source_get_time(source)));
}
static void
collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc)
{
  gint timeout;
  GTimeVal now;
  gint64 tmp;

  tmp = g_source_get_time ((GSource *) psrc);
  now.tv_sec = tmp / G_USEC_PER_SEC;
  now.tv_usec = tmp % G_USEC_PER_SEC;

  timeout = gst_rtsp_session_next_timeout (sess, &now);
  GST_INFO ("%p: next timeout: %d", sess, timeout);
  if (psrc->timeout == -1 || timeout < psrc->timeout)
    psrc->timeout = timeout;
}
/* In check, we're looking at the wall clock.
 */
static gboolean
g_datetime_source_check (GSource  *source)
{
	GDateTimeSource *datetime_source = (GDateTimeSource*)source;

#ifdef HAVE_TIMERFD
	if (datetime_source->pollfd.fd != -1)
		return datetime_source->pollfd.revents != 0;
#endif

	if (g_datetime_source_is_expired (datetime_source))
		return TRUE;

	g_datetime_source_reschedule (datetime_source, g_source_get_time (source));

	return FALSE;
}
Exemplo n.º 10
0
/** USB event source check() method.
 */
static gboolean usb_source_check(GSource *source)
{
	struct usb_source *usource;
	GPollFD *pollfd;
	unsigned int revents;
	unsigned int i;

	usource = (struct usb_source *)source;
	revents = 0;

	for (i = 0; i < usource->pollfds->len; i++) {
		pollfd = g_ptr_array_index(usource->pollfds, i);
		revents |= pollfd->revents;
	}
	return (revents != 0 || (usource->due_us != INT64_MAX
			&& usource->due_us <= g_source_get_time(source)));
}
Exemplo n.º 11
0
static CoglBool
cogl_glib_source_check (GSource *source)
{
  CoglGLibSource *cogl_source = (CoglGLibSource *) source;
  int i;

  if (cogl_source->expiration_time >= 0 &&
      g_source_get_time (source) >= cogl_source->expiration_time)
    return TRUE;

  for (i = 0; i < cogl_source->poll_fds->len; i++)
    {
      GPollFD *poll_fd = &g_array_index (cogl_source->poll_fds, GPollFD, i);
      if (poll_fd->revents != 0)
        return TRUE;
    }

  return FALSE;
}
Exemplo n.º 12
0
static gboolean
evict_source_check (GSource *source)
{
  EvictSource *ev = (EvictSource *)source;

  g_assert (ev != NULL);
  g_assert (ev->heap != NULL);

  if (ev->heap->len > 0)
    {
      CacheItem *item;
      gint64 now;

      now = g_source_get_time (source);
      item = egg_heap_peek (ev->heap, gpointer);

      return (item->evict_at <= now);
    }

  return FALSE;
}
Exemplo n.º 13
0
/** USB event source dispatch() method.
 */
static gboolean usb_source_dispatch(GSource *source,
		GSourceFunc callback, void *user_data)
{
	struct usb_source *usource;
	GPollFD *pollfd;
	unsigned int revents;
	unsigned int i;
	gboolean keep;

	usource = (struct usb_source *)source;
	revents = 0;
	/*
	 * This is somewhat arbitrary, but drivers use revents to distinguish
	 * actual I/O from timeouts. When we remove the user timeout from the
	 * driver API, this will no longer be needed.
	 */
	for (i = 0; i < usource->pollfds->len; i++) {
		pollfd = g_ptr_array_index(usource->pollfds, i);
		revents |= pollfd->revents;
	}
	if (revents != 0)
		sr_spew("%s: revents 0x%.2X", __func__, revents);
	else
		sr_spew("%s: timed out", __func__);

	if (!callback) {
		sr_err("Callback not set, cannot dispatch event.");
		return G_SOURCE_REMOVE;
	}
	keep = (*(sr_receive_data_callback)callback)(-1, revents, user_data);

	if (G_LIKELY(keep) && G_LIKELY(!g_source_is_destroyed(source))) {
		if (usource->timeout_us >= 0)
			usource->due_us = g_source_get_time(source)
					+ usource->timeout_us;
		else
			usource->due_us = INT64_MAX;
	}
	return keep;
}
Exemplo n.º 14
0
static gboolean
gb_frame_source_prepare (GSource *source,
                         gint    *timeout_)
{
   GbFrameSource *fsource = (GbFrameSource *)source;
   gint64 current_time;
   guint elapsed_time;
   guint new_frame_num;
   guint frame_time;

   current_time = g_source_get_time(source) / 1000;
   elapsed_time = current_time - fsource->start_time;
   new_frame_num = elapsed_time * fsource->fps / 1000;

   /* If time has gone backwards or the time since the last frame is
    * greater than the two frames worth then reset the time and do a
    * frame now */
   if (new_frame_num < fsource->frame_count ||
       new_frame_num - fsource->frame_count > 2) {
      /* Get the frame time rounded up to the nearest ms */
      frame_time = (1000 + fsource->fps - 1) / fsource->fps;

      /* Reset the start time */
      fsource->start_time = current_time;

      /* Move the start time as if one whole frame has elapsed */
      fsource->start_time -= frame_time;
      fsource->frame_count = 0;
      *timeout_ = 0;
      return TRUE;
   } else if (new_frame_num > fsource->frame_count) {
      *timeout_ = 0;
      return TRUE;
   } else {
      *timeout_ = (fsource->frame_count + 1) * 1000 / fsource->fps - elapsed_time;
      return FALSE;
   }
}
Exemplo n.º 15
0
/** FD event source dispatch() method.
 * This is called if either prepare() or check() returned TRUE.
 */
static gboolean fd_source_dispatch(GSource *source,
		GSourceFunc callback, void *user_data)
{
	struct fd_source *fsource;
	unsigned int revents;
	gboolean keep;

	fsource = (struct fd_source *)source;
	revents = fsource->pollfd.revents;

	if (!callback) {
		sr_err("Callback not set, cannot dispatch event.");
		return G_SOURCE_REMOVE;
	}
	keep = (*(sr_receive_data_callback)callback)
			(fsource->pollfd.fd, revents, user_data);

	if (fsource->timeout_us >= 0 && G_LIKELY(keep)
			&& G_LIKELY(!g_source_is_destroyed(source)))
		fsource->due_us = g_source_get_time(source)
				+ fsource->timeout_us;
	return keep;
}
Exemplo n.º 16
0
/** FD event source prepare() method.
 * This is called immediately before poll().
 */
static gboolean fd_source_prepare(GSource *source, int *timeout)
{
	int64_t now_us;
	struct fd_source *fsource;
	int remaining_ms;

	fsource = (struct fd_source *)source;

	if (fsource->timeout_us >= 0) {
		now_us = g_source_get_time(source);

		if (fsource->due_us == 0) {
			/* First-time initialization of the expiration time */
			fsource->due_us = now_us + fsource->timeout_us;
		}
		remaining_ms = (MAX(0, fsource->due_us - now_us) + 999) / 1000;
	} else {
		remaining_ms = -1;
	}
	*timeout = remaining_ms;

	return (remaining_ms == 0);
}
Exemplo n.º 17
0
static gboolean
keyboard_repeat (gpointer data)
{
  ClutterSeatEvdev *seat = data;
  GSource *source;

  /* There might be events queued in libinput that could cancel the
     repeat timer. */
  _clutter_device_manager_evdev_dispatch (seat->manager_evdev);
  if (!seat->repeat_timer)
    return G_SOURCE_REMOVE;

  g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE);
  source = g_main_context_find_source_by_id (NULL, seat->repeat_timer);

  clutter_seat_evdev_notify_key (seat,
                                 seat->repeat_device,
                                 g_source_get_time (source),
                                 seat->repeat_key,
                                 AUTOREPEAT_VALUE,
                                 FALSE);

  return G_SOURCE_CONTINUE;
}
static gboolean
g_datetime_source_is_expired (GDateTimeSource *datetime_source)
{
	gint64 real_now;
	gint64 monotonic_now;

	real_now = g_get_real_time ();
	monotonic_now = g_source_get_time ((GSource*)datetime_source);

	if (datetime_source->initially_expired)
		return TRUE;

	if (datetime_source->real_expiration <= real_now)
		return TRUE;

	/* We can't really detect without system support when things
	 * change; so just trigger every second (i.e. our wakeup
	 * expiration)
	 */
	if (datetime_source->cancel_on_set && monotonic_now >= datetime_source->wakeup_expiration)
		return TRUE;

	return FALSE;
}
Exemplo n.º 19
0
/** USB event source prepare() method.
 */
static gboolean usb_source_prepare(GSource *source, int *timeout)
{
	int64_t now_us, usb_due_us;
	struct usb_source *usource;
	struct timeval usb_timeout;
	int remaining_ms;
	int ret;

	usource = (struct usb_source *)source;

	ret = libusb_get_next_timeout(usource->usb_ctx, &usb_timeout);
	if (G_UNLIKELY(ret < 0)) {
		sr_err("Failed to get libusb timeout: %s",
			libusb_error_name(ret));
	}
	now_us = g_source_get_time(source);

	if (usource->due_us == 0) {
		/* First-time initialization of the expiration time */
		usource->due_us = now_us + usource->timeout_us;
	}
	if (ret == 1) {
		usb_due_us = (int64_t)usb_timeout.tv_sec * G_USEC_PER_SEC
				+ usb_timeout.tv_usec + now_us;
		if (usb_due_us < usource->due_us)
			usource->due_us = usb_due_us;
	}
	if (usource->due_us != INT64_MAX)
		remaining_ms = (MAX(0, usource->due_us - now_us) + 999) / 1000;
	else
		remaining_ms = -1;

	*timeout = remaining_ms;

	return (remaining_ms == 0);
}
Exemplo n.º 20
0
namespace WTF {

GMainLoopSource& GMainLoopSource::create()
{
    return *new GMainLoopSource(DeleteOnDestroy);
}

GMainLoopSource::GMainLoopSource()
    : m_deleteOnDestroy(DoNotDeleteOnDestroy)
    , m_status(Ready)
{
}

GMainLoopSource::GMainLoopSource(DeleteOnDestroyType deleteOnDestroy)
    : m_deleteOnDestroy(deleteOnDestroy)
    , m_status(Ready)
{
}

GMainLoopSource::~GMainLoopSource()
{
    cancel();
}

bool GMainLoopSource::isScheduled() const
{
    return m_status == Scheduled;
}

bool GMainLoopSource::isActive() const
{
    return m_status != Ready;
}

void GMainLoopSource::cancel()
{
    // Delete-on-destroy GMainLoopSource objects can't be cancelled.
    if (m_deleteOnDestroy == DeleteOnDestroy)
        return;

    // A valid context should only be present if GMainLoopSource is in the Scheduled or Dispatching state.
    ASSERT(!m_context.source || m_status == Scheduled || m_status == Dispatching);

    m_status = Ready;

    g_cancellable_cancel(m_context.socketCancellable.get());

    if (!m_context.source)
        return;

    Context context;
    context = WTF::move(m_context);
    context.destroySource();
}

void GMainLoopSource::scheduleIdleSource(const char* name, GSourceFunc sourceFunction, int priority, GMainContext* context)
{
    ASSERT(m_status == Ready);
    m_status = Scheduled;

    g_source_set_name(m_context.source.get(), name);
    if (priority != G_PRIORITY_DEFAULT_IDLE)
        g_source_set_priority(m_context.source.get(), priority);
    g_source_set_callback(m_context.source.get(), sourceFunction, this, nullptr);
    g_source_attach(m_context.source.get(), context);
}

void GMainLoopSource::schedule(const char* name, std::function<void ()> function, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_idle_source_new()),
        nullptr, // cancellable
        nullptr, // socketCancellable
        WTF::move(function),
        nullptr, // boolCallback
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleIdleSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context);
}

void GMainLoopSource::schedule(const char* name, std::function<bool ()> function, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_idle_source_new()),
        nullptr, // cancellable
        nullptr, // socketCancellable
        nullptr, // voidCallback
        WTF::move(function),
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleIdleSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context);
}

void GMainLoopSource::schedule(const char* name, std::function<bool (GIOCondition)> function, GSocket* socket, GIOCondition condition, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    GCancellable* socketCancellable = g_cancellable_new();
    m_context = {
        adoptGRef(g_socket_create_source(socket, condition, socketCancellable)),
        nullptr, // cancellable
        adoptGRef(socketCancellable),
        nullptr, // voidCallback
        nullptr, // boolCallback
        WTF::move(function),
        WTF::move(destroyFunction)
    };

    ASSERT(m_status == Ready);
    m_status = Scheduled;
    g_source_set_name(m_context.source.get(), name);
    g_source_set_callback(m_context.source.get(), reinterpret_cast<GSourceFunc>(socketSourceCallback), this, nullptr);
    g_source_attach(m_context.source.get(), context);
}

void GMainLoopSource::scheduleTimeoutSource(const char* name, GSourceFunc sourceFunction, int priority, GMainContext* context)
{
    ASSERT(m_status == Ready);
    m_status = Scheduled;

    g_source_set_name(m_context.source.get(), name);
    if (priority != G_PRIORITY_DEFAULT)
        g_source_set_priority(m_context.source.get(), priority);
    g_source_set_callback(m_context.source.get(), sourceFunction, this, nullptr);
    g_source_attach(m_context.source.get(), context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<void ()> function, std::chrono::milliseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_timeout_source_new(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        WTF::move(function),
        nullptr, // boolCallback
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<bool ()> function, std::chrono::milliseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_timeout_source_new(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        nullptr, // voidCallback
        WTF::move(function),
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<void ()> function, std::chrono::seconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_timeout_source_new_seconds(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        WTF::move(function),
        nullptr, // boolCallback
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<bool ()> function, std::chrono::seconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_timeout_source_new_seconds(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        nullptr, // voidCallback
        WTF::move(function),
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context);
}

struct MicrosecondsTimeoutSource {
    GSource source;
    uint64_t delay;
};

static GSourceFuncs microsecondsTimeoutSourceFunctions = {
    nullptr, // prepare
    nullptr, // check
    // dispatch
    [](GSource* source, GSourceFunc callback, gpointer userData) -> gboolean
    {
        bool repeat = callback(userData);
        if (repeat)
            g_source_set_ready_time(source, g_source_get_time(source) + reinterpret_cast<MicrosecondsTimeoutSource*>(source)->delay);
        return repeat;
    },
    nullptr, // finalize
    nullptr, // closure_callback
    nullptr // closure_marshall
};

static GSource* createMicrosecondsTimeoutSource(uint64_t delay)
{
    GSource* source = g_source_new(&microsecondsTimeoutSourceFunctions, sizeof(MicrosecondsTimeoutSource));
    reinterpret_cast<MicrosecondsTimeoutSource*>(source)->delay = delay;
    g_source_set_ready_time(source, g_get_monotonic_time() + delay);
    return source;
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<void ()> function, std::chrono::microseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(createMicrosecondsTimeoutSource(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        WTF::move(function),
        nullptr, // boolCallback
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<bool ()> function, std::chrono::microseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(createMicrosecondsTimeoutSource(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        nullptr, // voidCallback
        WTF::move(function),
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAndDeleteOnDestroy(const char* name, std::function<void()> function, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().schedule(name, function, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAndDeleteOnDestroy(const char* name, std::function<bool()> function, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().schedule(name, function, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<void()> function, std::chrono::milliseconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<bool()> function, std::chrono::milliseconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<void()> function, std::chrono::seconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<bool()> function, std::chrono::seconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<void()> function, std::chrono::microseconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<bool()> function, std::chrono::microseconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

bool GMainLoopSource::prepareVoidCallback(Context& context)
{
    if (!m_context.source)
        return false;

    context = WTF::move(m_context);

    ASSERT(context.voidCallback);
    ASSERT(m_status == Scheduled);
    m_status = Dispatching;

    return true;
}

void GMainLoopSource::finishVoidCallback()
{
    m_status = Ready;
}

void GMainLoopSource::voidCallback()
{
    Context context;
    if (!prepareVoidCallback(context))
        return;

    context.voidCallback();
    if (m_status != Ready && !m_context.source) {
        // Switch to Ready if it hasn't been re-scheduled or cancelled.
        finishVoidCallback();
    }

    context.destroySource();
    if (m_deleteOnDestroy == DeleteOnDestroy)
        delete this;
}

bool GMainLoopSource::prepareBoolCallback(Context& context)
{
    if (!m_context.source)
        return false;

    context = WTF::move(m_context);

    ASSERT(context.boolCallback);
    ASSERT(m_status == Scheduled || m_status == Dispatching);
    m_status = Dispatching;
    return true;
}

void GMainLoopSource::finishBoolCallback(bool retval, Context& context)
{
    // m_status should reflect whether the GMainLoopSource has been rescheduled during dispatch.
    ASSERT((!m_context.source && m_status == Dispatching) || m_status == Scheduled);
    if (retval && !m_context.source)
        m_context = WTF::move(context);
    else if (!retval)
        m_status = Ready;
}

bool GMainLoopSource::boolCallback()
{
    Context context;
    if (!prepareBoolCallback(context))
        return Stop;

    bool retval = context.boolCallback();
    if (m_status != Ready && !m_context.source) {
        // Prepare for a new iteration or switch to Ready if it hasn't been re-scheduled or cancelled.
        finishBoolCallback(retval, context);
    }

    if (context.source) {
        context.destroySource();
        if (m_deleteOnDestroy == DeleteOnDestroy)
            delete this;
    }

    return retval;
}

bool GMainLoopSource::socketCallback(GIOCondition condition)
{
    if (!m_context.source)
        return Stop;

    Context context;
    context = WTF::move(m_context);

    ASSERT(context.socketCallback);
    ASSERT(m_status == Scheduled || m_status == Dispatching);
    m_status = Dispatching;

    if (g_cancellable_is_cancelled(context.socketCancellable.get())) {
        context.destroySource();
        return Stop;
    }

    bool retval = context.socketCallback(condition);

    if (m_status != Ready && !m_context.source) {
        // m_status should reflect whether the GMainLoopSource has been rescheduled during dispatch.
        ASSERT((!m_context.source && m_status == Dispatching) || m_status == Scheduled);
        if (retval && !m_context.source)
            m_context = WTF::move(context);
        else if (!retval)
            m_status = Ready;
    }

    if (context.source)
        context.destroySource();

    return retval;
}

gboolean GMainLoopSource::voidSourceCallback(GMainLoopSource* source)
{
    source->voidCallback();
    return G_SOURCE_REMOVE;
}

gboolean GMainLoopSource::boolSourceCallback(GMainLoopSource* source)
{
    return source->boolCallback() == Continue;
}

gboolean GMainLoopSource::socketSourceCallback(GSocket*, GIOCondition condition, GMainLoopSource* source)
{
    return source->socketCallback(condition) == Continue;
}

void GMainLoopSource::Context::destroySource()
{
    g_source_destroy(source.get());
    if (destroyCallback)
        destroyCallback();
}

} // namespace WTF
Exemplo n.º 21
0
/*
 * master_clock_next_frame_delay:
 * @master_clock: a #ClutterMasterClock
 *
 * Computes the number of delay before we need to draw the next frame.
 *
 * Return value: -1 if there is no next frame pending, otherwise the
 *  number of millseconds before the we need to draw the next frame
 */
static gint
master_clock_next_frame_delay (ClutterMasterClock *master_clock)
{
  gint64 now, next;

  if (!master_clock_is_running (master_clock))
    return -1;

  /* When we have sync-to-vblank, we count on swap-buffer requests (or
   * swap-buffer-complete events if supported in the backend) to throttle our
   * frame rate so no additional delay is needed to start the next frame.
   *
   * If the master-clock has become idle due to no timeline progression causing
   * redraws then we can no longer rely on vblank synchronization because the
   * last real stage update/redraw may have happened a long time ago and so we
   * fallback to polling for timeline progressions every 1/frame_rate seconds.
   *
   * (NB: if there aren't even any timelines running then the master clock will
   * be completely stopped in master_clock_is_running())
   */
  if (clutter_feature_available (CLUTTER_FEATURE_SYNC_TO_VBLANK) &&
      !master_clock->idle)
    {
      CLUTTER_NOTE (SCHEDULER, "vblank available and updated stages");
      return 0;
    }

  if (master_clock->prev_tick == 0)
    {
      /* If we weren't previously running, then draw the next frame
       * immediately
       */
      CLUTTER_NOTE (SCHEDULER, "draw the first frame immediately");
      return 0;
    }

  /* Otherwise, wait at least 1/frame_rate seconds since we last
   * started a frame
   */
#if GLIB_CHECK_VERSION (2, 27, 3)
  now = g_source_get_time (master_clock->source);
#else
  {
    GTimeVal source_time;
    g_source_get_current_time (master_clock->source, &source_time);
    now = source_time.tv_sec * 1000000L + source_time.tv_usec;
  }
#endif

  next = master_clock->prev_tick;

  /* If time has gone backwards then there's no way of knowing how
     long we should wait so let's just dispatch immediately */
  if (now <= next)
    {
      CLUTTER_NOTE (SCHEDULER, "Time has gone backwards");

      return 0;
    }

  next += (1000000L / clutter_get_default_frame_rate ());

  if (next <= now)
    {
      CLUTTER_NOTE (SCHEDULER, "Less than %lu microsecs",
                    1000000L / (gulong) clutter_get_default_frame_rate ());

      return 0;
    }
  else
    {
      CLUTTER_NOTE (SCHEDULER, "Waiting %" G_GINT64_FORMAT " msecs",
                   (next - now) / 1000);

      return (next - now) / 1000;
    }
}
Exemplo n.º 22
0
static gboolean
g_file_monitor_source_dispatch (GSource     *source,
                                GSourceFunc  callback,
                                gpointer     user_data)
{
  GFileMonitorSource *fms = (GFileMonitorSource *) source;
  QueuedEvent *event;
  GQueue event_queue;
  gint64 now;

  /* make sure the monitor still exists */
  if (!fms->instance)
    return FALSE;

  now = g_source_get_time (source);

  /* Acquire the lock once and grab all events in one go, handling the
   * queued events first.  This avoids strange possibilities in cases of
   * long delays, such as CHANGED events coming before CREATED events.
   *
   * We do this by converting the applicable pending changes into queued
   * events (after the ones already queued) and then stealing the entire
   * event queue in one go.
   */
  g_mutex_lock (&fms->lock);

  /* Create events for any pending changes that are due to fire */
  while (!g_sequence_is_empty (fms->pending_changes))
    {
      GSequenceIter *iter = g_sequence_get_begin_iter (fms->pending_changes);
      PendingChange *pending = g_sequence_get (iter);

      /* We've gotten to a pending change that's not ready.  Stop. */
      if (pending_change_get_ready_time (pending, fms) > now)
        break;

      if (pending->dirty)
        {
          /* It's time to send another CHANGED and update the record */
          g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, pending->child, NULL);
          pending->last_emission = now;
          pending->dirty = FALSE;

          g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
        }
      else
        {
          /* It's time to send CHANGES_DONE and remove the pending record */
          g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, pending->child, NULL);
          g_file_monitor_source_remove_pending_change (fms, iter, pending->child);
        }
    }

  /* Steal the queue */
  memcpy (&event_queue, &fms->event_queue, sizeof event_queue);
  memset (&fms->event_queue, 0, sizeof fms->event_queue);

  g_file_monitor_source_update_ready_time (fms);

  g_mutex_unlock (&fms->lock);

  /* We now have our list of events to deliver */
  while ((event = g_queue_pop_head (&event_queue)))
    {
      /* an event handler could destroy 'instance', so check each time */
      if (fms->instance)
        g_file_monitor_emit_event (fms->instance, event->child, event->other, event->event_type);

      queued_event_free (event);
    }

  return TRUE;
}
Exemplo n.º 23
0
static gboolean
clutter_clock_dispatch (GSource     *source,
                        GSourceFunc  callback,
                        gpointer     user_data)
{
  ClutterClockSource *clock_source = (ClutterClockSource *) source;
  ClutterMasterClock *master_clock = clock_source->master_clock;
  ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
  gboolean stages_updated = FALSE;
  GSList *stages, *l;

  CLUTTER_STATIC_TIMER (master_dispatch_timer,
                        "Mainloop",
                        "Master Clock",
                        "Master clock dispatch",
                        0);
  CLUTTER_STATIC_TIMER (master_event_process,
                        "Master Clock",
                        "Event Processing",
                        "The time spent processing events on all stages",
                        0);

  CLUTTER_TIMER_START (_clutter_uprof_context, master_dispatch_timer);

  CLUTTER_NOTE (SCHEDULER, "Master clock [tick]");

  clutter_threads_enter ();

  /* Get the time to use for this frame */
#if GLIB_CHECK_VERSION (2, 27, 3)
  master_clock->cur_tick = g_source_get_time (source);
#else
  {
    GTimeVal source_time;
    g_source_get_current_time (source, &source_time);
    master_clock->cur_tick = source_time.tv_sec * 1000000L
                           + source_time.tv_usec;
  }
#endif

  /* We need to protect ourselves against stages being destroyed during
   * event handling
   */
  stages = clutter_stage_manager_list_stages (stage_manager);
  g_slist_foreach (stages, (GFunc) g_object_ref, NULL);

  CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process);

  master_clock->idle = FALSE;

  /* Process queued events */
  for (l = stages; l != NULL; l = l->next)
    {
      /* NB: If a stage is busy waiting for a swap-buffers completion then
       * we don't process its events so we can maximize the benefits of
       * motion compression, and avoid multiple picks per frame.
       */
      if (_clutter_stage_get_pending_swaps (l->data) == 0)
        _clutter_stage_process_queued_events (l->data);
    }

  CLUTTER_TIMER_STOP (_clutter_uprof_context, master_event_process);

  _clutter_master_clock_advance (master_clock);

  _clutter_run_repaint_functions ();

  /* Update any stage that needs redraw/relayout after the clock
   * is advanced.
   */
  for (l = stages; l != NULL; l = l->next)
    {
      /* If a stage has a swap-buffers pending we don't want to draw to it
       * in case the driver may block the CPU while it waits for the next
       * backbuffer to become available.
       *
       * TODO: We should be able to identify if we are running triple or N
       * buffered and in these cases we can still draw if there is 1 swap
       * pending so we can hopefully always be ready to swap for the next
       * vblank and really match the vsync frequency.
       */
      if (_clutter_stage_get_pending_swaps (l->data) == 0)
        stages_updated |= _clutter_stage_do_update (l->data);
    }

  /* The master clock goes idle if no stages were updated and falls back
   * to polling for timeline progressions... */
  if (!stages_updated)
    master_clock->idle = TRUE;

  g_slist_foreach (stages, (GFunc) g_object_unref, NULL);
  g_slist_free (stages);

  master_clock->prev_tick = master_clock->cur_tick;

  clutter_threads_leave ();

  CLUTTER_TIMER_STOP (_clutter_uprof_context, master_dispatch_timer);

  return TRUE;
}
Exemplo n.º 24
0
static gboolean
g_fam_file_monitor_callback (gint         fd,
                             GIOCondition condition,
                             gpointer     user_data)
{
  gint64 now = g_source_get_time (fam_source);

  g_mutex_lock (&fam_lock);

  while (FAMPending (&fam_connection))
    {
      const gchar *child;
      FAMEvent ev;

      if (FAMNextEvent (&fam_connection, &ev) != 1)
        {
          /* The daemon died.  We're in a really bad situation now
           * because we potentially have a bunch of request structures
           * outstanding which no longer make any sense to anyone.
           *
           * The best thing that we can do is do nothing.  Notification
           * won't work anymore for this process.
           */
          g_mutex_unlock (&fam_lock);

          g_warning ("Lost connection to FAM (file monitoring) service.  Expect no further file monitor events.");

          return FALSE;
        }

      /* We expect ev.filename to be a relative path for children in a
       * monitored directory, and an absolute path for a monitored file
       * or the directory itself.
       */
      if (ev.filename[0] != '/')
        child = ev.filename;
      else
        child = NULL;

      switch (ev.code)
        {
        case FAMAcknowledge:
          g_source_unref (ev.userdata);
          break;

        case FAMChanged:
          g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CHANGED, child, NULL, NULL, now);
          break;

        case FAMDeleted:
          g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_DELETED, child, NULL, NULL, now);
          break;

        case FAMCreated:
          g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CREATED, child, NULL, NULL, now);
          break;

        default:
          /* unknown type */
          break;
        }
    }

  g_mutex_unlock (&fam_lock);

  return TRUE;
}
Exemplo n.º 25
0
static CoglBool
cogl_glib_source_prepare (GSource *source, int *timeout)
{
  CoglGLibSource *cogl_source = (CoglGLibSource *) source;
  CoglPollFD *poll_fds;
  int n_poll_fds;
  int64_t cogl_timeout;
  int age;
  int i;

  age = cogl_poll_renderer_get_info (cogl_source->renderer,
                                     &poll_fds,
                                     &n_poll_fds,
                                     &cogl_timeout);

  /* We have to be careful not to call g_source_add/remove_poll unless
   * the FDs have changed because it will cause the main loop to
   * immediately wake up. If we call it every time the source is
   * prepared it will effectively never go idle. */
  if (age != cogl_source->poll_fds_age)
    {
      /* Remove any existing polls before adding the new ones */
      for (i = 0; i < cogl_source->poll_fds->len; i++)
        {
          GPollFD *poll_fd = &g_array_index (cogl_source->poll_fds, GPollFD, i);
          g_source_remove_poll (source, poll_fd);
        }

      g_array_set_size (cogl_source->poll_fds, n_poll_fds);

      for (i = 0; i < n_poll_fds; i++)
        {
          GPollFD *poll_fd = &g_array_index (cogl_source->poll_fds, GPollFD, i);
          poll_fd->fd = poll_fds[i].fd;
          g_source_add_poll (source, poll_fd);
        }
    }

  cogl_source->poll_fds_age = age;

  /* Update the events */
  for (i = 0; i < n_poll_fds; i++)
    {
      GPollFD *poll_fd = &g_array_index (cogl_source->poll_fds, GPollFD, i);
      poll_fd->events = poll_fds[i].events;
      poll_fd->revents = 0;
    }

  if (cogl_timeout == -1)
    {
      *timeout = -1;
      cogl_source->expiration_time = -1;
    }
  else
    {
      /* Round up to ensure that we don't try again too early */
      *timeout = (cogl_timeout + 999) / 1000;
      cogl_source->expiration_time = (g_source_get_time (source) +
                                      cogl_timeout);
    }

  return *timeout == 0;
}