erl_ppl_drv.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 309 行
C
309 行
/* ``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$ *//* --------------------- PORT PROGRAM LOADER ----------------- * This is a driver that can be used to load and start an OSE * program - an Erlang port program - given the load module * name. Example, loading the module "drv_lm": * * P = erlang:open_port({spawn,erl_ppl_drv}, []). * Result = port_call(P, 0, "drv_lm") * * Result = {ok,Handle} | {error,Reason} * * Note that the port program should take care of registering * and unregistering itself! * ----------------------------------------------------------- */#include <stdio.h>#include "ose.h"#include "ose_erl_driver.h"#include "ei.h"#include "stdlib.h"#include "stdio.h"#include "string.h"#include "prh.sig"#include "prhfuncs.h"#define LOAD 0#define UNLOAD 1#define NO_PLS -1#define PGM_NOT_REG -2#define FAIL(v, r) { ((v)=(r)); return -1; } #define SUCCESS(v, r) { ((v)=(r)); return 0; }#define ATTACH_SIGNO (~0UL)#define PLS_SERVER "ose_pls_elf/"/* -------------------------------------------------------------------------** Data types**/typedef struct _erl_drv_data PplDrvData;union SIGNAL{ SIGSELECT sigNo; struct PrhLoadProgramRequest loadProgramRequest; struct PrhLoadProgramReply loadProgramReply; struct PrhStartProgramRequest startProgramRequest; struct PrhStartProgramReply startProgramReply; struct PrhKillProgramRequest killProgramRequest; struct PrhKillProgramReply killProgramReply; struct PrhRemoveLMRequest removeLMRequest; struct PrhRemoveLMReply removeLMReply;};/* -------------------------------------------------------------------------** Entry struct**/static PplDrvData *ppl_drv_start(ErlDrvPort port, char *command);static void ppl_drv_stop(PplDrvData *data_p);static void ppl_drv_output(PplDrvData *data_p, char *buf, int len);static void ppl_drv_finish(void);static int ppl_drv_call(PplDrvData *data_p, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned *ret_flags); static ErlDrvEntry ppl_drv_entry = { NULL, /* init */ ppl_drv_start, ppl_drv_stop, ppl_drv_output, NULL, /* ready_input */ NULL, /* ready_output */ "erl_ppl_drv", ppl_drv_finish, NULL, /* handle */ NULL, /* control */ NULL, /* timeout */ NULL, /* outputv */ NULL, /* ready_async */ NULL, /* flush */ ppl_drv_call, NULL /* event */};/* -------------------------------------------------------------------------** Entry functions**/ERL_DRIVER_INIT(erl_ppl_drv){ DRIVER_INTERFACE_INIT(); return &ppl_drv_entry;}static PplDrvData *ppl_drv_start(ErlDrvPort port, char *command) { void *void_ptr; return void_ptr = port;}static void ppl_drv_stop(PplDrvData *data_p) {}static void ppl_drv_output(PplDrvData *data_p, char *buf, int len) {}static void ppl_drv_finish() {}static int pls_req(union SIGNAL **sig) { PROCESS pls_; OSATTREF attref; static const SIGSELECT select[] = {5, PRH_LOAD_PROGRAM_REPLY, PRH_START_PROGRAM_REPLY, PRH_KILL_PROGRAM_REPLY, PRH_REMOVE_LM_REPLY, ATTACH_SIGNO}; if(!hunt(PLS_SERVER, 0, &pls_, NULL)) { free_buf(sig); return -1; } send(sig, pls_); *sig = alloc(sizeof(SIGSELECT), ATTACH_SIGNO); attref = attach(sig, pls_); *sig = receive((SIGSELECT *) select); if((*sig)->sigNo == ATTACH_SIGNO) { free_buf(sig); return -1; } detach(&attref); return 0;}extern int add_pgm_handle(char*, PrhProgramHandle);static int load_pgm(char *name, PrhProgramHandle *result, int *reason) { struct PrhConnectAsfReply *conReply; struct PrhLoadProgramReply *loadReply; PrhProgramHandle hnd; PrhStatus res; union SIGNAL *sig; int size, status; char *elfname; size = strlen(name) + 2; sig = alloc(sizeof(struct PrhLoadProgramRequest) + size, PRH_LOAD_PROGRAM_REQUEST); sig->loadProgramRequest.programHandle = PRH_ALLOCATE_HANDLE; sig->loadProgramRequest.options = 0; prh_init_strings(&sig->loadProgramRequest.strings); prh_add_string(&sig->loadProgramRequest.strings, name); printf("Loading %s...\n", name); if(pls_req(&sig) < 0) FAIL(*reason, NO_PLS) loadReply = &sig->loadProgramReply; /* if LM wasn't found, try with an elf extension */ if(loadReply->status == PRH_ELM_NOT_FOUND) { free_buf(&sig); elfname = driver_alloc(strlen(name) + 5); sprintf(elfname, "%s.elf", name); size = strlen(elfname) + 2; sig = alloc(sizeof(struct PrhLoadProgramRequest) + size, PRH_LOAD_PROGRAM_REQUEST); sig->loadProgramRequest.programHandle = PRH_ALLOCATE_HANDLE; sig->loadProgramRequest.options = 0; prh_init_strings(&sig->loadProgramRequest.strings); prh_add_string(&sig->loadProgramRequest.strings, elfname); printf("Trying %s...\n", elfname); driver_free(elfname); if(pls_req(&sig) < 0) FAIL(*reason, NO_PLS) /* start program (which should register the port prog) */ if(loadReply->status == PRH_SUCCESS) { hnd = loadReply->programHandle; free_buf(&sig); sig = alloc(sizeof(struct PrhStartProgramRequest), PRH_START_PROGRAM_REQUEST); sig->startProgramRequest.programHandle = hnd; printf("Starting %s (%u)...\n", name, hnd); if(pls_req(&sig) < 0) FAIL(*reason, NO_PLS) if(sig->startProgramReply.status == PRH_SUCCESS) { free_buf(&sig); printf("Mapping %s -> %u...\n", name, hnd); /* save program handle with name and entrypoint */ if(!add_pgm_handle(name, hnd)) { *result = hnd; FAIL(*reason, PGM_NOT_REG) } SUCCESS(*result, hnd) } status = sig->startProgramReply.status; free_buf(&sig); FAIL(*reason, status) } status = loadReply->status; free_buf(&sig); FAIL(*reason, status) }}static int unload_pgm(PrhProgramHandle hnd, int *reason) { union SIGNAL *sig; static const SIGSELECT select[] = {3, PRH_KILL_PROGRAM_REPLY, PRH_REMOVE_LM_REPLY, ATTACH_SIGNO}; PrhStatus status; /* kill the program */ sig = alloc(sizeof (struct PrhKillProgramRequest), PRH_KILL_PROGRAM_REQUEST); sig->killProgramRequest.programHandle = (PrhProgramHandle)hnd; printf("Unloading pgm %d...\n", hnd); if(pls_req(&sig) < 0) FAIL(*reason, NO_PLS) if(sig->killProgramReply.status != PRH_SUCCESS) { status = sig->killProgramReply.status; free_buf(&sig); FAIL(*reason, status) } free_buf(&sig); SUCCESS(*reason, 0)} static int encode_ok(unsigned long result, char **rbuf, int rlen) { int nlen; ei_x_buff x; ei_x_new(&x); ei_x_format(&x, "{~a,~u}", "ok", result); nlen = x.index; if (nlen > rlen) { *rbuf = driver_alloc(nlen); } memcpy(*rbuf,x.buff,nlen); ei_x_free(&x); return nlen;} static int encode_error(int reason, char **rbuf, int rlen) { int nlen; ei_x_buff x; ei_x_new(&x); ei_x_format(&x, "{~a,~i}", "error", reason); nlen = x.index; if (nlen > rlen) { *rbuf = driver_alloc(nlen); } memcpy(*rbuf,x.buff,nlen); ei_x_free(&x); return nlen;} static int ppl_drv_call(PplDrvData *data_p, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned *ret_flags) { char name[256]; PrhProgramHandle hnd; int reason, ver, type, sz, index = 0, dummy; ei_x_buff x; ei_decode_version(buf, &index, &ver); switch(command) { case LOAD: ei_decode_string(buf, &index, name); if(load_pgm(name, &hnd, &reason) < 0) { if(reason == PGM_NOT_REG) { unload_pgm(hnd, &dummy); } return encode_error(reason, rbuf, rlen); } return encode_ok((unsigned long)hnd, rbuf, rlen); case UNLOAD: ei_decode_ulong(buf, &index, (unsigned long *)&hnd); if(unload_pgm(hnd, &reason) < 0) return encode_error(reason, rbuf, rlen); return encode_ok(0, rbuf, rlen); default: return -1; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?