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.