diff options
Diffstat (limited to 'erts/emulator/beam/erl_driver.h')
-rw-r--r-- | erts/emulator/beam/erl_driver.h | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h new file mode 100644 index 0000000000..cdb584b282 --- /dev/null +++ b/erts/emulator/beam/erl_driver.h @@ -0,0 +1,626 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-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% + */ + +/* + * Include file for erlang driver writers. + */ + +#ifndef __ERL_DRIVER_H__ +#define __ERL_DRIVER_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef SIZEOF_CHAR +# define SIZEOF_CHAR_SAVED__ SIZEOF_CHAR +# undef SIZEOF_CHAR +#endif +#ifdef SIZEOF_SHORT +# define SIZEOF_SHORT_SAVED__ SIZEOF_SHORT +# undef SIZEOF_SHORT +#endif +#ifdef SIZEOF_INT +# define SIZEOF_INT_SAVED__ SIZEOF_INT +# undef SIZEOF_INT +#endif +#ifdef SIZEOF_LONG +# define SIZEOF_LONG_SAVED__ SIZEOF_LONG +# undef SIZEOF_LONG +#endif +#ifdef SIZEOF_LONG_LONG +# define SIZEOF_LONG_LONG_SAVED__ SIZEOF_LONG_LONG +# undef SIZEOF_LONG_LONG +#endif +#include "erl_int_sizes_config.h" +#if defined(SIZEOF_CHAR_SAVED__) && SIZEOF_CHAR_SAVED__ != SIZEOF_CHAR +# error SIZEOF_CHAR mismatch +#endif +#if defined(SIZEOF_SHORT_SAVED__) && SIZEOF_SHORT_SAVED__ != SIZEOF_SHORT +# error SIZEOF_SHORT mismatch +#endif +#if defined(SIZEOF_INT_SAVED__) && SIZEOF_INT_SAVED__ != SIZEOF_INT +# error SIZEOF_INT mismatch +#endif +#if defined(SIZEOF_LONG_SAVED__) && SIZEOF_LONG_SAVED__ != SIZEOF_LONG +# error SIZEOF_LONG mismatch +#endif +#if defined(SIZEOF_LONG_LONG_SAVED__) && SIZEOF_LONG_LONG_SAVED__ != SIZEOF_LONG_LONG +# error SIZEOF_LONG_LONG mismatch +#endif + +#include <stdlib.h> + +#if defined(VXWORKS) +# include <ioLib.h> +typedef struct iovec SysIOVec; +#elif defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_) +#ifndef STATIC_ERLANG_DRIVER + /* Windows dynamic drivers, everything is different... */ +#define ERL_DRIVER_TYPES_ONLY +#define WIN32_DYNAMIC_ERL_DRIVER +#endif +/* + * This structure can be cast to a WSABUF structure. + */ +typedef struct _SysIOVec { + unsigned long iov_len; + char* iov_base; +} SysIOVec; +#else /* Unix */ +# ifdef HAVE_SYS_UIO_H +# include <sys/types.h> +# include <sys/uio.h> +typedef struct iovec SysIOVec; +# else +typedef struct { + char* iov_base; + size_t iov_len; +} SysIOVec; +# endif +#endif + +#ifndef EXTERN +# ifdef __cplusplus +# define EXTERN extern "C" +# else +# define EXTERN extern +# endif +#endif + +/* Values for mode arg to driver_select() */ +#define ERL_DRV_READ (1 << 0) +#define ERL_DRV_WRITE (1 << 1) +#define ERL_DRV_USE (1 << 2) +#define ERL_DRV_USE_NO_CALLBACK (ERL_DRV_USE | (1 << 3)) + +/* Old deprecated */ +#define DO_READ ERL_DRV_READ +#define DO_WRITE ERL_DRV_WRITE + +#define ERL_DRV_EXTENDED_MARKER (0xfeeeeeed) +#define ERL_DRV_EXTENDED_MAJOR_VERSION 1 +#define ERL_DRV_EXTENDED_MINOR_VERSION 4 + +/* + * The emulator will refuse to load a driver with different major + * version than the one used by the emulator. + */ + + +/* Values for set_port_control_flags() */ + +#define PORT_CONTROL_FLAG_BINARY (1 << 0) +#define PORT_CONTROL_FLAG_HEAVY (1 << 1) + +/* Values for get_port_flags() */ + +#define PORT_FLAG_BINARY (1 << 0) +#define PORT_FLAG_LINE (1 << 1) + + +#define ERL_DRV_FLAG_USE_PORT_LOCKING (1 << 0) +#define ERL_DRV_FLAG_SOFT_BUSY (1 << 1) + +/* + * A binary as seen in a driver. Note that a binary should never be + * altered by the driver when it has been sent to Erlang. + */ + +typedef struct erl_drv_binary { + long orig_size; /* total length of binary */ + char orig_bytes[1]; /* the data (char instead of byte!) */ +} ErlDrvBinary; + + +/* + * Note: These types are incomplete to catch type errors easier. + */ + +typedef struct _erl_drv_data* ErlDrvData; /* Data to be used by the driver itself. */ +#ifndef ERL_SYS_DRV +typedef struct _erl_drv_event* ErlDrvEvent; /* An event to be selected on. */ +typedef struct _erl_drv_port* ErlDrvPort; /* A port descriptor. */ +#endif +typedef struct _erl_drv_port* ErlDrvThreadData; /* Thread data. */ + +#if !defined(__WIN32__) && !defined(_WIN32) && !defined(_WIN32_) && !defined(USE_SELECT) +struct erl_drv_event_data { + short events; + short revents; +}; +#endif +typedef struct erl_drv_event_data *ErlDrvEventData; /* Event data */ + +/* + * Used in monitors... + */ +typedef unsigned long ErlDrvTermData; +typedef unsigned long ErlDrvUInt; +typedef signed long ErlDrvSInt; + +#if defined(__WIN32__) +typedef unsigned __int64 ErlDrvUInt64; +typedef __int64 ErlDrvSInt64; +#elif SIZEOF_LONG == 8 +typedef unsigned long ErlDrvUInt64; +typedef long ErlDrvSInt64; +#elif SIZEOF_LONG_LONG == 8 +typedef unsigned long long ErlDrvUInt64; +typedef long long ErlDrvSInt64; +#else +#error No 64-bit integer type +#endif + +/* + * A driver monitor + */ +typedef struct { + unsigned char data[sizeof(void *)*4]; +} ErlDrvMonitor; + + +/* + * System info + */ + +typedef struct { + int driver_major_version; + int driver_minor_version; + char *erts_version; + char *otp_release; + int thread_support; + int smp_support; + int async_threads; + int scheduler_threads; +} ErlDrvSysInfo; + +typedef struct { + unsigned long megasecs; + unsigned long secs; + unsigned long microsecs; +} ErlDrvNowData; + +/* + * Error codes that can be return from driver. + */ + +/* + * Exception code from open_port/2 will be {'EXIT',{einval,Where}}. + */ +#define ERL_DRV_ERROR_GENERAL ((ErlDrvData) -1) + +/* + * Exception code from open_port/2 will be {'EXIT',{Errno,Where}}, + * where Errno is a textual representation of the errno variable + * (e.g. eacces if errno is EACCES). + */ +#define ERL_DRV_ERROR_ERRNO ((ErlDrvData) -2) + +/* + * Exception code from open_port/2 will be {'EXIT',{badarg,Where}}. + */ +#define ERL_DRV_ERROR_BADARG ((ErlDrvData) -3) + +typedef struct erl_io_vec { + int vsize; /* length of vectors */ + int size; /* total size in bytes */ + SysIOVec* iov; + ErlDrvBinary** binv; +} ErlIOVec; + +/* + * erl driver thread types + */ + +typedef struct ErlDrvTid_ *ErlDrvTid; +typedef struct ErlDrvMutex_ ErlDrvMutex; +typedef struct ErlDrvCond_ ErlDrvCond; +typedef struct ErlDrvRWLock_ ErlDrvRWLock; +typedef int ErlDrvTSDKey; + +typedef struct { + int suggested_stack_size; +} ErlDrvThreadOpts; + +/* + * + */ +typedef struct erl_drv_port_data_lock * ErlDrvPDL; + +/* + * This structure defines a driver. + */ + +typedef struct erl_drv_entry { + int (*init)(void); /* called at system start up for statically + linked drivers, and after loading for + dynamically loaded drivers */ + +#ifndef ERL_SYS_DRV + ErlDrvData (*start)(ErlDrvPort port, char *command); + /* called when open_port/2 is invoked. + return value -1 means failure. */ +#else + ErlDrvData (*start)(ErlDrvPort port, char *command, SysDriverOpts* opts); + /* special options, only for system driver */ +#endif + void (*stop)(ErlDrvData drv_data); + /* called when port is closed, and when the + emulator is halted. */ + void (*output)(ErlDrvData drv_data, char *buf, int len); + /* called when we have output from erlang to + the port */ + void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event); + /* called when we have input from one of + the driver's handles) */ + void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event); + /* called when output is possible to one of + the driver's handles */ + char *driver_name; /* name supplied as command + in open_port XXX ? */ + void (*finish)(void); /* called before unloading the driver - + DYNAMIC DRIVERS ONLY */ + void *handle; /* Reserved -- Used by emulator internally */ + int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, + int len, char **rbuf, int rlen); + /* "ioctl" for drivers - invoked by + port_control/3) */ + void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */ + void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev); + /* called when we have output from erlang + to the port */ + void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data); + void (*flush)(ErlDrvData drv_data); + /* called when the port is about to be + closed, and there is data in the + driver queue that needs to be flushed + before 'stop' can be called */ + int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, + int len, char **rbuf, int rlen, unsigned int *flags); + /* Works mostly like 'control', a syncronous + call into the driver. */ + void (*event)(ErlDrvData drv_data, ErlDrvEvent event, + ErlDrvEventData event_data); + /* Called when an event selected by + driver_event() has occurred */ + int extended_marker; /* ERL_DRV_EXTENDED_MARKER */ + int major_version; /* ERL_DRV_EXTENDED_MAJOR_VERSION */ + int minor_version; /* ERL_DRV_EXTENDED_MINOR_VERSION */ + int driver_flags; /* ERL_DRV_FLAGs */ + void *handle2; /* Reserved -- Used by emulator internally */ + void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor); + /* Called when a process monitor fires */ + void (*stop_select)(ErlDrvEvent event, void* reserved); + /* Called on behalf of driver_select when + it is safe to release 'event'. A typical + unix driver would call close(event) */ + /* When adding entries here, dont forget to pad in obsolete/driver.h */ +} ErlDrvEntry; + +/* + * This macro is used to name a dynamic driver's init function in + * a way that doesn't lead to conflicts. This is crucial when using + * operating systems that has one namespace for all symbols + * (e.g. VxWorks). Example: if you have an dynamic driver C source + * file named echo_drv.c, you use the macro like this: + * + * DRIVER_INIT(echo_drv) + * { + * .... + * } + * + * This function will be called by the Erlang I/O system when the driver is loaded. + * It must initialize a ErlDrvEntry structure and return a pointer to it. + */ + +/* For windows dynamic drivers */ +#ifndef ERL_DRIVER_TYPES_ONLY + +#if defined(VXWORKS) +# define DRIVER_INIT(DRIVER_NAME) ErlDrvEntry* DRIVER_NAME ## _init(void) +#elif defined(__WIN32__) +# define DRIVER_INIT(DRIVER_NAME) __declspec(dllexport) ErlDrvEntry* driver_init(void) +#else +# define DRIVER_INIT(DRIVER_NAME) ErlDrvEntry* driver_init(void) +#endif + +/* + * These are the functions available for driver writers. + */ +EXTERN int driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on); +EXTERN int driver_event(ErlDrvPort port, ErlDrvEvent event, + ErlDrvEventData event_data); +EXTERN int driver_output(ErlDrvPort port, char *buf, int len); +EXTERN int driver_output2(ErlDrvPort port, char *hbuf, int hlen, + char *buf, int len); +EXTERN int driver_output_binary(ErlDrvPort port, char *hbuf, int hlen, + ErlDrvBinary* bin, int offset, int len); +EXTERN int driver_outputv(ErlDrvPort port, char* hbuf, int hlen, ErlIOVec *ev, + int skip); +EXTERN int driver_vec_to_buf(ErlIOVec *ev, char *buf, int len); +EXTERN int driver_set_timer(ErlDrvPort port, unsigned long time); +EXTERN int driver_cancel_timer(ErlDrvPort port); +EXTERN int driver_read_timer(ErlDrvPort port, unsigned long *time_left); + +/* + * Get plain-text error message from within a driver + */ +EXTERN char* erl_errno_id(int error); + +/* + * The following functions are used to initiate a close of a port + * from a driver. + */ +EXTERN int driver_failure_eof(ErlDrvPort port); +EXTERN int driver_failure_atom(ErlDrvPort port, char *string); +EXTERN int driver_failure_posix(ErlDrvPort port, int error); +EXTERN int driver_failure(ErlDrvPort port, int error); +EXTERN int driver_exit (ErlDrvPort port, int err); + + +/* + * Port Data Lock + */ + +EXTERN ErlDrvPDL driver_pdl_create(ErlDrvPort); +EXTERN void driver_pdl_lock(ErlDrvPDL); +EXTERN void driver_pdl_unlock(ErlDrvPDL); +EXTERN long driver_pdl_get_refc(ErlDrvPDL); +EXTERN long driver_pdl_inc_refc(ErlDrvPDL); +EXTERN long driver_pdl_dec_refc(ErlDrvPDL); + +/* + * Process monitors + */ +EXTERN int +driver_monitor_process(ErlDrvPort port, ErlDrvTermData process, + ErlDrvMonitor *monitor); +EXTERN int +driver_demonitor_process(ErlDrvPort port, const ErlDrvMonitor *monitor); +EXTERN ErlDrvTermData +driver_get_monitored_process(ErlDrvPort port, const ErlDrvMonitor *monitor); +EXTERN int driver_compare_monitors(const ErlDrvMonitor *monitor1, + const ErlDrvMonitor *monitor2); + +/* + * Port attributes + */ +EXTERN void set_busy_port(ErlDrvPort port, int on); +EXTERN void set_port_control_flags(ErlDrvPort port, int flags); + +EXTERN int get_port_flags(ErlDrvPort port); + + +/* Binary interface */ + +/* + * NOTE: DO NOT overwrite a binary with new data (if the data is delivered); + * since the binary is a shared object it MUST be written once. + */ + +EXTERN ErlDrvBinary* driver_alloc_binary(int size); +EXTERN ErlDrvBinary* driver_realloc_binary(ErlDrvBinary *bin, int size); +EXTERN void driver_free_binary(ErlDrvBinary *bin); + +/* Referenc count on driver binaries */ +EXTERN long driver_binary_get_refc(ErlDrvBinary *dbp); +EXTERN long driver_binary_inc_refc(ErlDrvBinary *dbp); +EXTERN long driver_binary_dec_refc(ErlDrvBinary *dbp); + +/* Allocation interface */ +EXTERN void *driver_alloc(size_t size); +EXTERN void *driver_realloc(void *ptr, size_t size); +EXTERN void driver_free(void *ptr); + +/* Queue interface */ +EXTERN int driver_enq(ErlDrvPort port, char* buf, int len); +EXTERN int driver_pushq(ErlDrvPort port, char* buf, int len); +EXTERN int driver_deq(ErlDrvPort port, int size); +EXTERN int driver_sizeq(ErlDrvPort port); +EXTERN int driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, + int len); +EXTERN int driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, + int len); + +EXTERN int driver_peekqv(ErlDrvPort port, ErlIOVec *ev); +EXTERN SysIOVec* driver_peekq(ErlDrvPort port, int *vlen); +EXTERN int driver_enqv(ErlDrvPort port, ErlIOVec *ev, int skip); +EXTERN int driver_pushqv(ErlDrvPort port, ErlIOVec *ev, int skip); + +/* + * Add and remove driver entries. + */ +EXTERN void add_driver_entry(ErlDrvEntry *de); +EXTERN int remove_driver_entry(ErlDrvEntry *de); + +/* + * System info + */ +EXTERN void driver_system_info(ErlDrvSysInfo *sip, size_t si_size); + +/* + * erl driver thread functions. + */ + +EXTERN ErlDrvMutex *erl_drv_mutex_create(char *name); +EXTERN void erl_drv_mutex_destroy(ErlDrvMutex *mtx); +EXTERN int erl_drv_mutex_trylock(ErlDrvMutex *mtx); +EXTERN void erl_drv_mutex_lock(ErlDrvMutex *mtx); +EXTERN void erl_drv_mutex_unlock(ErlDrvMutex *mtx); +EXTERN ErlDrvCond *erl_drv_cond_create(char *name); +EXTERN void erl_drv_cond_destroy(ErlDrvCond *cnd); +EXTERN void erl_drv_cond_signal(ErlDrvCond *cnd); +EXTERN void erl_drv_cond_broadcast(ErlDrvCond *cnd); +EXTERN void erl_drv_cond_wait(ErlDrvCond *cnd, ErlDrvMutex *mtx); +EXTERN ErlDrvRWLock *erl_drv_rwlock_create(char *name); +EXTERN void erl_drv_rwlock_destroy(ErlDrvRWLock *rwlck); +EXTERN int erl_drv_rwlock_tryrlock(ErlDrvRWLock *rwlck); +EXTERN void erl_drv_rwlock_rlock(ErlDrvRWLock *rwlck); +EXTERN void erl_drv_rwlock_runlock(ErlDrvRWLock *rwlck); +EXTERN int erl_drv_rwlock_tryrwlock(ErlDrvRWLock *rwlck); +EXTERN void erl_drv_rwlock_rwlock(ErlDrvRWLock *rwlck); +EXTERN void erl_drv_rwlock_rwunlock(ErlDrvRWLock *rwlck); +EXTERN int erl_drv_tsd_key_create(char *name, ErlDrvTSDKey *key); +EXTERN void erl_drv_tsd_key_destroy(ErlDrvTSDKey key); +EXTERN void erl_drv_tsd_set(ErlDrvTSDKey key, void *data); +EXTERN void *erl_drv_tsd_get(ErlDrvTSDKey key); +EXTERN ErlDrvThreadOpts *erl_drv_thread_opts_create(char *name); +EXTERN void erl_drv_thread_opts_destroy(ErlDrvThreadOpts *opts); +EXTERN int erl_drv_thread_create(char *name, + ErlDrvTid *tid, + void * (*func)(void *), + void *args, + ErlDrvThreadOpts *opts); +EXTERN ErlDrvTid erl_drv_thread_self(void); +EXTERN int erl_drv_equal_tids(ErlDrvTid tid1, ErlDrvTid tid2); +EXTERN void erl_drv_thread_exit(void *resp); +EXTERN int erl_drv_thread_join(ErlDrvTid, void **respp); + +/* + * Misc. + */ +EXTERN int null_func(void); + +#endif /* !ERL_DRIVER_TYPES_ONLY */ + +/* Constants for return flags from the 'port_call' callback */ +#define DRIVER_CALL_KEEP_BUFFER 0x1 + +/* ErlDrvTerm is the type to use for casts when building + * terms that should be sent to connected process, + * for instance a tuple on the form {tcp, Port, [Tag|Binary]} + * + * ErlDrvTerm spec[] = { + * ERL_DRV_ATOM, driver_mk_atom("tcp"), + * ERL_DRV_PORT, driver_mk_port(drv->ix), + * ERL_DRV_INT, REPLY_TAG, + * ERL_DRV_BINARY, (ErlDrvTerm)bin, 50, 0, + * ERL_DRV_LIST, 2, + * ERL_DRV_TUPLE, 3, + * } + * + */ + +#define TERM_DATA(x) ((ErlDrvTermData) (x)) + +/* Possible types to send from driver Argument type */ +#define ERL_DRV_NIL ((ErlDrvTermData) 1) /* None */ +#define ERL_DRV_ATOM ((ErlDrvTermData) 2) /* driver_mk_atom(string) */ +#define ERL_DRV_INT ((ErlDrvTermData) 3) /* ErlDrvSInt */ +#define ERL_DRV_PORT ((ErlDrvTermData) 4) /* driver_mk_port(ix) */ +#define ERL_DRV_BINARY ((ErlDrvTermData) 5) /* ErlDrvBinary*, + * ErlDrvUInt size, + * ErlDrvUInt offs */ +#define ERL_DRV_STRING ((ErlDrvTermData) 6) /* char*, ErlDrvUInt */ +#define ERL_DRV_TUPLE ((ErlDrvTermData) 7) /* ErlDrvUInt */ +#define ERL_DRV_LIST ((ErlDrvTermData) 8) /* ErlDrvUInt */ +#define ERL_DRV_STRING_CONS ((ErlDrvTermData) 9) /* char*, ErlDrvUInt */ +#define ERL_DRV_PID ((ErlDrvTermData) 10) /* driver_connected,... */ + +#define ERL_DRV_FLOAT ((ErlDrvTermData) 11) /* double * */ +#define ERL_DRV_EXT2TERM ((ErlDrvTermData) 12) /* char *, ErlDrvUInt */ +#define ERL_DRV_UINT ((ErlDrvTermData) 13) /* ErlDrvUInt */ +#define ERL_DRV_BUF2BINARY ((ErlDrvTermData) 14) /* char *, ErlDrvUInt */ +#define ERL_DRV_INT64 ((ErlDrvTermData) 15) /* ErlDrvSInt64 * */ +#define ERL_DRV_UINT64 ((ErlDrvTermData) 16) /* ErlDrvUInt64 * */ + +#ifndef ERL_DRIVER_TYPES_ONLY + +/* make terms for driver_output_term and driver_send_term */ +EXTERN ErlDrvTermData driver_mk_atom(char*); +EXTERN ErlDrvTermData driver_mk_port(ErlDrvPort); +EXTERN ErlDrvTermData driver_connected(ErlDrvPort); +EXTERN ErlDrvTermData driver_caller(ErlDrvPort); +extern const ErlDrvTermData driver_term_nil; +EXTERN ErlDrvTermData driver_mk_term_nil(void); +EXTERN ErlDrvPort driver_create_port(ErlDrvPort creator_port, + ErlDrvTermData connected, /* pid */ + char* name, /* driver name */ + ErlDrvData drv_data); + + +/* output term data to the port owner */ +EXTERN int driver_output_term(ErlDrvPort ix, ErlDrvTermData* data, int len); +/* output term data to a specific process */ +EXTERN int driver_send_term(ErlDrvPort ix, ErlDrvTermData to, + ErlDrvTermData* data, int len); + +/* Async IO functions */ +EXTERN long driver_async(ErlDrvPort ix, + unsigned int* key, + void (*async_invoke)(void*), + void* async_data, + void (*async_free)(void*)); + + +EXTERN int driver_async_cancel(unsigned int key); + +/* Locks the driver in the machine "forever", there is + no unlock function. Note that this is almost never useful, as an open + port towards the driver locks it until the port is closed, why unexpected + unloading "never" happens. */ +EXTERN int driver_lock_driver(ErlDrvPort ix); + +/* Get the current 'now' timestamp (analogue to erlang:now()) */ +EXTERN int driver_get_now(ErlDrvNowData *now); + + +/* These were removed from the ANSI version, now they're back. */ + +EXTERN void *driver_dl_open(char *); +EXTERN void *driver_dl_sym(void *, char *); +EXTERN int driver_dl_close(void *); +EXTERN char *driver_dl_error(void); + +/* environment */ +EXTERN int erl_drv_putenv(char *key, char *value); +EXTERN int erl_drv_getenv(char *key, char *value, size_t *value_size); + +#endif /* !ERL_DRIVER_TYPES_ONLY */ + +#ifdef WIN32_DYNAMIC_ERL_DRIVER +# include "erl_win_dyn_driver.h" +#endif + +#endif + + + + |