X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgioscheduler.c;h=4c826c67ee4a743ddd651fd46e631b9fedadf8fb;hb=d9ad40b4eaf1a9197ab363de4346a8d84f45f5c1;hp=178726665eb3c059f6bd6b83ec0fbdae65c1a409;hpb=10ba0c2e5c6ed069420ec926c1094331c44fb71e;p=platform%2Fupstream%2Fglib.git
diff --git a/gio/gioscheduler.c b/gio/gioscheduler.c
index 1787266..4c826c6 100644
--- a/gio/gioscheduler.c
+++ b/gio/gioscheduler.c
@@ -13,9 +13,7 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see .
*
* Author: Alexander Larsson
*/
@@ -24,154 +22,59 @@
#include "gioscheduler.h"
#include "gcancellable.h"
-
-#include "gioalias.h"
+#include "gtask.h"
/**
* SECTION:gioscheduler
* @short_description: I/O Scheduler
* @include: gio/gio.h
*
+ * As of GLib 2.36, #GIOScheduler is deprecated in favor of
+ * #GThreadPool and #GTask.
+ *
* Schedules asynchronous I/O operations. #GIOScheduler integrates
- * into the main event loop (#GMainLoop) and may use threads if they
- * are available.
- *
- * I/O priority
- * Each I/O operation has a priority, and the scheduler uses the priorities
- * to determine the order in which operations are executed. They are
- * not used to determine system-wide I/O scheduling.
- * Priorities are integers, with lower numbers indicating higher priority.
- * It is recommended to choose priorities between %G_PRIORITY_LOW and
- * %G_PRIORITY_HIGH, with %G_PRIORITY_DEFAULT as a default.
- *
- **/
+ * into the main event loop (#GMainLoop) and uses threads.
+ */
struct _GIOSchedulerJob {
- GSList *active_link;
+ GList *active_link;
+ GTask *task;
+
GIOSchedulerJobFunc job_func;
- GSourceFunc cancel_func; /* Runs under job map lock */
gpointer data;
GDestroyNotify destroy_notify;
- gint io_priority;
GCancellable *cancellable;
+ gulong cancellable_id;
GMainContext *context;
-
- guint idle_tag;
};
G_LOCK_DEFINE_STATIC(active_jobs);
-static GSList *active_jobs = NULL;
-
-static GThreadPool *job_thread_pool = NULL;
-
-static void io_job_thread (gpointer data,
- gpointer user_data);
+static GList *active_jobs = NULL;
static void
g_io_job_free (GIOSchedulerJob *job)
{
- if (job->cancellable)
- g_object_unref (job->cancellable);
- if (job->context)
- g_main_context_unref (job->context);
- g_free (job);
-}
-
-static gint
-g_io_job_compare (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
-{
- const GIOSchedulerJob *aa = a;
- const GIOSchedulerJob *bb = b;
-
- /* Cancelled jobs are set prio == -1, so that
- they are executed as quickly as possible */
-
- /* Lower value => higher priority */
- if (aa->io_priority < bb->io_priority)
- return -1;
- if (aa->io_priority == bb->io_priority)
- return 0;
- return 1;
-}
-
-static gpointer
-init_scheduler (gpointer arg)
-{
- if (job_thread_pool == NULL)
- {
- /* TODO: thread_pool_new can fail */
- job_thread_pool = g_thread_pool_new (io_job_thread,
- NULL,
- 10,
- FALSE,
- NULL);
- if (job_thread_pool != NULL)
- {
- g_thread_pool_set_sort_function (job_thread_pool,
- g_io_job_compare,
- NULL);
- /* It's kinda weird that this is a global setting
- * instead of per threadpool. However, we really
- * want to cache some threads, but not keep around
- * those threads forever. */
- g_thread_pool_set_max_idle_time (15 * 1000);
- g_thread_pool_set_max_unused_threads (2);
- }
- }
- return NULL;
-}
+ if (job->destroy_notify)
+ job->destroy_notify (job->data);
-static void
-remove_active_job (GIOSchedulerJob *job)
-{
- GIOSchedulerJob *other_job;
- GSList *l;
- gboolean resort_jobs;
-
G_LOCK (active_jobs);
- active_jobs = g_slist_delete_link (active_jobs, job->active_link);
-
- resort_jobs = FALSE;
- for (l = active_jobs; l != NULL; l = l->next)
- {
- other_job = l->data;
- if (other_job->io_priority >= 0 &&
- g_cancellable_is_cancelled (other_job->cancellable))
- {
- other_job->io_priority = -1;
- resort_jobs = TRUE;
- }
- }
+ active_jobs = g_list_delete_link (active_jobs, job->active_link);
G_UNLOCK (active_jobs);
-
- if (resort_jobs &&
- job_thread_pool != NULL)
- g_thread_pool_set_sort_function (job_thread_pool,
- g_io_job_compare,
- NULL);
+ if (job->cancellable)
+ g_object_unref (job->cancellable);
+ g_main_context_unref (job->context);
+ g_slice_free (GIOSchedulerJob, job);
}
static void
-job_destroy (gpointer data)
-{
- GIOSchedulerJob *job = data;
-
- if (job->destroy_notify)
- job->destroy_notify (job->data);
-
- remove_active_job (job);
- g_io_job_free (job);
-}
-
-static void
-io_job_thread (gpointer data,
- gpointer user_data)
+io_job_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
{
- GIOSchedulerJob *job = data;
+ GIOSchedulerJob *job = task_data;
gboolean result;
if (job->cancellable)
@@ -185,37 +88,18 @@ io_job_thread (gpointer data,
if (job->cancellable)
g_cancellable_pop_current (job->cancellable);
-
- job_destroy (job);
-}
-
-static gboolean
-run_job_at_idle (gpointer data)
-{
- GIOSchedulerJob *job = data;
- gboolean result;
-
- if (job->cancellable)
- g_cancellable_push_current (job->cancellable);
-
- result = job->job_func (job, job->cancellable, job->data);
-
- if (job->cancellable)
- g_cancellable_pop_current (job->cancellable);
-
- return result;
}
/**
* g_io_scheduler_push_job:
* @job_func: a #GIOSchedulerJobFunc.
* @user_data: data to pass to @job_func
- * @notify: a #GDestroyNotify for @user_data, or %NULL
- * @io_priority: the I/O priority
+ * @notify: (allow-none): a #GDestroyNotify for @user_data, or %NULL
+ * @io_priority: the [I/O priority][io-priority]
* of the request.
* @cancellable: optional #GCancellable object, %NULL to ignore.
*
- * Schedules the I/O job to run.
+ * Schedules the I/O job to run in another thread.
*
* @notify will be called on @user_data after @job_func has returned,
* regardless whether the job was cancelled or has run to completion.
@@ -223,6 +107,8 @@ run_job_at_idle (gpointer data)
* If @cancellable is not %NULL, it can be used to cancel the I/O job
* by calling g_cancellable_cancel() or by calling
* g_io_scheduler_cancel_all_jobs().
+ *
+ * Deprecated: use #GThreadPool or g_task_run_in_thread()
**/
void
g_io_scheduler_push_job (GIOSchedulerJobFunc job_func,
@@ -231,43 +117,31 @@ g_io_scheduler_push_job (GIOSchedulerJobFunc job_func,
gint io_priority,
GCancellable *cancellable)
{
- static GOnce once_init = G_ONCE_INIT;
GIOSchedulerJob *job;
+ GTask *task;
g_return_if_fail (job_func != NULL);
- job = g_new0 (GIOSchedulerJob, 1);
+ job = g_slice_new0 (GIOSchedulerJob);
job->job_func = job_func;
job->data = user_data;
job->destroy_notify = notify;
- job->io_priority = io_priority;
-
+
if (cancellable)
job->cancellable = g_object_ref (cancellable);
- job->context = g_main_context_get_thread_default ();
- if (job->context)
- g_main_context_ref (job->context);
+ job->context = g_main_context_ref_thread_default ();
G_LOCK (active_jobs);
- active_jobs = g_slist_prepend (active_jobs, job);
+ active_jobs = g_list_prepend (active_jobs, job);
job->active_link = active_jobs;
G_UNLOCK (active_jobs);
- if (g_thread_supported())
- {
- g_once (&once_init, init_scheduler, NULL);
- g_thread_pool_push (job_thread_pool, job, NULL);
- }
- else
- {
- /* Threads not available, instead do the i/o sync inside a
- * low prio idle handler
- */
- job->idle_tag = g_idle_add_full (io_priority,
- run_job_at_idle,
- job, job_destroy);
- }
+ task = g_task_new (NULL, cancellable, NULL, NULL);
+ g_task_set_task_data (task, job, (GDestroyNotify)g_io_job_free);
+ g_task_set_priority (task, io_priority);
+ g_task_run_in_thread (task, io_job_thread);
+ g_object_unref (task);
}
/**
@@ -277,11 +151,15 @@ g_io_scheduler_push_job (GIOSchedulerJobFunc job_func,
*
* A job is cancellable if a #GCancellable was passed into
* g_io_scheduler_push_job().
+ *
+ * Deprecated: You should never call this function, since you don't
+ * know how other libraries in your program might be making use of
+ * gioscheduler.
**/
void
g_io_scheduler_cancel_all_jobs (void)
{
- GSList *cancellable_list, *l;
+ GList *cancellable_list, *l;
G_LOCK (active_jobs);
cancellable_list = NULL;
@@ -289,8 +167,8 @@ g_io_scheduler_cancel_all_jobs (void)
{
GIOSchedulerJob *job = l->data;
if (job->cancellable)
- cancellable_list = g_slist_prepend (cancellable_list,
- g_object_ref (job->cancellable));
+ cancellable_list = g_list_prepend (cancellable_list,
+ g_object_ref (job->cancellable));
}
G_UNLOCK (active_jobs);
@@ -300,7 +178,7 @@ g_io_scheduler_cancel_all_jobs (void)
g_cancellable_cancel (c);
g_object_unref (c);
}
- g_slist_free (cancellable_list);
+ g_list_free (cancellable_list);
}
typedef struct {
@@ -309,8 +187,9 @@ typedef struct {
gpointer data;
GDestroyNotify notify;
- GMutex *ack_lock;
- GCond *ack_condition;
+ GMutex ack_lock;
+ GCond ack_condition;
+ gboolean ack;
} MainLoopProxy;
static gboolean
@@ -322,26 +201,20 @@ mainloop_proxy_func (gpointer data)
if (proxy->notify)
proxy->notify (proxy->data);
-
- if (proxy->ack_lock)
- {
- g_mutex_lock (proxy->ack_lock);
- g_cond_signal (proxy->ack_condition);
- g_mutex_unlock (proxy->ack_lock);
- }
-
+
+ g_mutex_lock (&proxy->ack_lock);
+ proxy->ack = TRUE;
+ g_cond_signal (&proxy->ack_condition);
+ g_mutex_unlock (&proxy->ack_lock);
+
return FALSE;
}
static void
mainloop_proxy_free (MainLoopProxy *proxy)
{
- if (proxy->ack_lock)
- {
- g_mutex_free (proxy->ack_lock);
- g_cond_free (proxy->ack_condition);
- }
-
+ g_mutex_clear (&proxy->ack_lock);
+ g_cond_clear (&proxy->ack_condition);
g_free (proxy);
}
@@ -350,13 +223,15 @@ mainloop_proxy_free (MainLoopProxy *proxy)
* @job: a #GIOSchedulerJob
* @func: a #GSourceFunc callback that will be called in the original thread
* @user_data: data to pass to @func
- * @notify: a #GDestroyNotify for @user_data, or %NULL
+ * @notify: (allow-none): a #GDestroyNotify for @user_data, or %NULL
*
* Used from an I/O job to send a callback to be run in the thread
* that the job was started from, waiting for the result (and thus
* blocking the I/O job).
*
* Returns: The return value of @func
+ *
+ * Deprecated: Use g_main_context_invoke().
**/
gboolean
g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job,
@@ -371,35 +246,26 @@ g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job,
g_return_val_if_fail (job != NULL, FALSE);
g_return_val_if_fail (func != NULL, FALSE);
- if (job->idle_tag)
- {
- /* We just immediately re-enter in the case of idles (non-threads)
- * Anything else would just deadlock. If you can't handle this, enable threads.
- */
- ret_val = func (user_data);
- if (notify)
- notify (user_data);
- return ret_val;
- }
-
proxy = g_new0 (MainLoopProxy, 1);
proxy->func = func;
proxy->data = user_data;
proxy->notify = notify;
- proxy->ack_lock = g_mutex_new ();
- proxy->ack_condition = g_cond_new ();
- g_mutex_lock (proxy->ack_lock);
-
+ g_mutex_init (&proxy->ack_lock);
+ g_cond_init (&proxy->ack_condition);
+ g_mutex_lock (&proxy->ack_lock);
+
source = g_idle_source_new ();
g_source_set_priority (source, G_PRIORITY_DEFAULT);
g_source_set_callback (source, mainloop_proxy_func, proxy,
NULL);
+ g_source_set_name (source, "[gio] mainloop_proxy_func");
g_source_attach (source, job->context);
g_source_unref (source);
- g_cond_wait (proxy->ack_condition, proxy->ack_lock);
- g_mutex_unlock (proxy->ack_lock);
+ while (!proxy->ack)
+ g_cond_wait (&proxy->ack_condition, &proxy->ack_lock);
+ g_mutex_unlock (&proxy->ack_lock);
ret_val = proxy->ret_val;
mainloop_proxy_free (proxy);
@@ -412,7 +278,7 @@ g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job,
* @job: a #GIOSchedulerJob
* @func: a #GSourceFunc callback that will be called in the original thread
* @user_data: data to pass to @func
- * @notify: a #GDestroyNotify for @user_data, or %NULL
+ * @notify: (allow-none): a #GDestroyNotify for @user_data, or %NULL
*
* Used from an I/O job to send a callback to be run asynchronously in
* the thread that the job was started from. The callback will be run
@@ -423,6 +289,8 @@ g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job,
* on to this function you have to ensure that it is not freed before
* @func is called, either by passing %NULL as @notify to
* g_io_scheduler_push_job() or by using refcounting for @user_data.
+ *
+ * Deprecated: Use g_main_context_invoke().
**/
void
g_io_scheduler_job_send_to_mainloop_async (GIOSchedulerJob *job,
@@ -436,31 +304,19 @@ g_io_scheduler_job_send_to_mainloop_async (GIOSchedulerJob *job,
g_return_if_fail (job != NULL);
g_return_if_fail (func != NULL);
- if (job->idle_tag)
- {
- /* We just immediately re-enter in the case of idles (non-threads)
- * Anything else would just deadlock. If you can't handle this, enable threads.
- */
- func (user_data);
- if (notify)
- notify (user_data);
- return;
- }
-
proxy = g_new0 (MainLoopProxy, 1);
proxy->func = func;
proxy->data = user_data;
proxy->notify = notify;
-
+ g_mutex_init (&proxy->ack_lock);
+ g_cond_init (&proxy->ack_condition);
+
source = g_idle_source_new ();
g_source_set_priority (source, G_PRIORITY_DEFAULT);
g_source_set_callback (source, mainloop_proxy_func, proxy,
(GDestroyNotify)mainloop_proxy_free);
+ g_source_set_name (source, "[gio] mainloop_proxy_func");
g_source_attach (source, job->context);
g_source_unref (source);
}
-
-
-#define __G_IO_SCHEDULER_C__
-#include "gioaliasdef.c"