1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
|
.TH driver_entry 3 "erts 5.6.3" "Ericsson AB" "ERLANG MODULE DEFINITION"
.SH MODULE
driver_entry \- The driver-entry structure used by erlang drivers\&.
.SH DESCRIPTION
.LP
As of erts version 5\&.5\&.3 the driver interface has been extended (see extended marker)\&. The extended interface introduce version management, the possibility to pass capability flags (see driver flags) to the runtime system at driver initialization, and some new driver API functions\&.
.SS Note:
.LP
Old drivers (compiled with an \fIerl_driver\&.h\fR from an earlier erts version than 5\&.5\&.3) have to be recompiled (but does not have to use the extended interface)\&.
.LP
The \fIdriver_entry\fR structure is a C struct that all erlang drivers defines\&. It contains entry points for the erlang driver that are called by the erlang emulator when erlang code accesses the driver\&.
.LP
The erl_driver driver API functions needs a port handle that identifies the driver instance (and the port in the emulator)\&. This is only passed to the \fIstart\fR function, but not to the other functions\&. The \fIstart\fR function returns a driver-defined handle that is passed to the other functions\&. A common practice is to have the \fIstart\fR function allocating some application-defined structure and stash the \fIport\fR handle in it, to use it later with the driver API functions\&.
.LP
The driver call-back functions are called synchronously from the erlang emulator\&. If they take too long before completing, they can cause timeouts in the emulator\&. Use the queue or asynchronous calls if nessecary, since the emulator must be responsive\&.
.LP
The driver structure contains the name of the driver and some 15 function pointers\&. These pointers are called at different times by the emulator\&.
.LP
The only exported function from the driver is \fIdriver_init\fR\&. This function returns the \fIdriver_entry\fR structure that points to the other functions in the driver\&. The \fIdriver_init\fR function is declared with a macro \fIDRIVER_INIT(drivername)\fR\&. (This is because different OS\&'s have different names for it\&.)
.LP
When writing a driver in C++, the driver entry should be of \fI"C"\fR linkage\&. One way to do this is to put this line somewhere before the driver entry: \fIextern "C" DRIVER_INIT(drivername);\fR\&.
.LP
When the driver has passed the \fIdriver_entry\fR over to the emulator, the driver is \fInot\fR allowed to modify the \fIdriver_entry\fR\&.
.SS Note:
.LP
Do \fInot\fR declare the \fIdriver_entry\fR\fIconst\fR\&. This since the emulator needs to modify the \fIhandle\fR, and the \fIhandle2\fR fields\&. A statically allocated, and \fIconst\fR declared \fIdriver_entry\fR may be located in read only memory which will cause the emulator to crash\&.
.LP
Here is the declaration of \fIdriver_entry\fR:
.nf
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 */
} ErlDrvEntry;
.fi
.SH EXPORTS
.LP
.B
int init(void)
.br
.RS
.LP
This is called directly after the driver has been loaded by \fIerl_ddll:load_driver/2\fR\&. (Actually when the driver is added to the driver list\&.) The driver should return 0, or if the driver can\&'t initialize, -1\&.
.RE
.LP
.B
int start(ErlDrvPort port, char* command)
.br
.RS
.LP
This is called when the driver is instantiated, when \fIopen_port/2\fR is called\&. The driver should return a number >= 0 or a pointer, or if the driver can\&'t be started, one of three error codes should be returned:
.LP
ERL_DRV_ERROR_GENERAL - general error, no error code
.LP
ERL_DRV_ERROR_ERRNO - error with error code in erl_errno
.LP
ERL_DRV_ERROR_BADARG - error, badarg
.LP
If an error code is returned, the port isn\&'t started\&.
.RE
.LP
.B
void stop(ErlDrvData drv_data)
.br
.RS
.LP
This is called when the port is closed, with \fIport_close/1\fR or \fIPort ! {self(), close}\fR\&. Note that terminating the port owner process also closes the p port\&.
.RE
.LP
.B
void output(ErlDrvData drv_data, char *buf, int len)
.br
.RS
.LP
This is called when an erlang process has sent data to the port\&. The data is pointed to by \fIbuf\fR, and is \fIlen\fR bytes\&. Data is sent to the port with \fIPort ! {self(), {command, Data}}\fR, or with \fIport_command/2\fR\&. Depending on how the port was opened, it should be either a list of integers 0\&.\&.\&.255 or a binary\&. See \fIopen_port/3\fR and \fIport_command/2\fR\&.
.RE
.LP
.B
void ready_input(ErlDrvData drv_data, ErlDrvEvent event)
.br
.B
void ready_output(ErlDrvData drv_data, ErlDrvEvent event)
.br
.RS
.LP
This is called when a driver event (given in the \fIevent\fR parameter) is signaled\&. This is used to help asynchronous drivers "wake up" when something happens\&.
.LP
On unix the \fIevent\fR is a pipe or socket handle (or something that the \fIselect\fR system call understands)\&.
.LP
On Windows the \fIevent\fR is an Event or Semaphore (or something that the \fIWaitForMultipleObjects\fR API function understands)\&. (Some trickery in the emulator allows more than the built-in limit of 64 \fIEvents\fR to be used\&.)
.LP
To use this with threads and asynchronous routines, create a pipe on unix and an Event on Windows\&. When the routine completes, write to the pipe (use \fISetEvent\fR on Windows), this will make the emulator call \fIready_input\fR or \fIready_output\fR\&.
.RE
.LP
.B
char *driver_name
.br
.RS
.LP
This is the name of the driver, it must correspond to the atom used in \fIopen_port\fR, and the name of the driver library file (without the extension)\&.
.RE
.LP
.B
void finish(void)
.br
.RS
.LP
This function is called by the \fIerl_ddll\fR driver when the driver is unloaded\&. (It is only called in dynamic drivers\&.)
.LP
The driver is only unloaded as a result of calling \fIunload_driver/1\fR, or when the emulator halts\&.
.RE
.LP
.B
void *handle
.br
.RS
.LP
This field is reserved for the emulators internal use\&. The emulator will modify this field; therefore, it is important that the \fIdriver_entry\fR isn\&'t declared \fIconst\fR\&.
.RE
.LP
.B
int control(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen)
.br
.RS
.LP
This is a special routine invoked with the erlang function \fIport_control/3\fR\&. It works a little like an "ioctl" for erlang drivers\&. The data given to \fIport_control/3\fR arrives in \fIbuf\fR and \fIlen\fR\&. The driver may send data back, using \fI*rbuf\fR and \fIrlen\fR\&.
.LP
This is the fastest way of calling a driver and get a response\&. It won\&'t make any context switch in the erlang emulator, and requires no message passing\&. It is suitable for calling C function to get faster execution, when erlang is too slow\&.
.LP
If the driver wants to return data, it should return it in \fIrbuf\fR\&. Data is returned different depending on the port control flags (those that are set with set_port_control_flags)\&.
.LP
If the flag is set to \fIPORT_CONTROL_FLAG_BINARY\fR, then \fI*rbuf\fR must point to a binary allocated with driver_alloc_binary or be NULL\&. This binary will be freed automatically after \fIcontrol\fR has returned\&. The driver can retain the returned binary for \fIread only\fR access with driver_binary_inc_refc to be freed later with driver_free_binary\&. It is never allowed to alter the binary after \fIcontrol\fR has returned\&. If \fI*rbuf\fR is set to NULL, an empty list will be returned\&.
.LP
If the flag is set to \fI0\fR, \fIrbuf\fR points to a \fIchar*\fR containing data, that is returned as a list of integers\&. When \fIcontrol\fR is called, \fI*rbuf\fR points to a buffer of \fIrlen\fR bytes, which can be used to return data\&. A larger buffer can be allocated with driver_alloc\&. The buffer will be freed automatically after \fIcontrol\fR has returned\&.
.LP
Using binaries is faster if more than a few bytes are returned\&.
.LP
The return value is the number of bytes returned in \fI*rbuf\fR\&.
.RE
.LP
.B
void timeout(ErlDrvData drv_data)
.br
.RS
.LP
This function is called any time after the driver\&'s timer reaches 0\&. The timer is activeated with \fIdriver_set_timer\fR\&. There are no priorities or ordering among drivers, so if several drivers time out at the same time, any one of them is called first\&.
.RE
.LP
.B
void outputv(ErlDrvData drv_data, ErlIOVec *ev)
.br
.RS
.LP
This function is called whenever the port is written to\&. If it is \fINULL\fR, the \fIoutput\fR function is called instead\&. This function is faster than \fIoutput\fR, because it takes an \fIErlIOVec\fR directly, which requires no copying of the data\&. The port should be in binary mode, see \fIopen_port/2\fR\&.
.LP
The \fIErlIOVec\fR contains both a \fISysIOVec\fR, suitable for \fIwritev\fR, and one or more binaries\&. If these binaries should be retained, when the driver returns from \fIoutputv\fR, they can be queued (using driver_enq_bin for instance), or if they are kept in a static or global variable, the reference counter can be incremented\&.
.RE
.LP
.B
void ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data)
.br
.RS
.LP
This function is called after an asynchronous call has completed\&. The asynchronous call is started with driver_async\&. This function is called from the erlang emulator thread, as opposed to the asynchronous function, which is called in some thread (if multithreading is enabled)\&.
.RE
.LP
.B
int call(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned int *flags)
.br
.RS
.LP
This function is called from \fIerlang:port_call/3\fR\&. It works a lot like the \fIcontrol\fR call-back, but uses the external term format for input and output\&.
.LP
\fIcommand\fR is an integer, obtained from the call from erlang (the second argument to \fIerlang:port_call/3\fR)\&.
.LP
\fIbuf\fR and \fIlen\fR provide the arguments to the call (the third argument to \fIerlang:port_call/3\fR)\&. They can be decoded using \fIei\fR functions\&.
.LP
\fIrbuf\fR points to a return buffer, \fIrlen\fR bytes long\&. The return data should be a valid erlang term in the external (binary) format\&. This is converted to an erlang term and returned by \fIerlang:port_call/3\fR to the caller\&. If more space than \fIrlen\fR bytes is needed to return data, \fI*rbuf\fR can be set to memory allocated with \fIdriver_alloc\fR\&. This memory will be freed automatically after \fIcall\fR has returned\&.
.LP
The return value is the number of bytes returned in \fI*rbuf\fR\&. If \fIERL_DRV_ERROR_GENERAL\fR is returned (or in fact, anything < 0), \fIerlang:port_call/3\fR will throw a \fIBAD_ARG\fR\&.
.RE
.LP
.B
void event(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data)
.br
.RS
.LP
Intentionally left undocumented\&.
.RE
.LP
.B
int extended_marker
.br
.RS
.LP
This field should either be equal to \fIERL_DRV_EXTENDED_MARKER\fR or \fI0\fR\&. An old driver (not aware of the extended driver interface) should set this field to \fI0\fR\&. If this field is equal to \fI0\fR, all the fields following this field also \fIhave\fR to be \fI0\fR, or \fINULL\fR in case it is a pointer field\&.
.RE
.LP
.B
int major_version
.br
.RS
.LP
This field should equal \fIERL_DRV_EXTENDED_MAJOR_VERSION\fR if the \fIextended_marker\fR field equals \fIERL_DRV_EXTENDED_MARKER\fR\&.
.RE
.LP
.B
int minor_version
.br
.RS
.LP
This field should equal \fIERL_DRV_EXTENDED_MINOR_VERSION\fR if the \fIextended_marker\fR field equals \fIERL_DRV_EXTENDED_MARKER\fR\&.
.RE
.LP
.B
int driver_flags
.br
.RS
.LP
This field is used to pass driver capability information to the runtime system\&. If the \fIextended_marker\fR field equals \fIERL_DRV_EXTENDED_MARKER\fR, it should contain \fI0\fR or driver flags (\fIERL_DRV_FLAG_*\fR) ored bitwise\&. Currently the following driver flags exist:
.RS 2
.TP 4
.B
\fIERL_DRV_FLAG_USE_PORT_LOCKING\fR:
The runtime system will use port level locking on all ports executing this driver instead of driver level locking when the driver is run in a runtime system with SMP support\&. For more information see the erl_driver documentation\&.
.RE
.RE
.LP
.B
void *handle2
.br
.RS
.LP
This field is reserved for the emulators internal use\&. The emulator will modify this field; therefore, it is important that the \fIdriver_entry\fR isn\&'t declared \fIconst\fR\&.
.RE
.LP
.B
void process_exit(ErlDrvData drv_data, ErlDrvMonitor *monitor)
.br
.RS
.LP
This callback is called when a monitored process exits\&. The \fIdrv_data\fR is the data associated with the port for which the process is monitored (using driver_monitor_process) and the \fImonitor\fR corresponds to the \fIErlDrvMonitor\fR structure filled in when creating the monitor\&. The driver interface function driver_get_monitored_process can be used to retrieve the process id of the exiting process as an \fIErlDrvTermData\fR
.RE
.SH SEE ALSO
.LP
erl_driver(3), erl_ddll(3), erlang(3), kernel(3)
|