efl/src/lib/ecore/ecore_thread.c

1503 lines
38 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <sys/time.h>
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
#include "Ecore.h"
#include "ecore_private.h"
# define LK(x) Eina_Lock x
# define LKI(x) eina_lock_new(&(x))
# define LKD(x) eina_lock_free(&(x))
# define LKL(x) eina_lock_take(&(x))
# define LKU(x) eina_lock_release(&(x))
# define SLK(x) Eina_Spinlock x
# define SLKI(x) eina_spinlock_new(&(x))
# define SLKD(x) eina_spinlock_free(&(x))
# define SLKL(x) eina_spinlock_take(&(x))
# define SLKU(x) eina_spinlock_release(&(x))
# define CD(x) Eina_Condition x
# define CDI(x, m) eina_condition_new(&(x), &(m))
# define CDD(x) eina_condition_free(&(x))
# define CDB(x) eina_condition_broadcast(&(x))
# define CDW(x, t) eina_condition_timedwait(&(x), t)
# define LRWK(x) Eina_RWLock x
# define LRWKI(x) eina_rwlock_new(&(x));
# define LRWKD(x) eina_rwlock_free(&(x));
# define LRWKWL(x) eina_rwlock_take_write(&(x));
# define LRWKRL(x) eina_rwlock_take_read(&(x));
# define LRWKU(x) eina_rwlock_release(&(x));
# define PH(x) Eina_Thread x
# define PHE(x, y) eina_thread_equal(x, y)
# define PHS() eina_thread_self()
# define PHC(x, f, d) eina_thread_create(&(x), EINA_THREAD_BACKGROUND, -1, (void *)f, d)
# define PHC2(x, f, d)eina_thread_create(&(x), EINA_THREAD_URGENT, -1, (void *)f, d)
# define PHJ(x) eina_thread_join(x)
typedef struct _Ecore_Pthread_Worker Ecore_Pthread_Worker;
typedef struct _Ecore_Pthread Ecore_Pthread;
typedef struct _Ecore_Thread_Data Ecore_Thread_Data;
typedef struct _Ecore_Thread_Waiter Ecore_Thread_Waiter;
struct _Ecore_Thread_Waiter
{
Ecore_Thread_Cb func_cancel;
Ecore_Thread_Cb func_end;
Eina_Bool waiting;
};
struct _Ecore_Thread_Data
{
void *data;
Eina_Free_Cb cb;
};
struct _Ecore_Pthread_Worker
{
union
{
struct
{
Ecore_Thread_Cb func_blocking;
} short_run;
struct
{
Ecore_Thread_Cb func_heavy;
Ecore_Thread_Notify_Cb func_notify;
Ecore_Pthread_Worker *direct_worker;
int send;
int received;
} feedback_run;
struct
{
Ecore_Thread_Cb func_main;
Ecore_Thread_Notify_Cb func_notify;
Ecore_Pipe *send;
Ecore_Pthread_Worker *direct_worker;
struct
{
int send;
int received;
} from, to;
} message_run;
} u;
Ecore_Thread_Waiter *waiter;
Ecore_Thread_Cb func_cancel;
Ecore_Thread_Cb func_end;
PH(self);
Eina_Hash *hash;
CD(cond);
LK(mutex);
const void *data;
int cancel;
SLK(cancel_mutex);
Eina_Bool message_run : 1;
Eina_Bool feedback_run : 1;
Eina_Bool kill : 1;
Eina_Bool reschedule : 1;
Eina_Bool no_queue : 1;
};
typedef struct _Ecore_Pthread_Notify Ecore_Pthread_Notify;
struct _Ecore_Pthread_Notify
{
Ecore_Pthread_Worker *work;
const void *user_data;
};
typedef void *(*Ecore_Thread_Sync_Cb)(void *data, Ecore_Thread *thread);
typedef struct _Ecore_Pthread_Message Ecore_Pthread_Message;
struct _Ecore_Pthread_Message
{
union
{
Ecore_Thread_Cb async;
Ecore_Thread_Sync_Cb sync;
} u;
const void *data;
int code;
Eina_Bool callback : 1;
Eina_Bool sync : 1;
};
static int _ecore_thread_count_max = 0;
static void _ecore_thread_handler(void *data);
static int _ecore_thread_count = 0;
static int _ecore_thread_count_no_queue = 0;
static Eina_List *_ecore_running_job = NULL;
static Eina_List *_ecore_pending_job_threads = NULL;
static Eina_List *_ecore_pending_job_threads_feedback = NULL;
static SLK(_ecore_pending_job_threads_mutex);
static SLK(_ecore_running_job_mutex);
static Eina_Hash *_ecore_thread_global_hash = NULL;
static LRWK(_ecore_thread_global_hash_lock);
static LK(_ecore_thread_global_hash_mutex);
static CD(_ecore_thread_global_hash_cond);
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(void *, Eina_Thread);
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)
{
SLKD(worker->cancel_mutex);
CDD(worker->cond);
LKD(worker->mutex);
if (_ecore_thread_worker_count > ((_ecore_thread_count_max + 1) * 16))
{
_ecore_thread_worker_count--;
free(worker);
return;
}
eina_trash_push(&_ecore_thread_worker_trash, worker);
}
static void
_ecore_thread_data_free(void *data)
{
Ecore_Thread_Data *d = data;
if (d->cb) d->cb(d->data);
free(d);
}
void
_ecore_thread_join(void *data)
{
PH(thread) = (uintptr_t)data;
DBG("joining thread=%" PRIu64, (uint64_t)thread);
PHJ(thread);
}
static void
_ecore_thread_kill(Ecore_Pthread_Worker *work)
{
if (work->cancel)
{
if (work->func_cancel)
work->func_cancel((void *)work->data, (Ecore_Thread *)work);
}
else
{
if (work->func_end)
work->func_end((void *)work->data, (Ecore_Thread *)work);
}
if (work->feedback_run)
{
if (work->u.feedback_run.direct_worker)
_ecore_thread_worker_free(work->u.feedback_run.direct_worker);
}
2010-07-23 10:52:50 -07:00
if (work->hash)
eina_hash_free(work->hash);
_ecore_thread_worker_free(work);
}
static void
_ecore_thread_handler(void *data)
{
Ecore_Pthread_Worker *work = data;
if (work->feedback_run)
{
if (work->u.feedback_run.send != work->u.feedback_run.received)
{
work->kill = EINA_TRUE;
return;
}
}
_ecore_thread_kill(work);
}
#if 0
static void
_ecore_nothing_handler(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int nbyte EINA_UNUSED)
{
}
#endif
static void
_ecore_notify_handler(void *data)
{
Ecore_Pthread_Notify *notify = data;
Ecore_Pthread_Worker *work = notify->work;
void *user_data = (void *)notify->user_data;
work->u.feedback_run.received++;
if (work->u.feedback_run.func_notify)
work->u.feedback_run.func_notify((void *)work->data, (Ecore_Thread *)work, user_data);
/* Force reading all notify event before killing the thread */
if (work->kill && work->u.feedback_run.send == work->u.feedback_run.received)
{
_ecore_thread_kill(work);
}
free(notify);
}
static void
_ecore_message_notify_handler(void *data)
{
Ecore_Pthread_Notify *notify = data;
Ecore_Pthread_Worker *work = notify->work;
Ecore_Pthread_Message *user_data = (void *)notify->user_data;
Eina_Bool delete = EINA_TRUE;
work->u.message_run.from.received++;
if (!user_data->callback)
{
if (work->u.message_run.func_notify)
work->u.message_run.func_notify((void *)work->data, (Ecore_Thread *)work, (void *)user_data->data);
}
else
{
if (user_data->sync)
{
user_data->data = user_data->u.sync((void *)user_data->data, (Ecore_Thread *)work);
user_data->callback = EINA_FALSE;
user_data->code = INT_MAX;
ecore_pipe_write(work->u.message_run.send, &user_data, sizeof (Ecore_Pthread_Message *));
delete = EINA_FALSE;
}
else
{
user_data->u.async((void *)user_data->data, (Ecore_Thread *)work);
}
}
if (delete)
{
free(user_data);
}
/* Force reading all notify event before killing the thread */
if (work->kill && work->u.message_run.from.send == work->u.message_run.from.received)
{
_ecore_thread_kill(work);
}
free(notify);
}
static void
_ecore_short_job_cleanup(void *data)
{
Ecore_Pthread_Worker *work = data;
DBG("cleanup work=%p, thread=%" PRIu64, work, (uint64_t)work->self);
SLKL(_ecore_running_job_mutex);
_ecore_running_job = eina_list_remove(_ecore_running_job, work);
SLKU(_ecore_running_job_mutex);
if (work->reschedule)
{
work->reschedule = EINA_FALSE;
SLKL(_ecore_pending_job_threads_mutex);
_ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, work);
SLKU(_ecore_pending_job_threads_mutex);
}
else
{
ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work);
}
}
static void
_ecore_short_job(PH(thread))
{
Ecore_Pthread_Worker *work;
int cancel;
SLKL(_ecore_pending_job_threads_mutex);
if (!_ecore_pending_job_threads)
{
SLKU(_ecore_pending_job_threads_mutex);
return;
}
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);
SLKU(_ecore_pending_job_threads_mutex);
SLKL(_ecore_running_job_mutex);
_ecore_running_job = eina_list_append(_ecore_running_job, work);
SLKU(_ecore_running_job_mutex);
SLKL(work->cancel_mutex);
cancel = work->cancel;
SLKU(work->cancel_mutex);
work->self = thread;
EINA_THREAD_CLEANUP_PUSH(_ecore_short_job_cleanup, work);
if (!cancel)
work->u.short_run.func_blocking((void *)work->data, (Ecore_Thread *)work);
eina_thread_cancellable_set(EINA_FALSE, NULL);
EINA_THREAD_CLEANUP_POP(EINA_TRUE);
}
static void
_ecore_feedback_job_cleanup(void *data)
{
Ecore_Pthread_Worker *work = data;
DBG("cleanup work=%p, thread=%" PRIu64, work, (uint64_t)work->self);
SLKL(_ecore_running_job_mutex);
_ecore_running_job = eina_list_remove(_ecore_running_job, work);
SLKU(_ecore_running_job_mutex);
if (work->reschedule)
{
work->reschedule = EINA_FALSE;
SLKL(_ecore_pending_job_threads_mutex);
_ecore_pending_job_threads_feedback = eina_list_append(_ecore_pending_job_threads_feedback, work);
SLKU(_ecore_pending_job_threads_mutex);
}
else
{
ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work);
}
}
static void
_ecore_feedback_job(PH(thread))
{
Ecore_Pthread_Worker *work;
int cancel;
SLKL(_ecore_pending_job_threads_mutex);
if (!_ecore_pending_job_threads_feedback)
{
SLKU(_ecore_pending_job_threads_mutex);
return;
}
work = eina_list_data_get(_ecore_pending_job_threads_feedback);
_ecore_pending_job_threads_feedback = eina_list_remove_list(_ecore_pending_job_threads_feedback,
_ecore_pending_job_threads_feedback);
SLKU(_ecore_pending_job_threads_mutex);
SLKL(_ecore_running_job_mutex);
_ecore_running_job = eina_list_append(_ecore_running_job, work);
SLKU(_ecore_running_job_mutex);
SLKL(work->cancel_mutex);
cancel = work->cancel;
SLKU(work->cancel_mutex);
work->self = thread;
EINA_THREAD_CLEANUP_PUSH(_ecore_feedback_job_cleanup, work);
if (!cancel)
work->u.feedback_run.func_heavy((void *)work->data, (Ecore_Thread *)work);
eina_thread_cancellable_set(EINA_FALSE, NULL);
EINA_THREAD_CLEANUP_POP(EINA_TRUE);
}
static void
_ecore_direct_worker_cleanup(void *data)
{
Ecore_Pthread_Worker *work = data;
DBG("cleanup work=%p, thread=%" PRIu64 " (should join)", work, (uint64_t)work->self);
SLKL(_ecore_pending_job_threads_mutex);
_ecore_thread_count_no_queue--;
ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work);
ecore_main_loop_thread_safe_call_async((Ecore_Cb)_ecore_thread_join,
(void *)(intptr_t)PHS());
SLKU(_ecore_pending_job_threads_mutex);
}
static void *
_ecore_direct_worker(void *data, Eina_Thread t EINA_UNUSED)
{
Ecore_Pthread_Worker *work = data;
eina_thread_cancellable_set(EINA_FALSE, NULL);
eina_thread_name_set(eina_thread_self(), "Ethread-feedback");
work->self = PHS();
EINA_THREAD_CLEANUP_PUSH(_ecore_direct_worker_cleanup, work);
if (work->message_run)
work->u.message_run.func_main((void *)work->data, (Ecore_Thread *)work);
else
work->u.feedback_run.func_heavy((void *)work->data, (Ecore_Thread *)work);
eina_thread_cancellable_set(EINA_FALSE, NULL);
EINA_THREAD_CLEANUP_POP(EINA_TRUE);
return NULL;
}
static void
_ecore_thread_worker_cleanup(void *data EINA_UNUSED)
{
DBG("cleanup thread=%" PRIuPTR " (should join)", PHS());
SLKL(_ecore_pending_job_threads_mutex);
_ecore_thread_count--;
ecore_main_loop_thread_safe_call_async((Ecore_Cb)_ecore_thread_join,
(void *)(intptr_t)PHS());
SLKU(_ecore_pending_job_threads_mutex);
}
static void *
_ecore_thread_worker(void *data EINA_UNUSED, Eina_Thread t EINA_UNUSED)
{
eina_thread_cancellable_set(EINA_FALSE, NULL);
EINA_THREAD_CLEANUP_PUSH(_ecore_thread_worker_cleanup, NULL);
restart:
/* these 2 are cancellation points as user cb may enable */
_ecore_short_job(PHS());
_ecore_feedback_job(PHS());
/* from here on, cancellations are guaranteed to be disabled */
/* FIXME: Check if there is feedback running task todo, and switch to feedback run handler. */
eina_thread_name_set(eina_thread_self(), "Ethread-worker");
SLKL(_ecore_pending_job_threads_mutex);
if (_ecore_pending_job_threads || _ecore_pending_job_threads_feedback)
{
SLKU(_ecore_pending_job_threads_mutex);
goto restart;
}
SLKU(_ecore_pending_job_threads_mutex);
/* Sleep a little to prevent premature death */
#ifdef _WIN32
Sleep(1); /* around 50ms */
#else
usleep(50);
#endif
SLKL(_ecore_pending_job_threads_mutex);
if (_ecore_pending_job_threads || _ecore_pending_job_threads_feedback)
{
SLKU(_ecore_pending_job_threads_mutex);
goto restart;
}
SLKU(_ecore_pending_job_threads_mutex);
EINA_THREAD_CLEANUP_POP(EINA_TRUE);
return NULL;
}
static Ecore_Pthread_Worker *
_ecore_thread_worker_new(void)
{
Ecore_Pthread_Worker *result;
result = eina_trash_pop(&_ecore_thread_worker_trash);
if (!result)
{
result = calloc(1, sizeof(Ecore_Pthread_Worker));
_ecore_thread_worker_count++;
}
else
{
memset(result, 0, sizeof(Ecore_Pthread_Worker));
}
SLKI(result->cancel_mutex);
LKI(result->mutex);
CDI(result->cond, result->mutex);
return result;
}
void
_ecore_thread_init(void)
{
_ecore_thread_count_max = eina_cpu_count() * 4;
if (_ecore_thread_count_max <= 0)
_ecore_thread_count_max = 1;
SLKI(_ecore_pending_job_threads_mutex);
LRWKI(_ecore_thread_global_hash_lock);
LKI(_ecore_thread_global_hash_mutex);
SLKI(_ecore_running_job_mutex);
CDI(_ecore_thread_global_hash_cond, _ecore_thread_global_hash_mutex);
}
void
_ecore_thread_shutdown(void)
{
/* FIXME: If function are still running in the background, should we kill them ? */
Ecore_Pthread_Worker *work;
Eina_List *l;
Eina_Bool test;
int iteration = 0;
SLKL(_ecore_pending_job_threads_mutex);
EINA_LIST_FREE(_ecore_pending_job_threads, work)
{
if (work->func_cancel)
work->func_cancel((void *)work->data, (Ecore_Thread *)work);
free(work);
}
EINA_LIST_FREE(_ecore_pending_job_threads_feedback, work)
{
if (work->func_cancel)
work->func_cancel((void *)work->data, (Ecore_Thread *)work);
free(work);
}
SLKU(_ecore_pending_job_threads_mutex);
SLKL(_ecore_running_job_mutex);
EINA_LIST_FOREACH(_ecore_running_job, l, work)
ecore_thread_cancel((Ecore_Thread *)work);
SLKU(_ecore_running_job_mutex);
do
{
SLKL(_ecore_pending_job_threads_mutex);
if (_ecore_thread_count + _ecore_thread_count_no_queue > 0)
{
test = EINA_TRUE;
}
else
{
test = EINA_FALSE;
}
SLKU(_ecore_pending_job_threads_mutex);
iteration++;
if (test)
{
_ecore_main_call_flush();
usleep(1000);
}
} while (test == EINA_TRUE && iteration < 50);
if (iteration == 20 && _ecore_thread_count > 0)
{
ERR("%i of the child thread are still running after 1s. This can lead to a segv. Sorry.", _ecore_thread_count);
}
if (_ecore_thread_global_hash)
eina_hash_free(_ecore_thread_global_hash);
have_main_loop_thread = 0;
while ((work = eina_trash_pop(&_ecore_thread_worker_trash)))
{
free(work);
}
SLKD(_ecore_pending_job_threads_mutex);
LRWKD(_ecore_thread_global_hash_lock);
LKD(_ecore_thread_global_hash_mutex);
SLKD(_ecore_running_job_mutex);
CDD(_ecore_thread_global_hash_cond);
}
2010-10-17 00:03:28 -07:00
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Ecore_Thread *
ecore_thread_run(Ecore_Thread_Cb func_blocking,
Ecore_Thread_Cb func_end,
Ecore_Thread_Cb func_cancel,
const void *data)
{
Ecore_Pthread_Worker *work;
Eina_Bool tried = EINA_FALSE;
PH(thread);
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
if (!func_blocking) return NULL;
work = _ecore_thread_worker_new();
if (!work)
{
if (func_cancel)
func_cancel((void *)data, NULL);
return NULL;
}
work->u.short_run.func_blocking = func_blocking;
work->func_end = func_end;
work->func_cancel = func_cancel;
work->cancel = EINA_FALSE;
work->feedback_run = EINA_FALSE;
work->message_run = EINA_FALSE;
work->kill = EINA_FALSE;
work->reschedule = EINA_FALSE;
work->no_queue = EINA_FALSE;
work->data = data;
work->self = 0;
work->hash = NULL;
SLKL(_ecore_pending_job_threads_mutex);
_ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, work);
if (_ecore_thread_count == _ecore_thread_count_max)
{
SLKU(_ecore_pending_job_threads_mutex);
return (Ecore_Thread *)work;
}
SLKU(_ecore_pending_job_threads_mutex);
/* One more thread could be created. */
eina_threads_init();
SLKL(_ecore_pending_job_threads_mutex);
retry:
if (PHC(thread, _ecore_thread_worker, NULL))
{
_ecore_thread_count++;
SLKU(_ecore_pending_job_threads_mutex);
return (Ecore_Thread *)work;
}
if (!tried)
{
_ecore_main_call_flush();
tried = EINA_TRUE;
goto retry;
}
if (_ecore_thread_count == 0)
{
_ecore_pending_job_threads = eina_list_remove(_ecore_pending_job_threads, work);
if (work->func_cancel)
work->func_cancel((void *)work->data, (Ecore_Thread *)work);
_ecore_thread_worker_free(work);
work = NULL;
}
SLKU(_ecore_pending_job_threads_mutex);
eina_threads_shutdown();
return (Ecore_Thread *)work;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_cancel(Ecore_Thread *thread)
{
Ecore_Pthread_Worker *volatile work = (Ecore_Pthread_Worker *)thread;
Eina_List *l;
int cancel;
if (!work)
return EINA_TRUE;
SLKL(work->cancel_mutex);
cancel = work->cancel;
SLKU(work->cancel_mutex);
if (cancel)
return EINA_FALSE;
if (work->feedback_run)
{
if (work->kill)
return EINA_TRUE;
if (work->u.feedback_run.send != work->u.feedback_run.received)
goto on_exit;
}
SLKL(_ecore_pending_job_threads_mutex);
if ((have_main_loop_thread) &&
(PHE(get_main_loop_thread(), PHS())))
{
if (!work->feedback_run)
EINA_LIST_FOREACH(_ecore_pending_job_threads, l, work)
{
if ((void *)work == (void *)thread)
{
_ecore_pending_job_threads = eina_list_remove_list(_ecore_pending_job_threads, l);
SLKU(_ecore_pending_job_threads_mutex);
if (work->func_cancel)
work->func_cancel((void *)work->data, (Ecore_Thread *)work);
free(work);
return EINA_TRUE;
}
}
else
EINA_LIST_FOREACH(_ecore_pending_job_threads_feedback, l, work)
{
if ((void *)work == (void *)thread)
{
_ecore_pending_job_threads_feedback = eina_list_remove_list(_ecore_pending_job_threads_feedback, l);
SLKU(_ecore_pending_job_threads_mutex);
if (work->func_cancel)
work->func_cancel((void *)work->data, (Ecore_Thread *)work);
free(work);
return EINA_TRUE;
}
}
}
SLKU(_ecore_pending_job_threads_mutex);
work = (Ecore_Pthread_Worker *)thread;
/* Delay the destruction */
on_exit:
eina_thread_cancel(work->self); /* noop unless eina_thread_cancellable_set() was used by user */
SLKL(work->cancel_mutex);
work->cancel = EINA_TRUE;
SLKU(work->cancel_mutex);
return EINA_FALSE;
}
static void
_ecore_thread_wait_reset(Ecore_Thread_Waiter *waiter,
Ecore_Pthread_Worker *worker)
{
worker->func_cancel = waiter->func_cancel;
worker->func_end = waiter->func_end;
worker->waiter = NULL;
waiter->func_end = NULL;
waiter->func_cancel = NULL;
waiter->waiting = EINA_FALSE;
}
static void
_ecore_thread_wait_cancel(void *data EINA_UNUSED, Ecore_Thread *thread)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
Ecore_Thread_Waiter *waiter = worker->waiter;
if (waiter->func_cancel) waiter->func_cancel(data, thread);
_ecore_thread_wait_reset(waiter, worker);
}
static void
_ecore_thread_wait_end(void *data EINA_UNUSED, Ecore_Thread *thread)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
Ecore_Thread_Waiter *waiter = worker->waiter;
if (waiter->func_end) waiter->func_end(data, thread);
_ecore_thread_wait_reset(waiter, worker);
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_wait(Ecore_Thread *thread, double wait)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
Ecore_Thread_Waiter waiter;
if (!thread) return EINA_TRUE;
waiter.func_end = worker->func_end;
waiter.func_cancel = worker->func_cancel;
waiter.waiting = EINA_TRUE;
// Now trick the thread to call the wrapper function
worker->waiter = &waiter;
worker->func_cancel = _ecore_thread_wait_cancel;
worker->func_end = _ecore_thread_wait_end;
while (waiter.waiting == EINA_TRUE)
{
double start, end;
start = ecore_time_get();
_ecore_main_call_flush();
ecore_main_loop_thread_safe_call_wait(0.0001);
end = ecore_time_get();
wait -= end - start;
if (wait <= 0) break;
}
if (waiter.waiting == EINA_FALSE)
{
return EINA_TRUE;
}
else
{
_ecore_thread_wait_reset(&waiter, worker);
return EINA_FALSE;
}
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_check(Ecore_Thread *thread)
{
Ecore_Pthread_Worker *volatile worker = (Ecore_Pthread_Worker *)thread;
int cancel;
if (!worker) return EINA_TRUE;
SLKL(worker->cancel_mutex);
cancel = worker->cancel;
/* FIXME: there is an insane bug driving me nuts here. I don't know if
it's a race condition, some cache issue or some alien attack on our software.
But ecore_thread_check will only work correctly with a printf, all the volatile,
lock and even usleep don't help here... */
/* fprintf(stderr, "wc: %i\n", cancel); */
SLKU(worker->cancel_mutex);
return cancel;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Ecore_Thread *
ecore_thread_feedback_run(Ecore_Thread_Cb func_heavy,
Ecore_Thread_Notify_Cb func_notify,
Ecore_Thread_Cb func_end,
Ecore_Thread_Cb func_cancel,
const void *data,
Eina_Bool try_no_queue)
{
Ecore_Pthread_Worker *worker;
Eina_Bool tried = EINA_FALSE;
PH(thread);
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
if (!func_heavy) return NULL;
worker = _ecore_thread_worker_new();
if (!worker) goto on_error;
worker->u.feedback_run.func_heavy = func_heavy;
worker->u.feedback_run.func_notify = func_notify;
worker->hash = NULL;
worker->func_cancel = func_cancel;
worker->func_end = func_end;
worker->data = data;
worker->cancel = EINA_FALSE;
worker->message_run = EINA_FALSE;
worker->feedback_run = EINA_TRUE;
worker->kill = EINA_FALSE;
worker->reschedule = EINA_FALSE;
worker->self = 0;
worker->u.feedback_run.send = 0;
worker->u.feedback_run.received = 0;
worker->u.feedback_run.direct_worker = NULL;
if (try_no_queue)
{
PH(t);
worker->u.feedback_run.direct_worker = _ecore_thread_worker_new();
worker->no_queue = EINA_TRUE;
eina_threads_init();
retry_direct:
if (PHC2(t, _ecore_direct_worker, worker))
{
SLKL(_ecore_pending_job_threads_mutex);
_ecore_thread_count_no_queue++;
SLKU(_ecore_pending_job_threads_mutex);
return (Ecore_Thread *)worker;
}
if (!tried)
{
_ecore_main_call_flush();
tried = EINA_TRUE;
goto retry_direct;
}
if (worker->u.feedback_run.direct_worker)
{
_ecore_thread_worker_free(worker->u.feedback_run.direct_worker);
worker->u.feedback_run.direct_worker = NULL;
}
eina_threads_shutdown();
}
worker->no_queue = EINA_FALSE;
SLKL(_ecore_pending_job_threads_mutex);
_ecore_pending_job_threads_feedback = eina_list_append(_ecore_pending_job_threads_feedback, worker);
if (_ecore_thread_count == _ecore_thread_count_max)
{
SLKU(_ecore_pending_job_threads_mutex);
return (Ecore_Thread *)worker;
}
SLKU(_ecore_pending_job_threads_mutex);
/* One more thread could be created. */
eina_threads_init();
SLKL(_ecore_pending_job_threads_mutex);
retry:
if (PHC(thread, _ecore_thread_worker, NULL))
{
_ecore_thread_count++;
SLKU(_ecore_pending_job_threads_mutex);
return (Ecore_Thread *)worker;
}
if (!tried)
{
_ecore_main_call_flush();
tried = EINA_TRUE;
goto retry;
}
SLKU(_ecore_pending_job_threads_mutex);
eina_threads_shutdown();
on_error:
SLKL(_ecore_pending_job_threads_mutex);
if (_ecore_thread_count == 0)
{
_ecore_pending_job_threads_feedback = eina_list_remove(_ecore_pending_job_threads_feedback,
worker);
if (func_cancel) func_cancel((void *)data, NULL);
if (worker)
{
CDD(worker->cond);
LKD(worker->mutex);
free(worker);
worker = NULL;
}
}
SLKU(_ecore_pending_job_threads_mutex);
return (Ecore_Thread *)worker;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_feedback(Ecore_Thread *thread,
const void *data)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
if (!worker) return EINA_FALSE;
if (!PHE(worker->self, PHS())) return EINA_FALSE;
if (worker->feedback_run)
{
Ecore_Pthread_Notify *notify;
notify = malloc(sizeof (Ecore_Pthread_Notify));
if (!notify) return EINA_FALSE;
notify->user_data = data;
notify->work = worker;
worker->u.feedback_run.send++;
ecore_main_loop_thread_safe_call_async(_ecore_notify_handler, notify);
}
else if (worker->message_run)
{
Ecore_Pthread_Message *msg;
Ecore_Pthread_Notify *notify;
msg = malloc(sizeof (Ecore_Pthread_Message));
if (!msg) return EINA_FALSE;
msg->data = data;
msg->callback = EINA_FALSE;
msg->sync = EINA_FALSE;
notify = malloc(sizeof (Ecore_Pthread_Notify));
if (!notify)
{
free(msg);
return EINA_FALSE;
}
notify->work = worker;
notify->user_data = msg;
worker->u.message_run.from.send++;
ecore_main_loop_thread_safe_call_async(_ecore_message_notify_handler, notify);
}
else
return EINA_FALSE;
return EINA_TRUE;
}
#if 0
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Ecore_Thread *
ecore_thread_message_run(Ecore_Thread_Cb func_main,
Ecore_Thread_Notify_Cb func_notify,
Ecore_Thread_Cb func_end,
Ecore_Thread_Cb func_cancel,
const void *data)
{
Ecore_Pthread_Worker *worker;
PH(t);
if (!func_main) return NULL;
worker = _ecore_thread_worker_new();
if (!worker) return NULL;
worker->u.message_run.func_main = func_main;
worker->u.message_run.func_notify = func_notify;
worker->u.message_run.direct_worker = _ecore_thread_worker_new();
worker->u.message_run.send = ecore_pipe_add(_ecore_nothing_handler, worker);
worker->u.message_run.from.send = 0;
worker->u.message_run.from.received = 0;
worker->u.message_run.to.send = 0;
worker->u.message_run.to.received = 0;
ecore_pipe_freeze(worker->u.message_run.send);
worker->func_cancel = func_cancel;
worker->func_end = func_end;
worker->hash = NULL;
worker->data = data;
worker->cancel = EINA_FALSE;
worker->message_run = EINA_TRUE;
worker->feedback_run = EINA_FALSE;
worker->kill = EINA_FALSE;
worker->reschedule = EINA_FALSE;
worker->no_queue = EINA_FALSE;
worker->self = 0;
eina_threads_init();
if (PHC(t, _ecore_direct_worker, worker))
return (Ecore_Thread *)worker;
eina_threads_shutdown();
if (worker->u.message_run.direct_worker) _ecore_thread_worker_free(worker->u.message_run.direct_worker);
if (worker->u.message_run.send) ecore_pipe_del(worker->u.message_run.send);
CDD(worker->cond);
LKD(worker->mutex);
func_cancel((void *)data, NULL);
return NULL;
}
#endif
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_reschedule(Ecore_Thread *thread)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
if (!worker) return EINA_FALSE;
if (!PHE(worker->self, PHS())) return EINA_FALSE;
worker->reschedule = EINA_TRUE;
return EINA_TRUE;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_thread_active_get(void)
{
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
return _ecore_thread_count;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_thread_pending_get(void)
{
int ret;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
SLKL(_ecore_pending_job_threads_mutex);
ret = eina_list_count(_ecore_pending_job_threads);
SLKU(_ecore_pending_job_threads_mutex);
return ret;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_thread_pending_feedback_get(void)
{
int ret;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
SLKL(_ecore_pending_job_threads_mutex);
ret = eina_list_count(_ecore_pending_job_threads_feedback);
SLKU(_ecore_pending_job_threads_mutex);
return ret;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_thread_pending_total_get(void)
{
int ret;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
SLKL(_ecore_pending_job_threads_mutex);
ret = eina_list_count(_ecore_pending_job_threads) + eina_list_count(_ecore_pending_job_threads_feedback);
SLKU(_ecore_pending_job_threads_mutex);
return ret;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_thread_max_get(void)
{
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
return _ecore_thread_count_max;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void
ecore_thread_max_set(int num)
{
EINA_MAIN_LOOP_CHECK_RETURN;
if (num < 1) return;
/* avoid doing something hilarious by blocking dumb users */
if (num > (32 * eina_cpu_count())) num = 32 * eina_cpu_count();
_ecore_thread_count_max = num;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void
ecore_thread_max_reset(void)
{
EINA_MAIN_LOOP_CHECK_RETURN;
_ecore_thread_count_max = eina_cpu_count() * 4;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_thread_available_get(void)
{
int ret;
SLKL(_ecore_pending_job_threads_mutex);
ret = _ecore_thread_count_max - _ecore_thread_count;
SLKU(_ecore_pending_job_threads_mutex);
return ret;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_local_data_add(Ecore_Thread *thread,
const char *key,
void *value,
Eina_Free_Cb cb,
Eina_Bool direct)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
Ecore_Thread_Data *d;
Eina_Bool ret;
if ((!thread) || (!key) || (!value))
return EINA_FALSE;
LKL(worker->mutex);
if (!worker->hash)
worker->hash = eina_hash_string_small_new(_ecore_thread_data_free);
LKU(worker->mutex);
if (!worker->hash)
return EINA_FALSE;
if (!(d = malloc(sizeof(Ecore_Thread_Data))))
return EINA_FALSE;
d->data = value;
d->cb = cb;
LKL(worker->mutex);
if (direct)
ret = eina_hash_direct_add(worker->hash, key, d);
else
ret = eina_hash_add(worker->hash, key, d);
LKU(worker->mutex);
CDB(worker->cond);
return ret;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void *
ecore_thread_local_data_set(Ecore_Thread *thread,
const char *key,
void *value,
Eina_Free_Cb cb)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
Ecore_Thread_Data *d, *r;
void *ret;
if ((!thread) || (!key) || (!value))
return NULL;
LKL(worker->mutex);
if (!worker->hash)
worker->hash = eina_hash_string_small_new(_ecore_thread_data_free);
LKU(worker->mutex);
if (!worker->hash)
return NULL;
if (!(d = malloc(sizeof(Ecore_Thread_Data))))
return NULL;
d->data = value;
d->cb = cb;
LKL(worker->mutex);
r = eina_hash_set(worker->hash, key, d);
LKU(worker->mutex);
CDB(worker->cond);
if (r)
{
ret = r->data;
free(r);
return ret;
}
return NULL;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void *
ecore_thread_local_data_find(Ecore_Thread *thread,
const char *key)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
Ecore_Thread_Data *d;
if ((!thread) || (!key))
return NULL;
if (!worker->hash)
return NULL;
LKL(worker->mutex);
d = eina_hash_find(worker->hash, key);
LKU(worker->mutex);
if (d)
return d->data;
return NULL;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_local_data_del(Ecore_Thread *thread,
const char *key)
{
Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
Eina_Bool r;
if ((!thread) || (!key))
return EINA_FALSE;
if (!worker->hash)
return EINA_FALSE;
LKL(worker->mutex);
r = eina_hash_del_by_key(worker->hash, key);
LKU(worker->mutex);
return r;
}
2010-07-23 06:12:42 -07:00
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_global_data_add(const char *key,
void *value,
Eina_Free_Cb cb,
Eina_Bool direct)
{
Ecore_Thread_Data *d;
Eina_Bool ret;
if ((!key) || (!value))
return EINA_FALSE;
LRWKWL(_ecore_thread_global_hash_lock);
if (!_ecore_thread_global_hash)
_ecore_thread_global_hash = eina_hash_string_small_new(_ecore_thread_data_free);
LRWKU(_ecore_thread_global_hash_lock);
if (!(d = malloc(sizeof(Ecore_Thread_Data))))
return EINA_FALSE;
d->data = value;
d->cb = cb;
if (!_ecore_thread_global_hash)
{
free(d);
return EINA_FALSE;
}
LRWKWL(_ecore_thread_global_hash_lock);
if (direct)
ret = eina_hash_direct_add(_ecore_thread_global_hash, key, d);
else
ret = eina_hash_add(_ecore_thread_global_hash, key, d);
LRWKU(_ecore_thread_global_hash_lock);
CDB(_ecore_thread_global_hash_cond);
return ret;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void *
ecore_thread_global_data_set(const char *key,
void *value,
Eina_Free_Cb cb)
{
Ecore_Thread_Data *d, *r;
void *ret;
if ((!key) || (!value))
return NULL;
LRWKWL(_ecore_thread_global_hash_lock);
if (!_ecore_thread_global_hash)
_ecore_thread_global_hash = eina_hash_string_small_new(_ecore_thread_data_free);
LRWKU(_ecore_thread_global_hash_lock);
if (!_ecore_thread_global_hash)
return NULL;
if (!(d = malloc(sizeof(Ecore_Thread_Data))))
return NULL;
d->data = value;
d->cb = cb;
LRWKWL(_ecore_thread_global_hash_lock);
r = eina_hash_set(_ecore_thread_global_hash, key, d);
LRWKU(_ecore_thread_global_hash_lock);
CDB(_ecore_thread_global_hash_cond);
if (r)
{
ret = r->data;
free(r);
return ret;
}
return NULL;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void *
ecore_thread_global_data_find(const char *key)
{
Ecore_Thread_Data *ret;
if (!key)
return NULL;
if (!_ecore_thread_global_hash) return NULL;
LRWKRL(_ecore_thread_global_hash_lock);
ret = eina_hash_find(_ecore_thread_global_hash, key);
LRWKU(_ecore_thread_global_hash_lock);
if (ret)
return ret->data;
return NULL;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_thread_global_data_del(const char *key)
{
Eina_Bool ret;
if (!key)
return EINA_FALSE;
if (!_ecore_thread_global_hash)
return EINA_FALSE;
LRWKWL(_ecore_thread_global_hash_lock);
ret = eina_hash_del_by_key(_ecore_thread_global_hash, key);
LRWKU(_ecore_thread_global_hash_lock);
return ret;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void *
ecore_thread_global_data_wait(const char *key,
double seconds)
{
double tm = 0;
Ecore_Thread_Data *ret = NULL;
if (!key)
return NULL;
if (seconds > 0)
tm = ecore_time_get() + seconds;
while (1)
{
LRWKRL(_ecore_thread_global_hash_lock);
if (_ecore_thread_global_hash)
ret = eina_hash_find(_ecore_thread_global_hash, key);
LRWKU(_ecore_thread_global_hash_lock);
if ((ret) ||
(!EINA_DBL_EQ(seconds, 0.0)) ||
((seconds > 0) && (tm <= ecore_time_get())))
break;
LKL(_ecore_thread_global_hash_mutex);
CDW(_ecore_thread_global_hash_cond, tm - ecore_time_get());
LKU(_ecore_thread_global_hash_mutex);
}
if (ret) return ret->data;
return NULL;
}