/* * %CopyrightBegin% * * Copyright Ericsson AB 2006-2009. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * %CopyrightEnd% */ /* * Interface functions to the dynamic linker using dl* functions. * (As far as I know it works on SunOS 4, 5, Linux and FreeBSD. /Seb) */ #include #define GET_ERTS_ALC_TEST #include "sys.h" #include "global.h" #include "erl_alloc.h" #include "erl_driver.h" #include "erl_win_dyn_driver.h" #include "erl_nif.h" #define EXT_LEN 4 #define FILE_EXT ".dll" static DWORD tls_index = 0; static TWinDynDriverCallbacks wddc; static TWinDynNifCallbacks nif_callbacks; void erl_sys_ddll_init(void) { tls_index = TlsAlloc(); ERL_INIT_CALLBACK_STRUCTURE(wddc); #define ERL_NIF_API_FUNC_DECL(RET,NAME,ARGS) nif_callbacks.NAME = NAME #include "erl_nif_api_funcs.h" #undef ERL_NIF_API_FUNC_DECL return; } /* * Open a shared object */ int erts_sys_ddll_open2(char *full_name, void **handle, ErtsSysDdllError* err) { int len; char dlname[MAXPATHLEN + 1]; if ((len = sys_strlen(full_name)) >= MAXPATHLEN - EXT_LEN) { if (err != NULL) { err->str = "Library name too long"; } return ERL_DE_LOAD_ERROR_NAME_TO_LONG; } sys_strcpy(dlname, full_name); sys_strcpy(dlname+len, FILE_EXT); return erts_sys_ddll_open_noext(dlname, handle, err); } int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err) { HINSTANCE hinstance; if ((hinstance = LoadLibrary(dlname)) == NULL) { int code = ERL_DE_DYNAMIC_ERROR_OFFSET - GetLastError(); if (err != NULL) { err->str = erts_sys_ddll_error(code); } return code; } else { *handle = (void *) hinstance; return ERL_DE_NO_ERROR; } } /* * Find a symbol in the shared object */ int erts_sys_ddll_sym2(void *handle, char *func_name, void **function, ErtsSysDdllError* err) { FARPROC proc; if ((proc = GetProcAddress( (HINSTANCE) handle, func_name)) == NULL) { int code = ERL_DE_DYNAMIC_ERROR_OFFSET - GetLastError(); if (err != NULL) { err->str = erts_sys_ddll_error(code); } return code; } *function = (void *) proc; return ERL_DE_NO_ERROR; } /* XXX:PaN These two will be changed with new driver interface! */ /* * Load the driver init function, might appear under different names depending on object arch... */ int erts_sys_ddll_load_driver_init(void *handle, void **function) { void *fn; int res; if ((res = erts_sys_ddll_sym(handle, "driver_init", &fn)) != ERL_DE_NO_ERROR) { return res; } *function = fn; return res; } int erts_sys_ddll_load_nif_init(void *handle, void **function, ErtsSysDdllError* err) { void *fn; int res; if ((res = erts_sys_ddll_sym2(handle, "nif_init", &fn, err)) != ERL_DE_NO_ERROR) { return res; } *function = fn; return res; } /* * Call the driver_init function, whatever it's really called, simple on unix... */ void *erts_sys_ddll_call_init(void *function) { void *(*initfn)(TWinDynDriverCallbacks *) = function; return (*initfn)(&wddc); } void *erts_sys_ddll_call_nif_init(void *function) { void *(*initfn)(TWinDynNifCallbacks *) = function; return (*initfn)(&nif_callbacks); } /* * Close a chared object */ int erts_sys_ddll_close2(void *handle, ErtsSysDdllError* err) { if (!FreeLibrary((HINSTANCE) handle)) { int code = ERL_DE_DYNAMIC_ERROR_OFFSET - GetLastError(); if (err != NULL) { err->str = erts_sys_ddll_error(code); } return code; } return ERL_DE_NO_ERROR; } /* * Return string that describes the (current) error */ #define MAX_ERROR 255 char *erts_sys_ddll_error(int code) { int actual_code; char *local_ptr; if (code > ERL_DE_DYNAMIC_ERROR_OFFSET) { return "Unspecified error"; } actual_code = -1*(code - ERL_DE_DYNAMIC_ERROR_OFFSET); local_ptr = TlsGetValue(tls_index); if (local_ptr == NULL) { local_ptr = erts_alloc(ERTS_ALC_T_DDLL_ERRCODES, MAX_ERROR); TlsSetValue(tls_index,local_ptr); } if (!FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) actual_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), local_ptr, MAX_ERROR, NULL )) { return "Unspecified error"; } else { char *ptr = local_ptr + strlen(local_ptr) - 1; while (ptr >= local_ptr && (*ptr == '\r' || *ptr == '\n')) { *ptr-- = '\0'; } } return local_ptr; } void erts_sys_ddll_free_error(ErtsSysDdllError* err) { /* err->str may be either a static string or reused as thread local data, * so wo don't bother free it. */ }