Sends data in the special driver term format to the port owner process. This is a fast way to deliver term data from a driver. It needs no binary conversion, so the port owner process receives data as normal Erlang terms. The erl_drv_send_term
functions can be used for sending to any process on the local node.
Note
Parameter port
is not an ordinary port handle, but a port handle converted using driver_mk_port
.
Parameter term
points to an array of ErlDrvTermData
with n
elements. This array contains terms described in the driver term format. Every term consists of 1-4 elements in the array. The first term has a term type and then arguments. Parameter port
specifies the sending port.
Tuples, maps, and lists (except strings, see below) are built in reverse polish notation, so that to build a tuple, the elements are specified first, and then the tuple term, with a count. Likewise for lists and maps.
-
A tuple must be specified with the number of elements. (The elements precede the ERL_DRV_TUPLE
term.)
-
A map must be specified with the number of key-value pairs N
. The key-value pairs must precede the ERL_DRV_MAP
in this order: key1,value1,key2,value2,...,keyN,valueN
. Duplicate keys are not allowed.
-
A list must be specified with the number of elements, including the tail, which is the last term preceding ERL_DRV_LIST
.
The special term ERL_DRV_STRING_CONS
is used to "splice" in a string in a list, a string specified this way is not a list in itself, but the elements are elements of the surrounding list.
Term type Arguments
--------- ---------
ERL_DRV_NIL
ERL_DRV_ATOM ErlDrvTermData atom (from driver_mk_atom(char *string))
ERL_DRV_INT ErlDrvSInt integer
ERL_DRV_UINT ErlDrvUInt integer
ERL_DRV_INT64 ErlDrvSInt64 *integer_ptr
ERL_DRV_UINT64 ErlDrvUInt64 *integer_ptr
ERL_DRV_PORT ErlDrvTermData port (from driver_mk_port(ErlDrvPort port))
ERL_DRV_BINARY ErlDrvBinary *bin, ErlDrvUInt len, ErlDrvUInt offset
ERL_DRV_BUF2BINARY char *buf, ErlDrvUInt len
ERL_DRV_STRING char *str, int len
ERL_DRV_TUPLE int sz
ERL_DRV_LIST int sz
ERL_DRV_PID ErlDrvTermData pid (from driver_connected(ErlDrvPort port)
or driver_caller(ErlDrvPort port))
ERL_DRV_STRING_CONS char *str, int len
ERL_DRV_FLOAT double *dbl
ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
ERL_DRV_MAP int sz
The unsigned integer data type ErlDrvUInt
and the signed integer data type ErlDrvSInt
are 64 bits wide on a 64-bit runtime system and 32 bits wide on a 32-bit runtime system. They were introduced in ERTS 5.6 and replaced some of the int
arguments in the list above.
The unsigned integer data type ErlDrvUInt64
and the signed integer data type ErlDrvSInt64
are always 64 bits wide. They were introduced in ERTS 5.7.4.
To build the tuple {tcp, Port, [100 | Binary]}
, the following call can be made.
ErlDrvBinary* bin = ...
ErlDrvPort port = ...
ErlDrvTermData spec[] = {
ERL_DRV_ATOM, driver_mk_atom("tcp"),
ERL_DRV_PORT, driver_mk_port(drvport),
ERL_DRV_INT, 100,
ERL_DRV_BINARY, bin, 50, 0,
ERL_DRV_LIST, 2,
ERL_DRV_TUPLE, 3,
};
erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
Here bin
is a driver binary of length at least 50 and drvport
is a port handle. Notice that ERL_DRV_LIST
comes after the elements of the list, likewise ERL_DRV_TUPLE
.
The ERL_DRV_STRING_CONS
term is a way to construct strings. It works differently from how ERL_DRV_STRING
works. ERL_DRV_STRING_CONS
builds a string list in reverse order (as opposed to how ERL_DRV_LIST
works), concatenating the strings added to a list. The tail must be specified before ERL_DRV_STRING_CONS
.
ERL_DRV_STRING
constructs a string, and ends it. (So it is the same as ERL_DRV_NIL
followed by ERL_DRV_STRING_CONS
.)
/* to send [x, "abc", y] to the port: */
ErlDrvTermData spec[] = {
ERL_DRV_ATOM, driver_mk_atom("x"),
ERL_DRV_STRING, (ErlDrvTermData)"abc", 3,
ERL_DRV_ATOM, driver_mk_atom("y"),
ERL_DRV_NIL,
ERL_DRV_LIST, 4
};
erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
/* to send "abc123" to the port: */
ErlDrvTermData spec[] = {
ERL_DRV_NIL, /* with STRING_CONS, the tail comes first */
ERL_DRV_STRING_CONS, (ErlDrvTermData)"123", 3,
ERL_DRV_STRING_CONS, (ErlDrvTermData)"abc", 3,
};
erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
The ERL_DRV_EXT2TERM
term type is used for passing a term encoded with the external format
, that is, a term that has been encoded by erlang:term_to_binary
, erl_interface:ei(3)
, and so on. For example, if binp
is a pointer to an ErlDrvBinary
that contains term {17, 4711}
encoded with the external format
, and you want to wrap it in a two-tuple with the tag my_tag
, that is, {my_tag, {17, 4711}}
, you can do as follows:
ErlDrvTermData spec[] = {
ERL_DRV_ATOM, driver_mk_atom("my_tag"),
ERL_DRV_EXT2TERM, (ErlDrvTermData) binp->orig_bytes, binp->orig_size
ERL_DRV_TUPLE, 2,
};
erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
To build the map #{key1 => 100, key2 => {200, 300}}
, the following call can be made.
ErlDrvPort port = ...
ErlDrvTermData spec[] = {
ERL_DRV_ATOM, driver_mk_atom("key1"),
ERL_DRV_INT, 100,
ERL_DRV_ATOM, driver_mk_atom("key2"),
ERL_DRV_INT, 200,
ERL_DRV_INT, 300,
ERL_DRV_TUPLE, 2,
ERL_DRV_MAP, 2
};
erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
If you want to pass a binary and do not already have the content of the binary in an ErlDrvBinary
, you can benefit from using ERL_DRV_BUF2BINARY
instead of creating an ErlDrvBinary
through driver_alloc_binary
and then pass the binary through ERL_DRV_BINARY
. The runtime system often allocates binaries smarter if ERL_DRV_BUF2BINARY
is used. However, if the content of the binary to pass already resides in an ErlDrvBinary
, it is normally better to pass the binary using ERL_DRV_BINARY
and the ErlDrvBinary
in question.
The ERL_DRV_UINT
, ERL_DRV_BUF2BINARY
, and ERL_DRV_EXT2TERM
term types were introduced in ERTS 5.6.
This function is thread-safe.