ddll_drv.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 417 行
C
417 行
/* ``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 via the world wide web 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. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ *//* * Dynamic driver loader and linker */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "erl_sys_driver.h"#include "global.h"#include "erl_ddll.h"#define LOAD_DRIVER 'l'#define UNLOAD_DRIVER 'u'#define GET_DRIVERS 'g'/*********************************************************************** * R e p l i e s * * The following replies are sent from this driver. * * Reply Translated to on Erlang side * ----- ---------------------------- * [$o] ok * [$o|List] {ok, List} * [$e|Atom] {error, Atom} * [$E|[Atom, 0, Message]] {error, {Atom, Message}} * [$i|String] "..." (This is an item in a list.) * * List of strings are sent as multiple messages: * * [$i|String] * . * . * . * [$i|String] * [$o] * * This will be represented as {ok, [String1, ..., StringN]} in Erlang. ************************************************************************/#define LOAD_FAILED 2/*typedef FUNCTION(DriverEntry*, (*DRV_INITFN), (void*));*/static ErlDrvData dyn_start(ErlDrvPort, char*, SysDriverOpts* opts);static void dyn_stop(ErlDrvData);static void handle_command(ErlDrvData, char*, int);static void unload_all(void);#if defined(VXWORKS)static int reset_ddll_drv(void);#endifstruct erl_drv_entry ddll_driver_entry = {#if defined(VXWORKS) reset_ddll_drv, /* init needed */#else NULL, /* init */#endif dyn_start, /* start */ dyn_stop, /* stop */ handle_command, /* output */ NULL, /* ready_input */ NULL, /* ready_output */ "ddll", /* driver_name */ NULL, /* finish */ NULL /* handle */};static long erlang_port = -1;#if defined(_OSE_) void reset_ddll_drv(void) { erlang_port = -1;}#elif defined(VXWORKS)static int reset_ddll_drv(void) { erlang_port = -1; return 0;}#endifstatic long reply(long port, int success, char *str){ char tmp[200]; *tmp = success; strncpy(tmp + 1, str, 198); tmp[199] = 0; /* in case str was more than 198 bytes */ driver_output(port, tmp, strlen(tmp)); return 0;}static longerror_reply(char* atom, char* string){ char* reply_str; int alen; /* Length of atom. */ int slen; /* Length of string. */ int rlen; /* Length of reply. */ alen = strlen(atom); slen = strlen(string); rlen = 1+alen+1+slen; reply_str = driver_alloc(rlen+1); reply_str[0] = 'E'; strcpy(reply_str+1, atom); strcpy(reply_str+alen+2, string); driver_output(erlang_port, reply_str, rlen); driver_free(reply_str); return 0;}static ErlDrvData dyn_start(ErlDrvPort port, char *buf, SysDriverOpts* opts){ if (erlang_port != -1) { return ERL_DRV_ERROR_GENERAL; /* Already started! */ } erlang_port = port; return (ErlDrvData)port;}static void dyn_stop(ErlDrvData d){ erlang_port = -1; unload_all(); return;}static int unload(void* arg1, void* arg2, void* dummy1, void* dummy2){ DE_List* de = (DE_List*) arg1; int ix = (int) (long) arg2; DE_Handle* dh; int j; DEBUGF(("ddll_drv: unload: (%d) %s\r\n", ix, de->drv->driver_name)); /* * Kill all ports that depend on this driver. */ for (j = 0; j < erts_max_ports; j++) { if (!(erts_port[j].status & ERTS_PORT_SFLGS_DEAD) && erts_port[j].drv_ptr == de->drv) { driver_failure_atom(j, "driver_unloaded"); } } /* * Let the driver clean up its mess before unloading it. * We ignore errors from the finish funtion and * ddll_close(). */ dh = de->de_hndl; if (de->drv->finish) { (*(de->drv->finish))(); } DEBUGF(("ddll_drv: unload: lib=%08x\r\n", dh->handle)); ddll_close(dh->handle); driver_free((void*)dh); remove_driver_entry(de->drv); return ix != -1 ? reply(ix, 'o', "") : 0;}static void unload_all(){ DE_List *de; DE_Handle* dh; do { for (de = driver_list; de != NULL; de = de->next) { if ( (dh = de->de_hndl)) { unload((void *)de, (void *)erlang_port, NULL, NULL); break; } } } while (de != NULL);}static int load(char* full_name, char* driver_name){ ErlDrvEntry *dp; DE_Handle* dh; void *lib; ErlDrvEntry* (* initfn)(DE_Handle *); DEBUGF(("ddll_drv: load: %s, %s\r\n", full_name, driver_name)); if ((lib = ddll_open(full_name)) == NULL) { return error_reply("open_error", ddll_error()); } DEBUGF(("ddll_drv: load: lib=%08x\r\n", lib)); /* Some systems still require an underscore at the beginning of the * symbol name. If we can't find the name without the underscore, try * again with it. */ if ((initfn = ddll_sym(lib, "driver_init")) == NULL) if ((initfn = ddll_sym(lib, "_driver_init")) == NULL) { ddll_close(lib); return reply(erlang_port, 'e', "no_driver_init"); } /* * Here we go, lets hope the driver write knew what he was doing... */ dh = driver_alloc(sizeof(DE_Handle)); dh->handle = lib; dh->ref_count = 1; dh->status = ERL_DE_OK; dh->cb = NULL; dh->ca[0] = NULL;#ifdef __WIN32__ dp = initfn((DE_Handle *) win_get_ddll_init_param());#else dp = initfn(dh);#endif if (dp == NULL) { ddll_close(lib); driver_free(dh); return reply(erlang_port, 'e', "driver_init_failed"); } if (strcmp(driver_name, dp->driver_name) != 0) { ddll_close(lib); driver_free(dh); return reply(erlang_port, 'e', "bad_driver_name"); } dp->handle = dh; /* insert driver */ add_driver_entry(dp); return reply(erlang_port, 'o', "");}/* static reload callback */static int reload(void* arg1, void* arg2, void* arg3, void* arg4){ char* full_name = (char*) arg1; char* driver_name = (char*) arg2; int code; DEBUGF(("ddll_drv: reload: %s, %s\r\n", full_name, driver_name)); unload(arg3, arg4, NULL, NULL); code = load(full_name, driver_name); driver_free(full_name); driver_free(driver_name); return code;}static void handle_command(ErlDrvData inport, char *buf, int count){ char *driver_name; /* * Do some sanity checking on the commands passed in buf. Make sure the * last string is null terminated, and that buf isn't empty. */ if (count == 0 || (count > 1 && buf[count-1] != 0)) { driver_failure(erlang_port, 100); return; } switch (*buf++) { case LOAD_DRIVER: { char* full_name; DE_List *de; DE_Handle* dh; int j; if (count < 5) { driver_failure(erlang_port, 110); return; } driver_name = buf; j = strlen(driver_name); if (j == 0 || j+3 >= count) { driver_failure(erlang_port, 111); return; } full_name = buf+j+1; for (de = driver_list; de != NULL; de = de->next) { if (strcmp(de->drv->driver_name, driver_name) == 0) { dh = de->de_hndl; if (dh != NULL) { if (dh->status == ERL_DE_UNLOAD) { dh->status = ERL_DE_RELOAD; dh->cb = reload; dh->ca[2] = dh->ca[0]; dh->ca[3] = dh->ca[1]; dh->ca[0] = driver_alloc(strlen(full_name)+1); dh->ca[1] = driver_alloc(strlen(driver_name)+1); strcpy((char*)dh->ca[0], full_name); strcpy((char*)dh->ca[1], driver_name); return; } else if (dh->status == ERL_DE_RELOAD) { driver_free(dh->ca[0]); driver_free(dh->ca[1]); dh->ca[0] = driver_alloc(strlen(full_name)+1); dh->ca[1] = driver_alloc(strlen(driver_name)+1); strcpy((char*)dh->ca[0], full_name); strcpy((char*)dh->ca[1], driver_name); return; } } reply(erlang_port, 'e', "already_loaded"); return; } } load(full_name, driver_name); return; } case UNLOAD_DRIVER: { DE_List *de; DE_Handle* dh; if (count < 3) { driver_failure(erlang_port, 200); return; } driver_name = buf; DEBUGF(("ddll_drv: UNLOAD: %s\r\n", driver_name)); for (de = driver_list; de != NULL; de = de->next) { if (strcmp(de->drv->driver_name, driver_name) == 0) { dh = de->de_hndl; if (dh == NULL) { reply(erlang_port, 'e', "linked_in_driver"); return; } dh->ref_count--; if (dh->ref_count > 0) { DEBUGF(("ddll_drv: UNLOAD: ref_count =%d\r\n", dh->ref_count)); if (dh->status == ERL_DE_OK) { dh->status = ERL_DE_UNLOAD; dh->cb = unload; dh->ca[0] = (void*) de; dh->ca[1] = (void*) erlang_port; return; /* delayed op */ } else if (dh->status == ERL_DE_RELOAD) { dh->status = ERL_DE_UNLOAD; dh->cb = unload; driver_free(dh->ca[0]); driver_free(dh->ca[1]); dh->ca[0] = (void*) de; dh->ca[1] = (void*) erlang_port; return; } else if (dh->status == ERL_DE_UNLOAD) return; } else { unload((void*) de, (void*) erlang_port, NULL, NULL); return; } } } reply(erlang_port, 'e', "not_loaded"); return; } case GET_DRIVERS: { DE_List *pos; for (pos = driver_list; pos != NULL; pos = pos->next) { reply(erlang_port, 'i', pos->drv->driver_name); } reply(erlang_port, 'o', ""); return; } default: driver_failure(erlang_port, 999); } return;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?