2009-07-31 10:06:11 -07:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_EVIL
|
|
|
|
# include <Evil.h>
|
|
|
|
#endif
|
|
|
|
|
2009-11-11 15:43:58 -08:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2009-08-19 23:09:15 -07:00
|
|
|
# include <pthread.h>
|
|
|
|
#endif
|
2009-07-31 10:06:11 -07:00
|
|
|
|
|
|
|
#include "Ecore.h"
|
2009-12-22 13:15:12 -08:00
|
|
|
#include "ecore_private.h"
|
2009-07-31 10:06:11 -07:00
|
|
|
|
|
|
|
typedef struct _Ecore_Pthread_Worker Ecore_Pthread_Worker;
|
|
|
|
typedef struct _Ecore_Pthread Ecore_Pthread;
|
|
|
|
|
|
|
|
struct _Ecore_Pthread_Worker
|
|
|
|
{
|
2010-07-22 13:28:34 -07:00
|
|
|
union
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
void (*func_blocking)(void *data);
|
|
|
|
} short_run;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
void (*func_heavy)(Ecore_Thread *thread, void *data);
|
|
|
|
void (*func_notify)(Ecore_Thread *thread, void *msg_data, void *data);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-22 13:28:34 -07:00
|
|
|
Ecore_Pipe *notify;
|
|
|
|
Eina_Hash *hash;
|
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
|
|
|
pthread_t self;
|
|
|
|
#endif
|
|
|
|
} long_run;
|
|
|
|
} u;
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-22 13:28:34 -07:00
|
|
|
void (*func_cancel)(void *data);
|
|
|
|
void (*func_end)(void *data);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-22 13:28:34 -07:00
|
|
|
const void *data;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-22 13:28:34 -07:00
|
|
|
Eina_Bool cancel : 1;
|
|
|
|
Eina_Bool long_run : 1;
|
2009-11-06 14:15:04 -08:00
|
|
|
};
|
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
|
|
|
typedef struct _Ecore_Pthread_Data Ecore_Pthread_Data;
|
|
|
|
|
2009-11-06 14:15:04 -08:00
|
|
|
struct _Ecore_Pthread_Data
|
|
|
|
{
|
|
|
|
Ecore_Pipe *p;
|
2010-06-30 06:25:28 -07:00
|
|
|
void *data;
|
2009-11-06 14:15:04 -08:00
|
|
|
pthread_t thread;
|
2009-07-31 10:06:11 -07:00
|
|
|
};
|
2009-11-08 14:16:17 -08:00
|
|
|
#endif
|
2009-07-31 10:06:11 -07:00
|
|
|
|
|
|
|
static int _ecore_thread_count_max = 0;
|
2009-11-08 14:16:17 -08:00
|
|
|
static int ECORE_THREAD_PIPE_DEL = 0;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2009-11-11 15:43:58 -08:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2009-11-08 14:16:17 -08:00
|
|
|
static int _ecore_thread_count = 0;
|
2010-07-22 13:28:34 -07:00
|
|
|
static Eina_Hash *_ecore_thread_global_hash = NULL;
|
2010-07-20 02:40:53 -07:00
|
|
|
static Eina_List *_ecore_active_job_threads = NULL;
|
|
|
|
static Eina_List *_ecore_pending_job_threads = NULL;
|
|
|
|
static Eina_List *_ecore_pending_job_threads_long = NULL;
|
2009-07-31 10:06:11 -07:00
|
|
|
static Ecore_Event_Handler *del_handler = NULL;
|
|
|
|
|
|
|
|
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
|
|
|
static void
|
|
|
|
_ecore_thread_pipe_free(void *data __UNUSED__, void *event)
|
|
|
|
{
|
|
|
|
Ecore_Pipe *p = event;
|
|
|
|
|
|
|
|
ecore_pipe_del(p);
|
|
|
|
}
|
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
static Eina_Bool
|
2009-07-31 10:06:11 -07:00
|
|
|
_ecore_thread_pipe_del(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
|
|
|
|
{
|
|
|
|
/* This is a hack to delay pipe destruction until we are out of it's internal loop. */
|
2010-06-24 09:15:56 -07:00
|
|
|
return ECORE_CALLBACK_CANCEL;
|
2009-07-31 10:06:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-11-06 14:15:04 -08:00
|
|
|
_ecore_thread_end(Ecore_Pthread_Data *pth)
|
2009-07-31 10:06:11 -07:00
|
|
|
{
|
|
|
|
Ecore_Pipe *p;
|
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
if (pthread_join(pth->thread, (void **) &p) != 0)
|
2009-07-31 10:06:11 -07:00
|
|
|
return ;
|
|
|
|
|
2010-07-20 02:40:53 -07:00
|
|
|
_ecore_active_job_threads = eina_list_remove(_ecore_active_job_threads, pth);
|
2009-11-06 14:15:04 -08:00
|
|
|
|
|
|
|
ecore_event_add(ECORE_THREAD_PIPE_DEL, pth->p, _ecore_thread_pipe_free, NULL);
|
2009-07-31 10:06:11 -07:00
|
|
|
}
|
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
static void
|
|
|
|
_ecore_thread_handler(void *data __UNUSED__, void *buffer, unsigned int nbyte)
|
2009-07-31 10:06:11 -07:00
|
|
|
{
|
|
|
|
Ecore_Pthread_Worker *work;
|
2009-11-06 14:15:04 -08:00
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
if (nbyte != sizeof (Ecore_Pthread_Worker *)) return ;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
work = *(Ecore_Pthread_Worker **)buffer;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
if (work->cancel)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
if (work->func_cancel)
|
|
|
|
work->func_cancel((void *) work->data);
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
if (work->func_end)
|
|
|
|
work->func_end((void *) work->data);
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
|
2010-07-22 13:28:34 -07:00
|
|
|
if (work->long_run)
|
|
|
|
{
|
|
|
|
ecore_pipe_del(work->u.long_run.notify);
|
|
|
|
eina_hash_free(work->u.long_run.hash);
|
|
|
|
}
|
2010-06-30 06:25:28 -07:00
|
|
|
free(work);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-07-02 04:15:20 -07:00
|
|
|
_ecore_notify_handler(void *data, void *buffer, unsigned int nbyte)
|
2010-06-30 06:25:28 -07:00
|
|
|
{
|
2010-07-02 04:15:20 -07:00
|
|
|
Ecore_Pthread_Worker *work = data;
|
|
|
|
void *user_data;
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
if (nbyte != sizeof (Ecore_Pthread_Worker *)) return ;
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
user_data = *(void **)buffer;
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
if (work->u.long_run.func_notify)
|
2010-07-10 04:08:20 -07:00
|
|
|
work->u.long_run.func_notify((Ecore_Thread *) work, user_data, (void *) work->data);
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_ecore_short_job(Ecore_Pipe *end_pipe)
|
|
|
|
{
|
|
|
|
Ecore_Pthread_Worker *work;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-20 02:40:53 -07:00
|
|
|
while (_ecore_pending_job_threads)
|
2009-07-31 10:06:11 -07:00
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
if (!_ecore_pending_job_threads)
|
|
|
|
{
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
break;
|
|
|
|
}
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
work = eina_list_data_get(_ecore_pending_job_threads);
|
|
|
|
_ecore_pending_job_threads = eina_list_remove_list(_ecore_pending_job_threads, _ecore_pending_job_threads);
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
work->u.short_run.func_blocking((void *) work->data);
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
ecore_pipe_write(end_pipe, &work, sizeof (Ecore_Pthread_Worker *));
|
2009-07-31 10:06:11 -07:00
|
|
|
}
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
static void
|
|
|
|
_ecore_long_job(Ecore_Pipe *end_pipe, pthread_t thread)
|
|
|
|
{
|
|
|
|
Ecore_Pthread_Worker *work;
|
|
|
|
|
2010-07-20 02:40:53 -07:00
|
|
|
while (_ecore_pending_job_threads_long)
|
2009-07-31 10:06:11 -07:00
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
if (!_ecore_pending_job_threads_long)
|
|
|
|
{
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
break;
|
|
|
|
}
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
work = eina_list_data_get(_ecore_pending_job_threads_long);
|
|
|
|
_ecore_pending_job_threads_long = eina_list_remove_list(_ecore_pending_job_threads_long, _ecore_pending_job_threads_long);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
work->u.long_run.self = thread;
|
|
|
|
work->u.long_run.func_heavy((Ecore_Thread *) work, (void *) work->data);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
ecore_pipe_write(end_pipe, &work, sizeof (Ecore_Pthread_Worker *));
|
2009-07-31 10:06:11 -07:00
|
|
|
}
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
static void *
|
|
|
|
_ecore_direct_worker(Ecore_Pthread_Worker *work)
|
|
|
|
{
|
|
|
|
Ecore_Pthread_Data *pth;
|
|
|
|
|
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
|
|
|
|
|
|
|
pth = malloc(sizeof (Ecore_Pthread_Data));
|
|
|
|
if (!pth) return NULL;
|
|
|
|
|
|
|
|
pth->p = ecore_pipe_add(_ecore_thread_handler, NULL);
|
|
|
|
if (!pth->p)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
free(pth);
|
|
|
|
return NULL;
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
pth->thread = pthread_self();
|
|
|
|
|
|
|
|
work->u.long_run.self = pth->thread;
|
2010-07-10 04:08:20 -07:00
|
|
|
work->u.long_run.func_heavy((Ecore_Thread *) work, (void *) work->data);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
ecore_pipe_write(pth->p, &work, sizeof (Ecore_Pthread_Worker *));
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2009-11-06 14:15:04 -08:00
|
|
|
work = malloc(sizeof (Ecore_Pthread_Worker));
|
2010-06-30 06:25:28 -07:00
|
|
|
if (!work)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
ecore_pipe_del(pth->p);
|
|
|
|
free(pth);
|
|
|
|
return NULL;
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2009-11-06 14:15:04 -08:00
|
|
|
work->data = pth;
|
2010-07-02 09:01:21 -07:00
|
|
|
work->u.short_run.func_blocking = NULL;
|
2010-07-10 04:08:20 -07:00
|
|
|
work->func_end = (void *) _ecore_thread_end;
|
2009-11-06 14:15:04 -08:00
|
|
|
work->func_cancel = NULL;
|
|
|
|
work->cancel = EINA_FALSE;
|
2010-06-30 06:25:28 -07:00
|
|
|
work->long_run = EINA_FALSE;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
ecore_pipe_write(pth->p, &work, sizeof (Ecore_Pthread_Worker *));
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2009-11-06 14:15:04 -08:00
|
|
|
return pth->p;
|
2009-07-31 10:06:11 -07:00
|
|
|
}
|
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
static void *
|
|
|
|
_ecore_thread_worker(Ecore_Pthread_Data *pth)
|
2009-07-31 10:06:11 -07:00
|
|
|
{
|
|
|
|
Ecore_Pthread_Worker *work;
|
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
_ecore_thread_count++;
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
on_error:
|
2010-07-20 02:40:53 -07:00
|
|
|
if (_ecore_pending_job_threads) _ecore_short_job(pth->p);
|
|
|
|
if (_ecore_pending_job_threads_long) _ecore_long_job(pth->p, pth->thread);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
/* FIXME: Check if there is long running task todo, and switch to long run handler. */
|
|
|
|
|
|
|
|
pthread_mutex_lock(&_mutex);
|
2010-07-20 02:40:53 -07:00
|
|
|
if (_ecore_pending_job_threads)
|
2009-11-06 14:15:04 -08:00
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
goto on_error;
|
2009-11-06 14:15:04 -08:00
|
|
|
}
|
2010-07-20 02:40:53 -07:00
|
|
|
if (_ecore_pending_job_threads_long)
|
2009-11-06 14:15:04 -08:00
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
goto on_error;
|
2009-11-06 14:15:04 -08:00
|
|
|
}
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
_ecore_thread_count--;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
|
|
|
|
work = malloc(sizeof (Ecore_Pthread_Worker));
|
|
|
|
if (!work) return NULL;
|
|
|
|
|
|
|
|
work->data = pth;
|
2010-07-02 09:01:21 -07:00
|
|
|
work->u.short_run.func_blocking = NULL;
|
2010-07-10 04:08:20 -07:00
|
|
|
work->func_end = (void *) _ecore_thread_end;
|
2010-06-30 06:25:28 -07:00
|
|
|
work->func_cancel = NULL;
|
|
|
|
work->cancel = EINA_FALSE;
|
|
|
|
work->long_run = EINA_FALSE;
|
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
ecore_pipe_write(pth->p, &work, sizeof (Ecore_Pthread_Worker *));
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
return pth->p;
|
2009-07-31 10:06:11 -07:00
|
|
|
}
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2009-07-31 10:06:11 -07:00
|
|
|
#endif
|
|
|
|
|
2009-10-09 20:24:56 -07:00
|
|
|
void
|
2009-09-03 22:49:54 -07:00
|
|
|
_ecore_thread_init(void)
|
2009-07-31 10:06:11 -07:00
|
|
|
{
|
|
|
|
_ecore_thread_count_max = eina_cpu_count();
|
2009-08-03 01:19:33 -07:00
|
|
|
if (_ecore_thread_count_max <= 0)
|
2009-07-31 10:06:11 -07:00
|
|
|
_ecore_thread_count_max = 1;
|
|
|
|
|
|
|
|
ECORE_THREAD_PIPE_DEL = ecore_event_type_new();
|
2009-11-11 15:43:58 -08:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2009-07-31 10:06:11 -07:00
|
|
|
del_handler = ecore_event_handler_add(ECORE_THREAD_PIPE_DEL, _ecore_thread_pipe_del, NULL);
|
2009-08-12 17:30:59 -07:00
|
|
|
#endif
|
2009-07-31 10:06:11 -07:00
|
|
|
}
|
|
|
|
|
2009-10-09 20:24:56 -07:00
|
|
|
void
|
2009-09-03 22:49:54 -07:00
|
|
|
_ecore_thread_shutdown(void)
|
2009-07-31 10:06:11 -07:00
|
|
|
{
|
2009-10-09 20:24:56 -07:00
|
|
|
/* FIXME: If function are still running in the background, should we kill them ? */
|
2009-11-11 15:43:58 -08:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2009-11-06 14:15:04 -08:00
|
|
|
Ecore_Pthread_Worker *work;
|
|
|
|
Ecore_Pthread_Data *pth;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
|
2010-07-20 02:40:53 -07:00
|
|
|
EINA_LIST_FREE(_ecore_pending_job_threads, work)
|
2009-11-06 14:15:04 -08:00
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
if (work->func_cancel)
|
|
|
|
work->func_cancel((void *)work->data);
|
|
|
|
free(work);
|
2009-11-06 14:15:04 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
|
2010-07-20 02:40:53 -07:00
|
|
|
EINA_LIST_FREE(_ecore_active_job_threads, pth)
|
2009-11-06 14:15:04 -08:00
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
Ecore_Pipe *p;
|
2009-11-06 14:15:04 -08:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_cancel(pth->thread);
|
|
|
|
pthread_join(pth->thread, (void **) &p);
|
2009-11-06 14:15:04 -08:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
ecore_pipe_del(pth->p);
|
2009-11-06 14:15:04 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ecore_event_handler_del(del_handler);
|
|
|
|
del_handler = NULL;
|
2009-08-25 22:59:56 -07:00
|
|
|
#endif
|
2009-07-31 10:06:11 -07:00
|
|
|
}
|
2010-07-20 18:04:28 -07:00
|
|
|
/**
|
|
|
|
* @defgroup Ecore_Thread Ecore Thread Functions
|
|
|
|
* These functions allow for ecore-managed threads which integrate with ecore's main loop.
|
2010-07-20 21:26:57 -07:00
|
|
|
*/
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-19 22:25:02 -07:00
|
|
|
/**
|
2010-07-02 09:01:21 -07:00
|
|
|
* @brief Run some blocking code in a parrallel thread to avoid locking the main loop.
|
|
|
|
* @param func_blocking The function that should run in another thread.
|
|
|
|
* @param func_end The function that will be called in the main loop if the thread terminate correctly.
|
|
|
|
* @param func_cancel The function that will be called in the main loop if the thread is cancelled.
|
|
|
|
* @param data User context data to pass to all callback.
|
|
|
|
* @return A reference to the newly created thread instance, or NULL if it failed.
|
|
|
|
*
|
|
|
|
* ecore_thread_run provide a facility for easily managing blocking task in a
|
|
|
|
* parallel thread. You should provide three function. The first one, func_blocking,
|
|
|
|
* that will do the blocking work in another thread (so you should not use the
|
|
|
|
* EFL in it except Eina if you are carefull). The second one, func_end,
|
|
|
|
* that will be called in Ecore main loop when func_blocking is done. So you
|
|
|
|
* can use all the EFL inside this function. The last one, func_cancel, will
|
|
|
|
* be called in the main loop if the thread is cancelled or could not run at all.
|
2009-07-31 10:06:11 -07:00
|
|
|
*
|
|
|
|
* Be aware, that you can't make assumption on the result order of func_end
|
|
|
|
* after many call to ecore_thread_run, as we start as much thread as the
|
|
|
|
* host CPU can handle.
|
|
|
|
*/
|
2009-11-06 14:15:04 -08:00
|
|
|
EAPI Ecore_Thread *
|
2010-07-02 09:01:21 -07:00
|
|
|
ecore_thread_run(void (*func_blocking)(void *data),
|
2010-07-20 21:26:57 -07:00
|
|
|
void (*func_end)(void *data),
|
|
|
|
void (*func_cancel)(void *data),
|
|
|
|
const void *data)
|
2009-07-31 10:06:11 -07:00
|
|
|
{
|
2009-11-11 15:43:58 -08:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2009-07-31 10:06:11 -07:00
|
|
|
Ecore_Pthread_Worker *work;
|
2010-06-30 06:25:28 -07:00
|
|
|
Ecore_Pthread_Data *pth = NULL;
|
|
|
|
|
2010-07-02 09:01:21 -07:00
|
|
|
if (!func_blocking) return NULL;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
|
|
|
work = malloc(sizeof (Ecore_Pthread_Worker));
|
2009-12-21 04:25:32 -08:00
|
|
|
if (!work)
|
|
|
|
{
|
2010-07-10 04:08:20 -07:00
|
|
|
func_cancel((void *) data);
|
2010-07-20 21:26:57 -07:00
|
|
|
return NULL;
|
2009-12-21 04:25:32 -08:00
|
|
|
}
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-02 09:01:21 -07:00
|
|
|
work->u.short_run.func_blocking = func_blocking;
|
2009-07-31 10:06:11 -07:00
|
|
|
work->func_end = func_end;
|
2009-11-06 14:15:04 -08:00
|
|
|
work->func_cancel = func_cancel;
|
|
|
|
work->cancel = EINA_FALSE;
|
2010-06-30 06:25:28 -07:00
|
|
|
work->long_run = EINA_FALSE;
|
2009-07-31 10:06:11 -07:00
|
|
|
work->data = data;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&_mutex);
|
2010-07-20 02:40:53 -07:00
|
|
|
_ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, work);
|
2009-07-31 10:06:11 -07:00
|
|
|
|
|
|
|
if (_ecore_thread_count == _ecore_thread_count_max)
|
2009-08-03 07:09:09 -07:00
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
return (Ecore_Thread *) work;
|
2009-08-03 07:09:09 -07:00
|
|
|
}
|
2009-07-31 10:06:11 -07:00
|
|
|
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
|
|
|
|
/* One more thread could be created. */
|
2009-11-06 14:15:04 -08:00
|
|
|
pth = malloc(sizeof (Ecore_Pthread_Data));
|
2010-06-30 06:25:28 -07:00
|
|
|
if (!pth) goto on_error;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2009-11-06 14:15:04 -08:00
|
|
|
pth->p = ecore_pipe_add(_ecore_thread_handler, NULL);
|
2010-06-30 06:25:28 -07:00
|
|
|
if (!pth->p) goto on_error;
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
if (pthread_create(&pth->thread, NULL, (void *) _ecore_thread_worker, pth) == 0)
|
|
|
|
return (Ecore_Thread *) work;
|
2009-11-06 14:15:04 -08:00
|
|
|
|
|
|
|
on_error:
|
2010-06-30 06:25:28 -07:00
|
|
|
if (pth)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
if (pth->p) ecore_pipe_del(pth->p);
|
|
|
|
free(pth);
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
|
2009-11-06 14:15:04 -08:00
|
|
|
if (_ecore_thread_count == 0)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
if (work->func_cancel)
|
|
|
|
work->func_cancel((void *) work->data);
|
|
|
|
free(work);
|
|
|
|
work = NULL;
|
2009-11-06 14:15:04 -08:00
|
|
|
}
|
2010-07-10 04:08:20 -07:00
|
|
|
return (Ecore_Thread *) work;
|
2009-07-31 10:06:11 -07:00
|
|
|
#else
|
|
|
|
/*
|
|
|
|
If no thread and as we don't want to break app that rely on this
|
|
|
|
facility, we will lock the interface until we are done.
|
|
|
|
*/
|
2010-07-02 09:01:21 -07:00
|
|
|
func_blocking((void *)data);
|
2009-12-19 03:43:44 -08:00
|
|
|
func_end((void *)data);
|
2009-07-31 10:06:11 -07:00
|
|
|
|
2009-12-19 03:43:44 -08:00
|
|
|
return NULL;
|
2009-07-31 10:06:11 -07:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-07-19 22:25:02 -07:00
|
|
|
/**
|
2010-07-02 09:01:21 -07:00
|
|
|
* @brief Cancel a running thread.
|
|
|
|
* @param thread The thread to cancel.
|
|
|
|
* @return Will return EINA_TRUE if the thread has been cancelled,
|
|
|
|
* EINA_FALSE if it is pending.
|
|
|
|
*
|
2009-11-06 14:15:04 -08:00
|
|
|
* ecore_thread_cancel give the possibility to cancel a task still running. It
|
|
|
|
* will return EINA_FALSE, if the destruction is delayed or EINA_TRUE if it is
|
|
|
|
* cancelled after this call.
|
|
|
|
*
|
|
|
|
* You should use this function only in the main loop.
|
|
|
|
*
|
|
|
|
* func_end, func_cancel will destroy the handler, so don't use it after.
|
|
|
|
* And if ecore_thread_cancel return EINA_TRUE, you should not use Ecore_Thread also.
|
|
|
|
*/
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_thread_cancel(Ecore_Thread *thread)
|
|
|
|
{
|
2009-11-11 15:43:58 -08:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2009-11-06 14:15:04 -08:00
|
|
|
Ecore_Pthread_Worker *work;
|
|
|
|
Eina_List *l;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
|
2010-07-20 02:40:53 -07:00
|
|
|
EINA_LIST_FOREACH(_ecore_pending_job_threads, l, work)
|
2010-07-10 04:08:20 -07:00
|
|
|
if ((void *) work == (void *) thread)
|
2009-11-06 14:15:04 -08:00
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
_ecore_pending_job_threads = eina_list_remove_list(_ecore_pending_job_threads, l);
|
2009-11-06 14:15:04 -08:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
2010-04-12 14:51:35 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
if (work->func_cancel)
|
|
|
|
work->func_cancel((void *) work->data);
|
|
|
|
free(work);
|
2009-11-06 14:15:04 -08:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
return EINA_TRUE;
|
2009-11-06 14:15:04 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
|
|
|
|
/* Delay the destruction */
|
2010-07-10 04:08:20 -07:00
|
|
|
((Ecore_Pthread_Worker *)thread)->cancel = EINA_TRUE;
|
2009-11-06 14:15:04 -08:00
|
|
|
return EINA_FALSE;
|
2009-11-08 14:16:17 -08:00
|
|
|
#else
|
2010-02-25 07:26:38 -08:00
|
|
|
return EINA_TRUE;
|
2009-11-08 14:16:17 -08:00
|
|
|
#endif
|
2009-11-06 14:15:04 -08:00
|
|
|
}
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-19 22:25:02 -07:00
|
|
|
/**
|
2010-07-02 09:01:21 -07:00
|
|
|
* @brief Tell if a thread was canceled or not.
|
|
|
|
* @param thread The thread to test.
|
|
|
|
* @return EINA_TRUE if the thread is cancelled,
|
|
|
|
* EINA_FALSE if it is not.
|
|
|
|
*
|
|
|
|
* You can use this function in main loop and in the thread.
|
|
|
|
*/
|
2010-06-30 06:25:28 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_thread_check(Ecore_Thread *thread)
|
|
|
|
{
|
2010-07-10 04:08:20 -07:00
|
|
|
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-02 09:01:21 -07:00
|
|
|
if (!worker) return EINA_TRUE;
|
2010-06-30 06:25:28 -07:00
|
|
|
return worker->cancel;
|
|
|
|
}
|
|
|
|
|
2010-07-19 22:25:02 -07:00
|
|
|
/**
|
2010-07-02 09:01:21 -07:00
|
|
|
* @brief Run some heavy code in a parrallel thread to avoid locking the main loop.
|
|
|
|
* @param func_heavy The function that should run in another thread.
|
|
|
|
* @param func_notify The function that will receive the data send by func_heavy in the main loop.
|
|
|
|
* @param func_end The function that will be called in the main loop if the thread terminate correctly.
|
|
|
|
* @param func_cancel The function that will be called in the main loop if the thread is cancelled.
|
|
|
|
* @param data User context data to pass to all callback.
|
|
|
|
* @param try_no_queue If you wan't to run outside of the thread pool.
|
|
|
|
* @return A reference to the newly created thread instance, or NULL if it failed.
|
|
|
|
*
|
|
|
|
* ecore_long_run provide a facility for easily managing heavy task in a
|
|
|
|
* parallel thread. You should provide four functions. The first one, func_heavy,
|
|
|
|
* that will do the heavy work in another thread (so you should not use the
|
|
|
|
* EFL in it except Eina and Eet if you are carefull). The second one, func_notify,
|
|
|
|
* will receive the data send from the thread function (func_heavy) by ecore_thread_notify
|
|
|
|
* in the main loop (and so, can use all the EFL). Tje third, func_end,
|
|
|
|
* that will be called in Ecore main loop when func_heavy is done. So you
|
|
|
|
* can use all the EFL inside this function. The last one, func_cancel, will
|
|
|
|
* be called in the main loop also, if the thread is cancelled or could not run at all.
|
|
|
|
*
|
|
|
|
* Be aware, that you can't make assumption on the result order of func_end
|
|
|
|
* after many call to ecore_long_run, as we start as much thread as the
|
|
|
|
* host CPU can handle.
|
|
|
|
*
|
|
|
|
* If you set try_no_queue, it will try to run outside of the thread pool, this can bring
|
|
|
|
* the CPU down, so be carefull with that. Of course if it can't start a new thread, it will
|
|
|
|
* try to use one from the pool.
|
|
|
|
*/
|
2010-06-30 06:25:28 -07:00
|
|
|
EAPI Ecore_Thread *
|
|
|
|
ecore_long_run(void (*func_heavy)(Ecore_Thread *thread, void *data),
|
2010-07-20 21:26:57 -07:00
|
|
|
void (*func_notify)(Ecore_Thread *thread, void *msg_data, void *data),
|
|
|
|
void (*func_end)(void *data),
|
|
|
|
void (*func_cancel)(void *data),
|
|
|
|
const void *data,
|
|
|
|
Eina_Bool try_no_queue)
|
2010-06-30 06:25:28 -07:00
|
|
|
{
|
|
|
|
|
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
|
|
|
Ecore_Pthread_Worker *worker;
|
|
|
|
Ecore_Pthread_Data *pth = NULL;
|
|
|
|
|
|
|
|
if (!func_heavy) return NULL;
|
|
|
|
|
|
|
|
worker = malloc(sizeof (Ecore_Pthread_Worker));
|
|
|
|
if (!worker) goto on_error;
|
|
|
|
|
|
|
|
worker->u.long_run.func_heavy = func_heavy;
|
|
|
|
worker->u.long_run.func_notify = func_notify;
|
2010-07-22 13:28:34 -07:00
|
|
|
worker->u.long_run.hash = NULL;
|
2010-06-30 06:25:28 -07:00
|
|
|
worker->func_cancel = func_cancel;
|
|
|
|
worker->func_end = func_end;
|
|
|
|
worker->data = data;
|
|
|
|
worker->cancel = EINA_FALSE;
|
|
|
|
worker->long_run = EINA_TRUE;
|
|
|
|
|
2010-07-02 04:15:20 -07:00
|
|
|
worker->u.long_run.notify = ecore_pipe_add(_ecore_notify_handler, worker);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
if (!try_no_queue)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_t t;
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
if (pthread_create(&t, NULL, (void *) _ecore_direct_worker, worker) == 0)
|
|
|
|
return (Ecore_Thread *) worker;
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_lock(&_mutex);
|
2010-07-20 02:40:53 -07:00
|
|
|
_ecore_pending_job_threads_long = eina_list_append(_ecore_pending_job_threads_long, worker);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
if (_ecore_thread_count == _ecore_thread_count_max)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
return (Ecore_Thread *) worker;
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
|
|
|
|
/* One more thread could be created. */
|
|
|
|
pth = malloc(sizeof (Ecore_Pthread_Data));
|
|
|
|
if (!pth) goto on_error;
|
|
|
|
|
|
|
|
pth->p = ecore_pipe_add(_ecore_thread_handler, NULL);
|
|
|
|
if (pth->p) goto on_error;
|
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
if (pthread_create(&pth->thread, NULL, (void *) _ecore_thread_worker, pth) == 0)
|
|
|
|
return (Ecore_Thread *) worker;
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
on_error:
|
|
|
|
if (pth)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
if (pth->p) ecore_pipe_del(pth->p);
|
|
|
|
free(pth);
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (_ecore_thread_count == 0)
|
|
|
|
{
|
2010-07-20 21:26:57 -07:00
|
|
|
if (func_cancel) func_cancel((void *) data);
|
|
|
|
|
|
|
|
if (worker)
|
|
|
|
{
|
|
|
|
ecore_pipe_del(worker->u.long_run.notify);
|
|
|
|
free(worker);
|
|
|
|
worker = NULL;
|
|
|
|
}
|
2010-06-30 06:25:28 -07:00
|
|
|
}
|
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
return (Ecore_Thread *) worker;
|
2010-06-30 06:25:28 -07:00
|
|
|
#else
|
|
|
|
Ecore_Pthread_Worker worker;
|
|
|
|
|
2010-07-12 07:39:06 -07:00
|
|
|
(void) try_no_queue;
|
|
|
|
|
2010-06-30 06:25:28 -07:00
|
|
|
/*
|
|
|
|
If no thread and as we don't want to break app that rely on this
|
|
|
|
facility, we will lock the interface until we are done.
|
|
|
|
*/
|
|
|
|
worker.u.long_run.func_heavy = func_heavy;
|
|
|
|
worker.u.long_run.func_notify = func_notify;
|
2010-07-22 13:28:34 -07:00
|
|
|
worker->u.long_run.hash = NULL;
|
2010-06-30 06:25:28 -07:00
|
|
|
worker.u.long_run.notify = NULL;
|
|
|
|
worker.func_cancel = func_cancel;
|
|
|
|
worker.func_end = func_end;
|
|
|
|
worker.data = data;
|
|
|
|
worker.cancel = EINA_FALSE;
|
|
|
|
worker.long_run = EINA_TRUE;
|
|
|
|
|
2010-07-10 04:09:40 -07:00
|
|
|
func_heavy((Ecore_Thread *) &worker, (void *)data);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
2010-07-10 04:09:40 -07:00
|
|
|
if (worker.cancel) func_cancel((void *)data);
|
|
|
|
else func_end((void *)data);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-07-19 22:25:02 -07:00
|
|
|
/**
|
2010-07-02 09:01:21 -07:00
|
|
|
* @brief Send data to main loop from worker thread.
|
|
|
|
* @param thread The current Ecore_Thread context to send data from
|
|
|
|
* @param data Data to be transmitted to the main loop
|
|
|
|
* @return EINA_TRUE if data was successfully send to main loop,
|
|
|
|
* EINA_FALSE if anything goes wrong.
|
|
|
|
*
|
|
|
|
* After a succesfull call, the data should be considered owned
|
|
|
|
* by the main loop.
|
|
|
|
*
|
|
|
|
* You should use this function only in the func_heavy call.
|
|
|
|
*/
|
2010-06-30 06:25:28 -07:00
|
|
|
EAPI Eina_Bool
|
2010-07-02 09:01:21 -07:00
|
|
|
ecore_thread_notify(Ecore_Thread *thread, const void *data)
|
2010-06-30 06:25:28 -07:00
|
|
|
{
|
2010-07-10 04:08:20 -07:00
|
|
|
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
if (!worker) return EINA_FALSE;
|
|
|
|
if (!worker->long_run) return EINA_FALSE;
|
|
|
|
|
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
|
|
|
if (worker->u.long_run.self != pthread_self()) return EINA_FALSE;
|
|
|
|
|
2010-07-10 04:08:20 -07:00
|
|
|
ecore_pipe_write(worker->u.long_run.notify, &data, sizeof (void *));
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
#else
|
2010-07-12 07:39:06 -07:00
|
|
|
worker->u.long_run.func_notify(thread, (void*) data, (void*) worker->data);
|
2010-06-30 06:25:28 -07:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-07-20 02:40:18 -07:00
|
|
|
/**
|
|
|
|
* @brief Get number of active thread jobs
|
|
|
|
* @return Number of active threads running jobs
|
|
|
|
* This returns the number of threads currently running jobs through the
|
|
|
|
* ecore_thread api.
|
|
|
|
*/
|
|
|
|
EAPI int
|
|
|
|
ecore_thread_active_get(void)
|
|
|
|
{
|
2010-07-21 01:33:25 -07:00
|
|
|
int ret;
|
2010-07-20 02:40:18 -07:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
ret = _ecore_thread_count;
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
return ret;
|
2010-07-20 02:40:18 -07:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get number of pending (short) thread jobs
|
|
|
|
* @return Number of pending threads running "short" jobs
|
|
|
|
* This returns the number of threads currently running jobs through the
|
|
|
|
* ecore_thread_run api call.
|
|
|
|
*/
|
|
|
|
EAPI int
|
|
|
|
ecore_thread_pending_get(void)
|
|
|
|
{
|
2010-07-21 01:33:25 -07:00
|
|
|
int ret;
|
2010-07-20 02:40:18 -07:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
ret = eina_list_count(_ecore_pending_job_threads);
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
return ret;
|
2010-07-20 02:40:18 -07:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get number of pending long thread jobs
|
|
|
|
* @return Number of pending threads running "long" jobs
|
|
|
|
* This returns the number of threads currently running jobs through the
|
|
|
|
* ecore_long_run api call.
|
|
|
|
*/
|
|
|
|
EAPI int
|
|
|
|
ecore_thread_pending_long_get(void)
|
|
|
|
{
|
2010-07-21 01:33:25 -07:00
|
|
|
int ret;
|
2010-07-20 02:40:18 -07:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
ret = eina_list_count(_ecore_pending_job_threads_long);
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
return ret;
|
2010-07-20 02:40:18 -07:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
2010-07-20 18:04:28 -07:00
|
|
|
|
2010-07-20 21:03:40 -07:00
|
|
|
/**
|
|
|
|
* @brief Get number of pending thread jobs
|
|
|
|
* @return Number of pending threads running jobs
|
|
|
|
* This returns the number of threads currently running jobs through the
|
|
|
|
* ecore_thread_run and ecore_long_run api calls combined.
|
|
|
|
*/
|
|
|
|
EAPI int
|
|
|
|
ecore_thread_pending_total_get(void)
|
|
|
|
{
|
2010-07-21 01:33:25 -07:00
|
|
|
int ret;
|
2010-07-20 21:03:40 -07:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
ret = eina_list_count(_ecore_pending_job_threads) + eina_list_count(_ecore_pending_job_threads_long);
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
return ret;
|
2010-07-20 21:03:40 -07:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
2010-07-20 18:04:28 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the max number of threads that can run simultaneously
|
|
|
|
* @return Max number of threads ecore will run
|
|
|
|
* This returns the total number of threads that ecore will attempt to run
|
|
|
|
* simultaneously.
|
|
|
|
*/
|
|
|
|
EAPI int
|
|
|
|
ecore_thread_max_get(void)
|
|
|
|
{
|
2010-07-21 01:33:25 -07:00
|
|
|
int ret;
|
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
ret = _ecore_thread_count_max;
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
|
2010-07-20 21:26:57 -07:00
|
|
|
return _ecore_thread_count_max;
|
2010-07-20 18:04:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the max number of threads that can run simultaneously
|
|
|
|
* @param num The new maximum
|
|
|
|
* This sets the maximum number of threads that ecore will try to run
|
|
|
|
* simultaneously. This number cannot be < 1 or >= 2x the number of active cpus.
|
|
|
|
*/
|
|
|
|
EAPI void
|
|
|
|
ecore_thread_max_set(int num)
|
|
|
|
{
|
|
|
|
if (num < 1) return;
|
|
|
|
/* avoid doing something hilarious by blocking dumb users */
|
|
|
|
if (num >= (2 * eina_cpu_count())) return;
|
|
|
|
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
2010-07-20 18:04:28 -07:00
|
|
|
_ecore_thread_count_max = num;
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
2010-07-20 18:04:28 -07:00
|
|
|
}
|
2010-07-20 19:12:10 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Reset the max number of threads that can run simultaneously
|
|
|
|
* This resets the maximum number of threads that ecore will try to run
|
|
|
|
* simultaneously to the number of active cpus.
|
|
|
|
*/
|
|
|
|
EAPI void
|
|
|
|
ecore_thread_max_reset(void)
|
|
|
|
{
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
2010-07-20 19:12:10 -07:00
|
|
|
_ecore_thread_count_max = eina_cpu_count();
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_unlock(&_mutex);
|
2010-07-20 19:12:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the number of threads which are available to be used
|
|
|
|
* @return The number of available threads
|
|
|
|
* This returns the number of threads slots that ecore has currently available.
|
|
|
|
* Assuming that you haven't changed the max number of threads with @ref ecore_thread_max_set
|
|
|
|
* this should be equal to (num_cpus - (active_running + active_long_running))
|
|
|
|
*/
|
|
|
|
EAPI int
|
2010-07-21 00:09:51 -07:00
|
|
|
ecore_thread_available_get(void)
|
2010-07-20 19:12:10 -07:00
|
|
|
{
|
2010-07-21 01:33:25 -07:00
|
|
|
int ret;
|
2010-07-20 19:12:10 -07:00
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
2010-07-21 01:33:25 -07:00
|
|
|
pthread_mutex_lock(&_mutex);
|
|
|
|
ret = _ecore_thread_count_max - _ecore_thread_count;
|
|
|
|
pthread_mutex_unlock(&_mutex);
|
|
|
|
return ret;
|
2010-07-20 19:12:10 -07:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
2010-07-22 13:28:34 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add data to the pool for subsequent uses
|
|
|
|
* @param thread The thread context to add to
|
|
|
|
* @param key The name string to add the data with
|
|
|
|
* @param value The data to add
|
2010-07-22 20:39:52 -07:00
|
|
|
* @param direct If true, this will not copy the key string (like eina_hash_direct_add)
|
2010-07-22 13:28:34 -07:00
|
|
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
|
|
|
* This adds data to the thread context, allowing for subsequent users of the thread's pool
|
|
|
|
* to retrieve and use it without complicated mutexing. This function can only be called by a
|
|
|
|
* heavy_run thread INSIDE the thread and will return EINA_FALSE in any case but success.
|
|
|
|
* All data added to the thread pool must be freed in the thread's func_end/func_cancel
|
|
|
|
* functions to avoid leaks.
|
|
|
|
*/
|
|
|
|
EAPI Eina_Bool
|
2010-07-22 20:39:52 -07:00
|
|
|
ecore_thread_pool_data_add(Ecore_Thread *thread, const char *key, const void *value, Eina_Bool direct)
|
2010-07-22 13:28:34 -07:00
|
|
|
{
|
|
|
|
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
|
|
|
|
if ((!thread) || (!key) || (!value))
|
|
|
|
return EINA_FALSE;
|
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
|
|
|
if (worker->u.long_run.self != pthread_self()) return EINA_FALSE;
|
|
|
|
|
|
|
|
if (!worker->u.long_run.hash)
|
|
|
|
worker->u.long_run.hash = eina_hash_string_small_new(NULL);
|
|
|
|
|
|
|
|
if (!worker->u.long_run.hash)
|
|
|
|
return EINA_FALSE;
|
2010-07-22 20:39:52 -07:00
|
|
|
if (direct)
|
|
|
|
return eina_hash_direct_add(worker->u.long_run.hash, key, value);
|
2010-07-22 13:28:34 -07:00
|
|
|
return eina_hash_add(worker->u.long_run.hash, key, value);
|
|
|
|
#else
|
|
|
|
return EINA_TRUE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-07-22 20:39:52 -07:00
|
|
|
|
2010-07-22 13:28:34 -07:00
|
|
|
/**
|
|
|
|
* @brief Find data in the pool's data
|
|
|
|
* @param thread The thread context
|
|
|
|
* @param key The name string the data is associated with
|
|
|
|
* @return The value, or NULL on error
|
|
|
|
* This finds data in the thread context that has been previously added with @ref ecore_thread_pool_data_add
|
|
|
|
* This function can only be called by a heavy_run thread INSIDE the thread, and will return NULL
|
|
|
|
* in any case but success.
|
|
|
|
*/
|
|
|
|
|
|
|
|
EAPI void *
|
|
|
|
ecore_thread_pool_data_find(Ecore_Thread *thread, const char *key)
|
|
|
|
{
|
|
|
|
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
|
|
|
|
if ((!thread) || (!key))
|
|
|
|
return NULL;
|
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
|
|
|
if (worker->u.long_run.self != pthread_self()) return NULL;
|
|
|
|
|
|
|
|
if (!worker->u.long_run.hash)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return eina_hash_find(worker->u.long_run.hash, key);
|
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Delete data from the pool's data
|
|
|
|
* @param thread The thread context
|
|
|
|
* @param key The name string the data is associated with
|
|
|
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
|
|
|
* This deletes the data pointer from the thread context which was previously added with @ref ecore_thread_pool_data_add
|
|
|
|
* This function can only be called by a heavy_run thread INSIDE the thread, and will return EINA_FALSE
|
|
|
|
* in any case but success. Note that this WILL NOT free the data, it merely removes it from the thread pool.
|
|
|
|
*/
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_thread_pool_data_del(Ecore_Thread *thread, const char *key)
|
|
|
|
{
|
|
|
|
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
|
|
|
|
if ((!thread) || (!key))
|
|
|
|
return EINA_FALSE;
|
|
|
|
#ifdef EFL_HAVE_PTHREAD
|
|
|
|
if (worker->u.long_run.self != pthread_self()) return EINA_FALSE;
|
|
|
|
|
|
|
|
if (!worker->u.long_run.hash)
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
|
|
|
return eina_hash_del_by_key(worker->u.long_run.hash, key);
|
|
|
|
#else
|
|
|
|
return EINA_TRUE;
|
|
|
|
#endif
|
|
|
|
}
|