From 314702f86c9199957e40edfb73bcdbddb422f9d7 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 24 Feb 2017 19:38:37 +0100 Subject: erts: Add nif ioq --- erts/doc/src/erl_nif.xml | 251 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) (limited to 'erts/doc/src') diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 5a69bed34c..e47bb6a806 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -343,6 +343,81 @@ return term; enif_convert_time_unit() + + I/O Queues + +

The Erlang nif library contains function for easily working + with I/O vectors as used by the unix system call writev. + The I/O Queue is not thread safe, so some other synchronization + mechanism has to be used.

+ + + SysIOVec + + ErlNifIOVec + + enif_ioq_create() + + enif_ioq_destroy() + + enif_ioq_enq_binary() + + enif_ioq_enqv() + + enif_ioq_deq() + + enif_ioq_peek() + + enif_inspect_iovec() + + enif_free_iovec() + +

Typical usage when writing to a file descriptor looks like this:

+ 0) { + /* If the I/O queue contains data we enqueue the iovec and + then peek the data to write out of the queue. */ + if (!enif_ioq_enqv(q, iovec, 0)) + return -3; + + sysiovec = enif_ioq_peek(q, &iovcnt); + } else { + /* If the I/O queue is empty we skip the trip through it. */ + iovcnt = iovec->iovcnt; + sysiovec = iovec->iov; + } + + /* Attempt to write the data */ + n = writev(fd, sysiovec, iovcnt); + saved_errno = errno; + + if (enif_ioq_size(q) == 0) { + /* If the I/O queue was initially empty we enqueue any + remaining data into the queue for writing later. */ + if (n >= 0 && !enif_ioq_enqv(q, iovec, n)) + return -3; + } else { + /* Dequeue any data that was written from the queue. */ + if (n > 0 && !enif_ioq_deq(q, n, NULL)) + return -4; + } + + /* return n, which is either number of bytes written or -1 if + some error happened */ + errno = saved_errno; + return n; +}]]>
Long-running NIFs @@ -837,6 +912,36 @@ typedef enum { + SysIOVec + +

A system I/O vector, as used by writev on + Unix and WSASend on Win32. It is used in + ErlNifIOVec and by + enif_ioq_peek.

+
+ ErlNifIOVec + + +typedef struct { + int iovcnt; + size_t size; + SysIOVec* iov; +} ErlNifIOVec; +

An I/O vector containing iovcnt SysIOVecs + pointing to the data. It is used by + + enif_inspect_iovec and + + enif_ioq_enqv.

+
+ ErlNifIOQueueOpts + + Options to configure a ErlNifIOQueue. + + ERL_NIF_IOQ_NORMAL +

Create a normal I/O Queue

+
+
@@ -1142,6 +1247,31 @@ typedef enum { + + void + enif_free_iovec(ErlNifIOvec* iov) + Free an ErlIOVec + +

Frees an io vector returned from + + enif_inspect_iovec. + This is needed only if a NULL environment is passed to + + enif_inspect_iovec.

+ +
+
+ intenif_get_atom(ErlNifEnv* env, ERL_NIF_TERM term, char* buf, unsigned size, ErlNifCharEncoding encode) @@ -1448,6 +1578,127 @@ typedef enum { + + intenif_inspect_iovec(ErlNifEnv* + env, size_t max_elements, ERL_NIF_TERM iovec_term, ERL_NIF_TERM* tail, + ErlNifIOVec** iovec) + Inspect a list of binaries as an ErlNifIOVec. + +

Fills iovec with the list of binaries provided in + iovec_term. The number of elements handled in the call is + limited to max_elements, and tail is set to the + remainder of the list. Note that the output may be longer than + max_elements on some platforms. +

+

To create a list of binaries from an arbitrary iolist, use + + erlang:iolist_to_iovec/1.

+

When calling this function, iovec should contain a pointer to + NULL or a ErlNifIOVec structure that should be used if + possible. e.g. +

+ +/* Don't use a pre-allocated structure */ +ErlNifIOVec *iovec = NULL; +enif_inspect_iovec(env, max_elements, term, &tail, &iovec); + +/* Use a stack-allocated vector as an optimization for vectors with few elements */ +ErlNifIOVec vec, *iovec = &vec; +enif_inspect_iovec(env, max_elements, term, &tail, &iovec); + +

The contents of the iovec is valid until the called nif + function returns. If the iovec should be valid after the nif + call returns, it is possible to call this function with a + NULL environment. If no environment is given the iovec + owns the data in the vector and it has to be explicitly freed using + enif_free_iovec + .

+

Returns true on success, or false if iovec_term + not an iovec.

+
+
+ + + ErlNifIOQueue * + enif_ioq_create(ErlNifIOQueueOpts opts) + Create a new IO Queue + +

Create a new I/O Queue that can be used to store data. + opts has to be set to ERL_NIF_IOQ_NORMAL. +

+
+
+ + + void + enif_ioq_destroy(ErlNifIOQueue *q) + Destroy an IO Queue and free it's content + +

Destroy the I/O queue and free all of it's contents

+
+
+ + + int + enif_ioq_deq(ErlNifIOQueue *q, size_t count, size_t *size) + Dequeue count bytes from the IO Queue + +

Dequeue count bytes from the I/O queue. + If size is not NULL, the new size of the queue + is placed there.

+

Returns true on success, or false if the I/O does + not contain count bytes. On failure the queue is left un-altered.

+
+
+ + + int + enif_ioq_enq_binary(ErlNifIOQueue *q, ErlNifBinary *bin, size_t skip) + Enqueue the binary into the IO Queue + +

Enqueue the bin into q skipping the first skip bytes.

+

Returns true on success, or false if skip is greater + than the size of bin. Any ownership of the binary data is transferred + to the queue and bin is to be considered read-only for the rest of the NIF + call and then as released.

+
+
+ + + int + enif_ioq_enqv(ErlNifIOQueue *q, ErlNifIOVec *iovec, size_t skip) + Enqueue the iovec into the IO Queue + +

Enqueue the iovec into q skipping the first skip bytes.

+

Returns true on success, or false if skip is greater + than the size of iovec.

+
+
+ + + SysIOVec * + enif_ioq_peek(ErlNifIOQueue *q, int *iovlen) + Peek inside the IO Queue + +

Get the I/O queue as a pointer to an array of SysIOVecs. + It also returns the number of elements in iovlen. + This is the only way to get data out of the queue.

+

Nothing is removed from the queue by this function, that must be done + with enif_ioq_deq.

+

The returned array is suitable to use with the Unix system + call writev.

+
+
+ + + size_t + enif_ioq_size(ErlNifIOQueue *q) + Get the current size of the IO Queue + +

Get the size of q.

+
+
+ int enif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term) -- cgit v1.2.3