#endif
#include <sys/time.h>
+#include <assert.h>
#ifdef HAVE_EVIL
# include <Evil.h>
CloseHandle(x->thread);
}
if (res) *res = x->val;
+ free(x);
return 0;
}
LONG readers_count;
LONG writers_count;
int readers;
- int writers;
+ int writers;
LK(mutex);
CD(cond_read);
CD(cond_write);
Eina_Bool cancel : 1;
Eina_Bool feedback_run : 1;
Eina_Bool kill : 1;
+ Eina_Bool reschedule : 1;
+ Eina_Bool no_queue : 1;
};
#ifdef EFL_HAVE_THREADS
static LK(_ecore_thread_global_hash_mutex);
static CD(_ecore_thread_global_hash_cond);
-static PH(main_loop_thread);
+static LK(_ecore_main_loop_mutex);
static Eina_Bool have_main_loop_thread = 0;
static Eina_Trash *_ecore_thread_worker_trash = NULL;
static int _ecore_thread_worker_count = 0;
+static void *_ecore_thread_worker(Ecore_Pthread_Data *pth);
+static Ecore_Pthread_Worker *_ecore_thread_worker_new(void);
+
+static PH(get_main_loop_thread)(void)
+{
+ static PH(main_loop_thread);
+ static pid_t main_loop_pid;
+ pid_t pid = getpid();
+
+ if (pid != main_loop_pid)
+ {
+ main_loop_pid = pid;
+ main_loop_thread = PHS();
+ have_main_loop_thread = 1;
+ }
+
+ return main_loop_thread;
+}
+
static void
_ecore_thread_worker_free(Ecore_Pthread_Worker *worker)
{
{
Ecore_Pipe *p = event;
- eina_array_push(_ecore_thread_pipe, p);
+ if (eina_array_count_get(_ecore_thread_pipe) < 50)
+ eina_array_push(_ecore_thread_pipe, p);
+ else
+ ecore_pipe_del(p);
eina_threads_shutdown();
}
}
static void
-_ecore_thread_end(Ecore_Pthread_Data *pth, __UNUSED__ Ecore_Thread *work)
+_ecore_thread_end(Ecore_Pthread_Data *pth, Ecore_Thread *work)
{
+ Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) work;
Ecore_Pipe *p;
+ if (!worker->feedback_run || (worker->feedback_run && !worker->no_queue))
+ _ecore_thread_count--;
+
if (PHJ(pth->thread, p) != 0)
return ;
+ if (eina_list_count(_ecore_pending_job_threads) > 0
+ && (unsigned int) _ecore_thread_count < eina_list_count(_ecore_pending_job_threads)
+ && _ecore_thread_count < _ecore_thread_count_max)
+ {
+ /* One more thread should be created. */
+ INF("spawning threads because of still pending jobs.");
+
+ pth->death_job = _ecore_thread_worker_new();
+ if (!pth->p || !pth->death_job) goto end;
+
+ eina_threads_init();
+
+ if (PHC(pth->thread, _ecore_thread_worker, pth) == 0)
+ {
+ _ecore_thread_count++;
+ return ;
+ }
+
+ eina_threads_shutdown();
+
+ end:
+ if (pth->death_job) _ecore_thread_worker_free(pth->death_job);
+ }
+
_ecore_active_job_threads = eina_list_remove(_ecore_active_job_threads, pth);
ecore_event_add(ECORE_THREAD_PIPE_DEL, pth->p, _ecore_thread_pipe_free, NULL);
if (!work->cancel)
work->u.short_run.func_blocking((void *) work->data, (Ecore_Thread*) work);
- ecore_pipe_write(end_pipe, &work, sizeof (Ecore_Pthread_Worker *));
+ if (work->reschedule)
+ {
+ work->reschedule = EINA_FALSE;
+
+ LKL(_ecore_pending_job_threads_mutex);
+ _ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, work);
+ LKU(_ecore_pending_job_threads_mutex);
+ }
+ else
+ {
+ ecore_pipe_write(end_pipe, &work, sizeof (Ecore_Pthread_Worker *));
+ }
}
}
if (!work->cancel)
work->u.feedback_run.func_heavy((void *) work->data, (Ecore_Thread *) work);
- ecore_pipe_write(end_pipe, &work, sizeof (Ecore_Pthread_Worker *));
+ if (work->reschedule)
+ {
+ work->reschedule = EINA_FALSE;
+
+ LKL(_ecore_pending_job_threads_mutex);
+ _ecore_pending_job_threads_feedback = eina_list_append(_ecore_pending_job_threads_feedback, work);
+ LKU(_ecore_pending_job_threads_mutex);
+ }
+ else
+ {
+ ecore_pipe_write(end_pipe, &work, sizeof (Ecore_Pthread_Worker *));
+ }
}
}
eina_sched_prio_drop();
- LKL(_ecore_pending_job_threads_mutex);
- _ecore_thread_count++;
- LKU(_ecore_pending_job_threads_mutex);
-
restart:
if (_ecore_pending_job_threads) _ecore_short_job(pth->p);
if (_ecore_pending_job_threads_feedback) _ecore_feedback_job(pth->p, pth->thread);
LKU(_ecore_pending_job_threads_mutex);
/* Sleep a little to prevent premature death */
+#ifdef _WIN32
+ Sleep(1); /* around 50ms */
+#else
usleep(200);
+#endif
LKL(_ecore_pending_job_threads_mutex);
if (_ecore_pending_job_threads || _ecore_pending_job_threads_feedback)
LKU(_ecore_pending_job_threads_mutex);
goto restart;
}
- _ecore_thread_count--;
LKU(_ecore_pending_job_threads_mutex);
work = pth->death_job;
#ifdef EFL_HAVE_THREADS
del_handler = ecore_event_handler_add(ECORE_THREAD_PIPE_DEL, _ecore_thread_pipe_del, NULL);
- main_loop_thread = PHS();
- have_main_loop_thread = 1;
LKI(_ecore_pending_job_threads_mutex);
LRWKI(_ecore_thread_global_hash_lock);
LKI(_ecore_thread_global_hash_mutex);
+ LKI(_ecore_main_loop_mutex);
CDI(_ecore_thread_global_hash_cond);
#endif
}
/* Improve emergency shutdown */
EINA_LIST_FREE(_ecore_active_job_threads, pth)
{
- Ecore_Pipe *p;
+ Ecore_Pipe *ep;
PHA(pth->thread);
- PHJ(pth->thread, p);
+ PHJ(pth->thread, ep);
ecore_pipe_del(pth->p);
}
_ecore_thread_pipe = NULL;
}
-/**
- * @addtogroup Ecore_Group Ecore - Main Loop and Job Functions.
- *
- * @{
- */
-
-/**
- * @addtogroup Ecore_Thread_Group Ecore Thread functions
- *
- * These functions allow for ecore-managed threads which integrate with ecore's main loop.
- *
- * @{
- */
-
-/**
- * @brief Run some blocking code in a parallel 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 careful). 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.
- *
- * 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.
- */
+void
+_ecore_thread_assert_main_loop_thread(const char *function)
+{
+ Eina_Bool good;
+#ifdef EFL_HAVE_THREADS
+ good = PHE(get_main_loop_thread(), PHS());
+#else
+ good = EINA_TRUE;
+#endif
+ if (!good)
+ {
+ EINA_LOG_CRIT("Call to %s from wrong thread!", function);
+#if 0
+ abort();
+#endif
+ }
+}
+
+#ifdef HAVE_THREAD_SAFETY
+static int lock_count;
+
+void
+_ecore_lock(void)
+{
+ LKL(_ecore_main_loop_mutex);
+ lock_count++;
+ assert(lock_count == 1);
+}
+
+void
+_ecore_unlock(void)
+{
+ lock_count--;
+ assert(lock_count == 0);
+ LKU(_ecore_main_loop_mutex);
+}
+#endif
+
EAPI Ecore_Thread *
ecore_thread_run(Ecore_Thread_Cb func_blocking,
Ecore_Thread_Cb func_end,
work->cancel = EINA_FALSE;
work->feedback_run = EINA_FALSE;
work->kill = EINA_FALSE;
+ work->reschedule = EINA_FALSE;
work->data = data;
#ifdef EFL_HAVE_THREADS
eina_threads_init();
if (PHC(pth->thread, _ecore_thread_worker, pth) == 0)
- return (Ecore_Thread *) work;
+ {
+ _ecore_thread_count++;
+ return (Ecore_Thread *) work;
+ }
eina_threads_shutdown();
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.
*/
- func_blocking((void *)data, (Ecore_Thread *) work);
- if (work->cancel == EINA_FALSE) func_end((void *)data, (Ecore_Thread *) work);
- else func_end((void *)data, (Ecore_Thread *) work);
+ do {
+ /* Handle reschedule by forcing it here. That would mean locking the app,
+ * would be better with an idler, but really to complex for a case where
+ * thread should really exist.
+ */
+ work->reschedule = EINA_FALSE;
+
+ func_blocking((void *)data, (Ecore_Thread *) work);
+ if (work->cancel == EINA_FALSE) func_end((void *)data, (Ecore_Thread *) work);
+ else func_cancel((void *)data, (Ecore_Thread *) work);
+
+ } while (work->reschedule == EINA_TRUE);
free(work);
#endif
}
-/**
- * @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.
- *
- * 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.
- *
- * This function work in the main loop and in the thread, but you should not pass
- * the Ecore_Thread variable from main loop to the worker thread in any structure.
- * You should always use the one passed to the Ecore_Thread_Heavy_Cb.
- *
- * 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)
{
LKL(_ecore_pending_job_threads_mutex);
if ((have_main_loop_thread) &&
- (PHE(main_loop_thread, PHS())))
+ (PHE(get_main_loop_thread(), PHS())))
{
if (!work->feedback_run)
EINA_LIST_FOREACH(_ecore_pending_job_threads, l, work)
#endif
}
-/**
- * @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.
- */
EAPI Eina_Bool
ecore_thread_check(Ecore_Thread *thread)
{
return worker->cancel;
}
-/**
- * @brief Run some heavy code in a parallel 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 want to run outside of the thread pool.
- * @return A reference to the newly created thread instance, or NULL if it failed.
- *
- * ecore_thread_feedback_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 careful). 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). The 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_feedback_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 careful with that. Of course if it can't start a new thread, it will
- * try to use one from the pool.
- */
EAPI Ecore_Thread *ecore_thread_feedback_run(Ecore_Thread_Cb func_heavy,
Ecore_Thread_Notify_Cb func_notify,
Ecore_Thread_Cb func_end,
worker->cancel = EINA_FALSE;
worker->feedback_run = EINA_TRUE;
worker->kill = EINA_FALSE;
+ worker->reschedule = EINA_FALSE;
+
worker->u.feedback_run.send = 0;
worker->u.feedback_run.received = 0;
worker->u.feedback_run.direct_pipe = _ecore_thread_pipe_get();
worker->u.feedback_run.direct_worker = _ecore_thread_worker_new();
+ worker->no_queue = EINA_TRUE;
+
+ eina_threads_init();
if (PHC(t, _ecore_direct_worker, worker) == 0)
return (Ecore_Thread *) worker;
+
+ eina_threads_shutdown();
}
+ worker->no_queue = EINA_FALSE;
+
LKL(_ecore_pending_job_threads_mutex);
_ecore_pending_job_threads_feedback = eina_list_append(_ecore_pending_job_threads_feedback, worker);
eina_threads_init();
if (PHC(pth->thread, _ecore_thread_worker, pth) == 0)
- return (Ecore_Thread *) worker;
+ {
+ _ecore_thread_count++;
+ return (Ecore_Thread *) worker;
+ }
eina_threads_shutdown();
worker.feedback_run = EINA_TRUE;
worker.kill = EINA_FALSE;
- func_heavy((void *)data, (Ecore_Thread *) &worker);
+ do {
+ worker.reschedule = EINA_FALSE;
+
+ func_heavy((void *)data, (Ecore_Thread *) &worker);
- if (worker.cancel) func_cancel((void *)data, (Ecore_Thread *) &worker);
- else func_end((void *)data, (Ecore_Thread *) &worker);
+ if (worker.cancel) func_cancel((void *)data, (Ecore_Thread *) &worker);
+ else func_end((void *)data, (Ecore_Thread *) &worker);
+ } while (worker.reschedule == EINA_TRUE);
return NULL;
#endif
}
-/**
- * @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.
- */
EAPI Eina_Bool
ecore_thread_feedback(Ecore_Thread *thread, const void *data)
{
#endif
}
-/**
- * @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 Eina_Bool
+ecore_thread_reschedule(Ecore_Thread *thread)
+{
+ Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
+
+ if (!worker) return EINA_FALSE;
+
+#ifdef EFL_HAVE_THREADS
+ if (!PHE(worker->self, PHS())) return EINA_FALSE;
+#endif
+
+ worker->reschedule = EINA_TRUE;
+ return EINA_TRUE;
+}
+
EAPI int
ecore_thread_active_get(void)
{
#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)
{
#endif
}
-/**
- * @brief Get number of pending feedback thread jobs
- * @return Number of pending threads running "feedback" jobs
- * This returns the number of threads currently running jobs through the
- * ecore_thread_feedback_run api call.
- */
EAPI int
ecore_thread_pending_feedback_get(void)
{
#endif
}
-/**
- * @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_thread_feedback_run api calls combined.
- */
EAPI int
ecore_thread_pending_total_get(void)
{
#endif
}
-/**
- * @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)
{
return _ecore_thread_count_max;
}
-/**
- * @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)
{
_ecore_thread_count_max = num;
}
-/**
- * @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)
{
_ecore_thread_count_max = eina_cpu_count();
}
-/**
- * @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_feedback_running))
- */
EAPI int
ecore_thread_available_get(void)
{
#endif
}
-/**
- * @brief Add data to the thread for subsequent use
- * @param thread The thread context to add to
- * @param key The name string to add the data with
- * @param value The data to add
- * @param cb The callback to free the data with
- * @param direct If true, this will not copy the key string (like eina_hash_direct_add)
- * @return EINA_TRUE on success, EINA_FALSE on failure
- * This adds data to the thread context, allowing the thread
- * to retrieve and use it without complicated mutexing. This function can only be called by a
- * *_run thread INSIDE the thread and will return EINA_FALSE in any case but success.
- * All data added to the thread will be freed with its associated callback (if present)
- * upon thread termination. If no callback is specified, it is expected that the user will free the
- * data, but this is most likely not what you want.
- */
EAPI Eina_Bool
ecore_thread_local_data_add(Ecore_Thread *thread, const char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct)
{
#endif
}
-/**
- * @brief Modify data in the thread, or add if not found
- * @param thread The thread context
- * @param key The name string to add the data with
- * @param value The data to add
- * @param cb The callback to free the data with
- * @return The old data associated with @p key on success if modified, NULL if added
- * This adds/modifies data in the thread context, adding only if modify fails.
- * This function can only be called by a *_run thread INSIDE the thread.
- * All data added to the thread pool will be freed with its associated callback (if present)
- * upon thread termination. If no callback is specified, it is expected that the user will free the
- * data, but this is most likely not what you want.
- */
EAPI void *
ecore_thread_local_data_set(Ecore_Thread *thread, const char *key, void *value, Eina_Free_Cb cb)
{
#endif
}
-/**
- * @brief Find data in the thread'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_local_data_add
- * This function can only be called by a *_run thread INSIDE the thread, and will return NULL
- * in any case but success.
- */
EAPI void *
ecore_thread_local_data_find(Ecore_Thread *thread, const char *key)
return NULL;
d = eina_hash_find(worker->hash, key);
- return d->data;
+ if (d)
+ return d->data;
+ return NULL;
#else
return NULL;
#endif
}
-/**
- * @brief Delete data from the thread'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_local_data_add
- * This function can only be called by a *_run thread INSIDE the thread, and will return EINA_FALSE
- * in any case but success. Note that this WILL free the data if a callback was specified.
- */
EAPI Eina_Bool
ecore_thread_local_data_del(Ecore_Thread *thread, const char *key)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
- Ecore_Thread_Data *d;
if ((!thread) || (!key))
return EINA_FALSE;
#ifdef EFL_HAVE_THREADS
if (!worker->hash)
return EINA_FALSE;
- if ((d = eina_hash_find(worker->hash, key)))
- _ecore_thread_data_free(d);
return eina_hash_del_by_key(worker->hash, key);
#else
return EINA_TRUE;
#endif
}
-/**
- * @brief Add data to the global data
- * @param key The name string to add the data with
- * @param value The data to add
- * @param cb The optional callback to free the data with once ecore is shut down
- * @param direct If true, this will not copy the key string (like eina_hash_direct_add)
- * @return EINA_TRUE on success, EINA_FALSE on failure
- * This adds data to the global thread data, and will return EINA_FALSE in any case but success.
- * All data added to global can be manually freed, or a callback can be provided with @p cb which will
- * be called upon ecore_thread shutting down. Note that if you have manually freed data that a callback
- * was specified for, you will most likely encounter a segv later on.
- */
EAPI Eina_Bool
ecore_thread_global_data_add(const char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct)
{
#endif
}
-/**
- * @brief Add data to the global data
- * @param key The name string to add the data with
- * @param value The data to add
- * @param cb The optional callback to free the data with once ecore is shut down
- * @return An Ecore_Thread_Data on success, NULL on failure
- * This adds data to the global thread data and returns NULL, or replaces the previous data
- * associated with @p key and returning the previous data if it existed. To see if an error occurred,
- * one must use eina_error_get.
- * All data added to global can be manually freed, or a callback can be provided with @p cb which will
- * be called upon ecore_thread shutting down. Note that if you have manually freed data that a callback
- * was specified for, you will most likely encounter a segv later on.
- */
EAPI void *
ecore_thread_global_data_set(const char *key, void *value, Eina_Free_Cb cb)
{
#endif
}
-/**
- * @brief Find data in the global data
- * @param key The name string the data is associated with
- * @return The value, or NULL on error
- * This finds data in the global data that has been previously added with @ref ecore_thread_global_data_add
- * This function will return NULL in any case but success.
- * All data added to global can be manually freed, or a callback can be provided with @p cb which will
- * be called upon ecore_thread shutting down. Note that if you have manually freed data that a callback
- * was specified for, you will most likely encounter a segv later on.
- * @note Keep in mind that the data returned can be used by multiple threads at a time, so you will most likely want to mutex
- * if you will be doing anything with it.
- */
EAPI void *
ecore_thread_global_data_find(const char *key)
LRWKRL(_ecore_thread_global_hash_lock);
ret = eina_hash_find(_ecore_thread_global_hash, key);
LRWKU(_ecore_thread_global_hash_lock);
- return ret->data;
+ if (ret)
+ return ret->data;
+ return NULL;
#else
return NULL;
#endif
}
-/**
- * @brief Delete data from the global data
- * @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 global data which was previously added with @ref ecore_thread_global_data_add
- * This function will return EINA_FALSE in any case but success.
- * Note that this WILL free the data if an @c Eina_Free_Cb was specified when the data was added.
- */
EAPI Eina_Bool
ecore_thread_global_data_del(const char *key)
{
Eina_Bool ret;
- Ecore_Thread_Data *d;
if (!key)
return EINA_FALSE;
return EINA_FALSE;
LRWKWL(_ecore_thread_global_hash_lock);
- if ((d = eina_hash_find(_ecore_thread_global_hash, key)))
- _ecore_thread_data_free(d);
ret = eina_hash_del_by_key(_ecore_thread_global_hash, key);
LRWKU(_ecore_thread_global_hash_lock);
return ret;
#endif
}
-/**
- * @brief Find data in the global data and optionally wait for the data if not found
- * @param key The name string the data is associated with
- * @param seconds The amount of time in seconds to wait for the data. If 0, the call will be async and not wait for data.
- * If < 0 the call will wait indefinitely for the data.
- * @return The value, or NULL on failure
- * This finds data in the global data that has been previously added with @ref ecore_thread_global_data_add
- * This function will return NULL in any case but success.
- * Use @p seconds to specify the amount of time to wait. Use > 0 for an actual wait time, 0 to not wait, and < 0 to wait indefinitely.
- * @note Keep in mind that the data returned can be used by multiple threads at a time, so you will most likely want to mutex
- * if you will be doing anything with it.
- */
EAPI void *
ecore_thread_global_data_wait(const char *key, double seconds)
{
- double time = 0;
+ double tm = 0;
Ecore_Thread_Data *ret = NULL;
+
if (!key)
return NULL;
#ifdef EFL_HAVE_THREADS
if (!_ecore_thread_global_hash)
return NULL;
if (seconds > 0)
- time = ecore_time_get() + seconds;
+ tm = ecore_time_get() + seconds;
while (1)
{
#ifndef _WIN32
struct timespec t = { 0, 0 };
- t.tv_sec = (long int)time;
- t.tv_nsec = (long int)((time - (double)t.tv_sec) * 1000000000);
+ t.tv_sec = (long int)tm;
+ t.tv_nsec = (long int)((tm - (double)t.tv_sec) * 1000000000);
#else
struct timeval t = { 0, 0 };
- t.tv_sec = (long int)time;
- t.tv_usec = (long int)((time - (double)t.tv_sec) * 1000000);
+ t.tv_sec = (long int)tm;
+ t.tv_usec = (long int)((tm - (double)t.tv_sec) * 1000000);
#endif
LRWKRL(_ecore_thread_global_hash_lock);
ret = eina_hash_find(_ecore_thread_global_hash, key);
LRWKU(_ecore_thread_global_hash_lock);
- if ((ret) || (!seconds) || ((seconds > 0) && (time <= ecore_time_get())))
+ if ((ret) || (!seconds) || ((seconds > 0) && (tm <= ecore_time_get())))
break;
LKL(_ecore_thread_global_hash_mutex);
CDW(_ecore_thread_global_hash_cond, _ecore_thread_global_hash_mutex, &t);
return NULL;
#endif
}
-
-/**
- * @}
- */
-
-/**
- * @}
- */