From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- erts/doc/src/driver_entry.xml | 453 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 erts/doc/src/driver_entry.xml (limited to 'erts/doc/src/driver_entry.xml') diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml new file mode 100644 index 0000000000..6b7d2acf24 --- /dev/null +++ b/erts/doc/src/driver_entry.xml @@ -0,0 +1,453 @@ + + + + +
+ + 20012009 + Ericsson AB. 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. + + + + driver_entry + Jakob Cederlund + Jakob Cederlund + 1 + + + 2001-10-01 + PA1 + driver_entry.xml +
+ driver_entry + The driver-entry structure used by erlang drivers. + +

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.

+ +

Old drivers (compiled with an erl_driver.h from an + earlier erts version than 5.5.3) have to be recompiled + (but does not have to use the extended interface).

+
+

The driver_entry 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.

+

+ + 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 start function, but + not to the other functions. The start function returns a + driver-defined handle that is passed to the other functions. A + common practice is to have the start function allocating + some application-defined structure and stash the port + handle in it, to use it later with the driver API functions.

+

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 necessary, since the emulator must be + responsive.

+

The driver structure contains the name of the driver and some + 15 function pointers. These pointers are called at different + times by the emulator.

+

The only exported function from the driver is + driver_init. This function returns the driver_entry + structure that points to the other functions in the driver. The + driver_init function is declared with a macro + DRIVER_INIT(drivername). (This is because different OS's + have different names for it.)

+

When writing a driver in C++, the driver entry should be of + "C" linkage. One way to do this is to put this line + somewhere before the driver entry: + extern "C" DRIVER_INIT(drivername);.

+

When the driver has passed the driver_entry over to + the emulator, the driver is not allowed to modify the + driver_entry.

+ +

Do not declare the driver_entryconst. This since the emulator needs to + modify the handle, and the handle2 + fields. A statically allocated, and const + declared driver_entry may be located in + read only memory which will cause the emulator + to crash.

+
+
+ +
+ DATA TYPES + + ErlDrvEntry + +

+ +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 to close an event object */ + } ErlDrvEntry; + +

+ + int (*init)(void) + +

This is called directly after the driver has been loaded by + erl_ddll:load_driver/2. (Actually when the driver is + added to the driver list.) The driver should return 0, or if + the driver can't initialize, -1.

+
+ int (*start)(ErlDrvPort port, char* command) + +

This is called when the driver is instantiated, when + open_port/2 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:

+

ERL_DRV_ERROR_GENERAL - general error, no error code

+

ERL_DRV_ERROR_ERRNO - error with error code in erl_errno

+

ERL_DRV_ERROR_BADARG - error, badarg

+

If an error code is returned, the port isn't started.

+
+ void (*stop)(ErlDrvData drv_data) + +

This is called when the port is closed, with + port_close/1 or Port ! {self(), close}. Note + that terminating the port owner process also closes the + p\011 port.

+
+ void (*output)(ErlDrvData drv_data, char *buf, int len) + +

This is called when an erlang process has sent data to the + port. The data is pointed to by buf, and is + len bytes. Data is sent to the port with Port ! {self(), {command, Data}}, or with + port_command/2. Depending on how the port was opened, + it should be either a list of integers 0...255 or a + binary. See open_port/3 and port_command/2.

+
+ + void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event) + void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event) + +

This is called when a driver event (given in the + event parameter) is signaled. This is used to help + asynchronous drivers "wake up" when something happens.

+

On unix the event is a pipe or socket handle (or + something that the select system call understands).

+

On Windows the event is an Event or Semaphore (or + something that the WaitForMultipleObjects API + function understands). (Some trickery in the emulator allows + more than the built-in limit of 64 Events to be used.)

+

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 SetEvent on + Windows), this will make the emulator call + ready_input or ready_output.

+
+ char *driver_name + +

This is the name of the driver, it must correspond to the + atom used in open_port, and the name of the driver + library file (without the extension).

+
+ void (*finish)(void) + +

This function is called by the erl_ddll driver when the + driver is unloaded. (It is only called in dynamic drivers.)

+

The driver is only unloaded as a result of calling + unload_driver/1, or when the emulator halts.

+
+ void *handle + +

This field is reserved for the emulators internal use. The + emulator will modify this field; therefore, it is important + that the driver_entry isn't declared const.

+
+ int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen) + +

This is a special routine invoked with the erlang function + port_control/3. It works a little like an "ioctl" for + erlang drivers. The data given to port_control/3 + arrives in buf and len. The driver may send + data back, using *rbuf and rlen.

+

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.

+

If the driver wants to return data, it should return it in + rbuf. When control is called, + *rbuf points to a default buffer of rlen bytes, which + can be used to return data. Data is returned different depending on + the port control flags (those that are set with + set_port_control_flags). +

+

If the flag is set to PORT_CONTROL_FLAG_BINARY, + a binary will be returned. Small binaries can be returned by writing + the raw data into the default buffer. A binary can also be + returned by setting *rbuf to point to a binary allocated with + driver_alloc_binary. + This binary will be freed automatically after control has returned. + The driver can retain the binary for read only access with + driver_binary_inc_refc to be freed later with + driver_free_binary. + It is never allowed to alter the binary after control has returned. + If *rbuf is set to NULL, an empty list will be returned. +

+

If the flag is set to 0, data is returned as a + list of integers. Either use the default buffer or set + *rbuf to point to a larger buffer allocated with + driver_alloc. + The buffer will be freed automatically after control has returned.

+

Using binaries is faster if more than a few bytes are returned.

+

The return value is the number of bytes returned in + *rbuf.

+
+ + void (*timeout)(ErlDrvData drv_data) + +

This function is called any time after the driver's timer + reaches 0. The timer is activated with + driver_set_timer. 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.

+
+ + void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev) + +

This function is called whenever the port is written to. If + it is NULL, the output function is called + instead. This function is faster than output, because + it takes an ErlIOVec directly, which requires no + copying of the data. The port should be in binary mode, see + open_port/2.

+

The ErlIOVec contains both a SysIOVec, + suitable for writev, and one or more binaries. If + these binaries should be retained, when the driver returns + from outputv, 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.

+
+ void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data) + +

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).

+
+ int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned int *flags) + +

This function is called from erlang:port_call/3. It + works a lot like the control call-back, but uses the + external term format for input and output.

+

command is an integer, obtained from the call from + erlang (the second argument to erlang:port_call/3).

+

buf and len provide the arguments to the call + (the third argument to erlang:port_call/3). They can + be decoded using ei functions.

+

rbuf points to a return buffer, rlen 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 erlang:port_call/3 to the + caller. If more space than rlen bytes is needed to + return data, *rbuf can be set to memory allocated with + driver_alloc. This memory will be freed automatically + after call has returned.

+

The return value is the number of bytes returned in + *rbuf. If ERL_DRV_ERROR_GENERAL is returned + (or in fact, anything < 0), erlang:port_call/3 will + throw a BAD_ARG.

+
+ void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data) + +

Intentionally left undocumented.

+
+ int extended_marker + +

+ This field should either be equal to ERL_DRV_EXTENDED_MARKER + or 0. An old driver (not aware of the extended driver + interface) should set this field to 0. If this field is + equal to 0, all the fields following this field also + have to be 0, or NULL in case it is a + pointer field. +

+
+ int major_version + +

This field should equal ERL_DRV_EXTENDED_MAJOR_VERSION if + the extended_marker field equals + ERL_DRV_EXTENDED_MARKER.

+
+ int minor_version + +

+ This field should equal ERL_DRV_EXTENDED_MINOR_VERSION if + the extended_marker field equals + ERL_DRV_EXTENDED_MARKER. +

+
+ + int driver_flags + +

This field is used to pass driver capability information to the + runtime system. If the extended_marker field equals + ERL_DRV_EXTENDED_MARKER, it should contain 0 or + driver flags (ERL_DRV_FLAG_*) ored bitwise. Currently + the following driver flags exist: +

+ + ERL_DRV_FLAG_USE_PORT_LOCKING + + 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. + + ERL_DRV_FLAG_SOFT_BUSY + + Marks that driver instances can handle being called + in the output and/or + outputv callbacks even + though a driver instance has marked itself as busy (see + set_busy_port()). + Since erts version 5.7.4 this flag is required for drivers used + by the Erlang distribution (the behaviour has always been + required by drivers used by the distribution). + + +
+ void *handle2 + +

+ This field is reserved for the emulators internal use. The + emulator will modify this field; therefore, it is important + that the driver_entry isn't declared const. +

+
+ void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor) + +

This callback is called when a monitored process exits. The + drv_data is the data associated with the port for which + the process is monitored (using driver_monitor_process) + and the monitor corresponds to the ErlDrvMonitor + 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 ErlDrvTermData.

+
+ void (*stop_select)(ErlDrvEvent event, void* reserved) + +

This function is called on behalf of + driver_select + when it is safe to close an event object.

+

A typical implementation on Unix is to do + close((int)event).

+

Argument reserved is intended for future use and should be ignored.

+

In contrast to most of the other call-back functions, + stop_select is called independent of any port. No + ErlDrvData argument is passed to the function. No + driver lock or port lock is guaranteed to be held. The port that + called driver_select might even be closed at the + time stop_select is called. But it could also be + the case that stop_select is called directly by + driver_select.

+

It is not allowed to call any functions in the + driver API from + stop_select. This strict limitation is due to the + volatile context that stop_select may be called.

+
+ +
+ + + +
+ +
+ SEE ALSO +

erl_driver(3), + erl_ddll(3), + erlang(3), + kernel(3)

+
+
+ -- cgit v1.2.3