+ return context->continue_idle_job_func (thread_data, context - pool_contexts);
+}
+
+static gboolean
+should_work (SgenThreadPoolContext *context, void *thread_data)
+{
+ if (!context->should_work_func)
+ return TRUE;
+ return context->should_work_func (thread_data);
+}
+
+/*
+ * Tells whether we should lock and attempt to get work from
+ * a higher priority context.
+ */
+static gboolean
+has_priority_work (int worker_index, int current_context)
+{
+ int i;
+
+ for (i = 0; i < current_context; i++) {
+ SgenThreadPoolContext *context = &pool_contexts [i];
+ void *thread_data;
+
+ if (worker_index >= context->num_threads)
+ continue;
+ thread_data = (context->thread_datas) ? context->thread_datas [worker_index] : NULL;
+ if (!should_work (context, thread_data))
+ continue;
+ if (context->job_queue.next_slot > 0)
+ return TRUE;
+ if (continue_idle_job (context, thread_data))
+ return TRUE;
+ }
+
+ /* Return if job enqueued on current context. Jobs have priority over idle work */
+ if (pool_contexts [current_context].job_queue.next_slot > 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * Gets the highest priority work. If there is none, it waits
+ * for work_cond. Should always be called with lock held.
+ */
+static void
+get_work (int worker_index, int *work_context, int *do_idle, SgenThreadPoolJob **job)
+{
+ while (!threadpool_shutdown) {
+ int i;
+
+ for (i = 0; i < contexts_num; i++) {
+ SgenThreadPoolContext *context = &pool_contexts [i];
+ void *thread_data;
+
+ if (worker_index >= context->num_threads)
+ continue;
+ thread_data = (context->thread_datas) ? context->thread_datas [worker_index] : NULL;
+
+ if (!should_work (context, thread_data))
+ continue;
+
+ /*
+ * It's important that we check the continue idle flag with the lock held.
+ * Suppose we didn't check with the lock held, and the result is FALSE. The
+ * main thread might then set continue idle and signal us before we can take
+ * the lock, and we'd lose the signal.
+ */
+ *do_idle = continue_idle_job (context, thread_data);
+ *job = get_job_and_set_in_progress (context);
+
+ if (*job || *do_idle) {
+ *work_context = i;
+ return;
+ }
+ }
+
+ /*
+ * Nothing to do on any context
+ * pthread_cond_wait() can return successfully despite the condition
+ * not being signalled, so we have to run this in a loop until we
+ * really have work to do.
+ */
+ mono_os_cond_wait (&work_cond, &lock);
+ }