From e4f6a3c1f1032f83b25210dea21bbacf4552f8f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 2 May 2017 12:57:12 +0200 Subject: Move nif_helpers into their own project --- c_src/nif_helpers.c | 195 ---------------------------------------------------- 1 file changed, 195 deletions(-) delete mode 100644 c_src/nif_helpers.c (limited to 'c_src/nif_helpers.c') diff --git a/c_src/nif_helpers.c b/c_src/nif_helpers.c deleted file mode 100644 index f29d76d..0000000 --- a/c_src/nif_helpers.c +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2014-2015, Loïc Hoguin -// -// Permission to use, copy, modify, and/or distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -#include "nif_helpers.h" -#include -#include - -extern ERL_NIF_TERM atom_ok; -extern ERL_NIF_TERM atom__nif_thread_ret_; - -typedef struct nif_thread_message { - TAILQ_ENTRY(nif_thread_message) next_entry; - - ErlNifPid* from_pid; - void* function; - nif_thread_arg* args; -} nif_thread_message; - -typedef TAILQ_HEAD(nif_thread_mailbox, nif_thread_message) nif_thread_mailbox; - -typedef struct { - ErlNifTid tid; - ErlNifMutex* lock; - ErlNifCond* cond; - nif_thread_mailbox* mailbox; -} nif_thread_state; - -// Message. - -static nif_thread_message* nif_thread_message_alloc(void* f, nif_thread_arg* args, ErlNifPid* pid) -{ - nif_thread_message* msg = (nif_thread_message*)enif_alloc(sizeof(nif_thread_message)); - - msg->from_pid = pid; - msg->function = f; - msg->args = args; - - return msg; -} - -static void nif_thread_message_free(nif_thread_message* msg) -{ - enif_free(msg->from_pid); - enif_free(msg->args); - enif_free(msg); -} - -// Calls and casts. - -static ERL_NIF_TERM nif_thread_send(nif_thread_state* st, nif_thread_message* msg) -{ - enif_mutex_lock(st->lock); - - TAILQ_INSERT_TAIL(st->mailbox, msg, next_entry); - - enif_cond_signal(st->cond); - enif_mutex_unlock(st->lock); - - return atom_ok; -} - -ERL_NIF_TERM nif_thread_cast(ErlNifEnv* env, void (*f)(nif_thread_arg*), int a, ...) -{ - va_list ap; - int i; - - nif_thread_arg* args = (nif_thread_arg*)enif_alloc(a * sizeof(nif_thread_arg)); - - va_start(ap, a); - for (i = 0; i < a; i++) - args[i] = va_arg(ap, void*); - va_end(ap); - - nif_thread_message* msg = nif_thread_message_alloc(f, args, NULL); - - return nif_thread_send((nif_thread_state*)enif_priv_data(env), msg); -} - -ERL_NIF_TERM nif_thread_call(ErlNifEnv* env, ERL_NIF_TERM (*f)(ErlNifEnv*, nif_thread_arg*), int a, ...) -{ - va_list ap; - int i; - - nif_thread_arg* args = (nif_thread_arg*)enif_alloc(a * sizeof(nif_thread_arg)); - - va_start(ap, a); - for (i = 0; i < a; i++) - args[i] = va_arg(ap, void*); - va_end(ap); - - ErlNifPid* pid = (ErlNifPid*)enif_alloc(sizeof(ErlNifPid)); - nif_thread_message* msg = nif_thread_message_alloc((void*)f, args, enif_self(env, pid)); - - return nif_thread_send((nif_thread_state*)enif_priv_data(env), msg); -} - -// Main thread loop. - -static int nif_thread_receive(nif_thread_state* st, nif_thread_message** msg) -{ - enif_mutex_lock(st->lock); - - while (TAILQ_EMPTY(st->mailbox)) - enif_cond_wait(st->cond, st->lock); - - *msg = TAILQ_FIRST(st->mailbox); - TAILQ_REMOVE(st->mailbox, TAILQ_FIRST(st->mailbox), next_entry); - - enif_mutex_unlock(st->lock); - - if ((*msg)->function == NULL) - return 0; - - return 1; -} - -static void nif_thread_handle(ErlNifEnv* env, nif_thread_state* st, nif_thread_message* msg) -{ - if (msg->from_pid == NULL) { - void (*cast)(nif_thread_arg*) = msg->function; - cast(msg->args); - } else { - ERL_NIF_TERM (*call)(ErlNifEnv*, nif_thread_arg*) = msg->function; - ERL_NIF_TERM ret = call(env, msg->args); - - enif_send(NULL, msg->from_pid, env, - enif_make_tuple2(env, atom__nif_thread_ret_, ret)); - - enif_clear_env(env); - } - - nif_thread_message_free(msg); -} - -static void* nif_main_thread(void* obj) -{ - ErlNifEnv* env = enif_alloc_env(); - nif_thread_state* st = (nif_thread_state*)obj; - nif_thread_message* msg; - - while (nif_thread_receive(st, &msg)) - nif_thread_handle(env, st, msg); - - enif_free_env(env); - - return NULL; -} - -// Main thread creation/destruction. - -void* nif_create_main_thread(char* name) -{ - nif_thread_state* st = (nif_thread_state*)enif_alloc(sizeof(nif_thread_state)); - - st->lock = enif_mutex_create("nif_thread_mailbox_lock"); - st->cond = enif_cond_create("nif_thread_mailbox_cond"); - st->mailbox = (nif_thread_mailbox*)enif_alloc(sizeof(nif_thread_mailbox)); - TAILQ_INIT(st->mailbox); - -#if defined(__APPLE__) && defined(__MACH__) - // On OSX we identify ourselves as the main thread to ensure that - // we are compatible with libraries that require it. For example - // this is necessary with SDL2 in order to receive input events. - erl_drv_steal_main_thread(name, &(st->tid), nif_main_thread, st, NULL); -#else - enif_thread_create(name, &(st->tid), nif_main_thread, st, NULL); -#endif - - return (void*)st; -} - -void nif_destroy_main_thread(void* void_st) -{ - nif_thread_state* st = (nif_thread_state*)void_st; - nif_thread_message* msg = nif_thread_message_alloc(NULL, NULL, NULL); - - nif_thread_send(st, msg); - enif_thread_join(st->tid, NULL); - - enif_cond_destroy(st->cond); - enif_mutex_destroy(st->lock); - enif_free(st->mailbox); - enif_free(st); -} -- cgit v1.2.3