diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /erts/emulator/sys/win32/erl_win32_sys_ddll.c | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'erts/emulator/sys/win32/erl_win32_sys_ddll.c')
-rw-r--r-- | erts/emulator/sys/win32/erl_win32_sys_ddll.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c new file mode 100644 index 0000000000..a19f49af10 --- /dev/null +++ b/erts/emulator/sys/win32/erl_win32_sys_ddll.c @@ -0,0 +1,206 @@ +/* + * %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 <windows.h> + +#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. + */ +} + |