summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--lib/uloop.c955
1 files changed, 955 insertions, 0 deletions
diff --git a/lib/uloop.c b/lib/uloop.c
index bccb699..de5a464 100644
--- a/lib/uloop.c
+++ b/lib/uloop.c
@@ -14,6 +14,55 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/**
+ * # OpenWrt uloop event loop
+ *
+ * The `uloop` binding provides functions for integrating with the OpenWrt
+ * {@link https://github.com/openwrt/libubox/blob/master/uloop.h uloop library}.
+ *
+ * Functions can be individually imported and directly accessed using the
+ * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import named import}
+ * syntax:
+ *
+ * ```javascript
+ * import { init, handle, timer, interval, process, signal, task, run } from 'uloop';
+ *
+ * init();
+ *
+ * handle(…);
+ * timer(…);
+ * interval(…);
+ * process(…);
+ * signal(…);
+ * task(…);
+ *
+ * run();
+ * ```
+ *
+ * Alternatively, the module namespace can be imported using a wildcard import
+ * statement:
+ *
+ * ```javascript
+ * import * as uloop from 'uloop';
+ *
+ * uloop.init();
+ *
+ * uloop.handle(…);
+ * uloop.timer(…);
+ * uloop.interval(…);
+ * uloop.process(…);
+ * uloop.signal(…);
+ * uloop.task(…);
+ *
+ * uloop.run();
+ * ```
+ *
+ * Additionally, the uloop binding namespace may also be imported by invoking
+ * the `ucode` interpreter with the `-luloop` switch.
+ *
+ * @module uloop
+ */
+
#include <errno.h>
#include <string.h>
#include <unistd.h>
@@ -92,6 +141,26 @@ uc_uloop_reg_invoke(uc_vm_t *vm, size_t i, uc_value_t *arg)
return true;
}
+/**
+ * Retrieves the last error message.
+ *
+ * This function retrieves the last error message generated by the uloop event loop.
+ * If no error occurred, it returns `null`.
+ *
+ * @function module:uloop#error
+ *
+ * @returns {?string}
+ * Returns the last error message as a string, or `null` if no error occurred.
+ *
+ * @example
+ * // Retrieve the last error message
+ * const errorMessage = uloop.error();
+ *
+ * if (errorMessage)
+ * printf(`Error message: ${errorMessage}\n`);
+ * else
+ * printf("No error occurred\n");
+ */
static uc_value_t *
uc_uloop_error(uc_vm_t *vm, size_t nargs)
{
@@ -106,6 +175,29 @@ uc_uloop_error(uc_vm_t *vm, size_t nargs)
return errmsg;
}
+/**
+ * Initializes the uloop event loop.
+ *
+ * This function initializes the uloop event loop, allowing subsequent
+ * usage of uloop functionalities. It takes no arguments.
+ *
+ * Returns `true` on success.
+ * Returns `null` if an error occurred during initialization.
+ *
+ * @function module:uloop#init
+ *
+ * @returns {?boolean}
+ * Returns `true` on success, `null` on error.
+ *
+ * @example
+ * // Initialize the uloop event loop
+ * const success = uloop.init();
+ *
+ * if (success)
+ * printf("uloop event loop initialized successfully\n");
+ * else
+ * die(`Initialization failure: ${uloop.error()}\n`);
+ */
static uc_value_t *
uc_uloop_init(uc_vm_t *vm, size_t nargs)
{
@@ -117,6 +209,39 @@ uc_uloop_init(uc_vm_t *vm, size_t nargs)
ok_return(ucv_boolean_new(true));
}
+/**
+ * Runs the uloop event loop.
+ *
+ * This function starts running the uloop event loop, allowing it to handle
+ * scheduled events and callbacks. If a timeout value is provided and is
+ * non-negative, the event loop will run for that amount of milliseconds
+ * before returning. If the timeout is omitted or negative, the event loop
+ * runs indefinitely until explicitly stopped.
+ *
+ * @function module:uloop#run
+ *
+ * @param {number} [timeout=-1]
+ * Optional. The timeout value in milliseconds for running the event loop.
+ * Defaults to -1, indicating an indefinite run.
+ *
+ * @returns {?boolean}
+ * Returns `true` on success, `null` on error.
+ *
+ * @example
+ * // Run the uloop event loop indefinitely
+ * const success = uloop.run();
+ * if (success)
+ * printf("uloop event loop ran successfully\n");
+ * else
+ * die(`Error occurred during uloop execution: ${uloop.error()}\n`);
+ *
+ * // Run the uloop event loop for 1000 milliseconds
+ * const success = uloop.run(1000);
+ * if (success)
+ * printf("uloop event loop ran successfully\n");
+ * else
+ * die(`Error occurred during uloop execution: ${uloop.error()}\n`);
+ */
static uc_value_t *
uc_uloop_run(uc_vm_t *vm, size_t nargs)
{
@@ -134,12 +259,50 @@ uc_uloop_run(uc_vm_t *vm, size_t nargs)
ok_return(ucv_int64_new(rv));
}
+/**
+ * Checks if the uloop event loop is currently shutting down.
+ *
+ * This function checks whether the uloop event loop is currently in the process
+ * of shutting down.
+ *
+ * @function module:uloop#cancelling
+ *
+ * @returns {boolean}
+ * Returns `true` if uloop is currently shutting down, `false` otherwise.
+ *
+ * @example
+ * // Check if the uloop event loop is shutting down
+ * const shuttingDown = uloop.cancelling();
+ * if (shuttingDown)
+ * printf("uloop event loop is currently shutting down\n");
+ * else
+ * printf("uloop event loop is not shutting down\n");
+ */
static uc_value_t *
uc_uloop_cancelling(uc_vm_t *vm, size_t nargs)
{
ok_return(ucv_boolean_new(uloop_cancelling()));
}
+/**
+ * Checks if the uloop event loop is currently running.
+ *
+ * This function checks whether the uloop event loop is currently started
+ * and running.
+ *
+ * @function module:uloop#running
+ *
+ * @returns {boolean}
+ * Returns `true` if the event loop is currently running, `false` otherwise.
+ *
+ * @example
+ * // Check if the uloop event loop is running
+ * const isRunning = uloop.running();
+ * if (isRunning)
+ * printf("uloop event loop is currently running\n");
+ * else
+ * printf("uloop event loop is not running\n");
+ */
static uc_value_t *
uc_uloop_running(uc_vm_t *vm, size_t nargs)
{
@@ -153,6 +316,24 @@ uc_uloop_running(uc_vm_t *vm, size_t nargs)
ok_return(ucv_boolean_new(active));
}
+/**
+ * Halts the uloop event loop.
+ *
+ * This function halts the uloop event loop, stopping its execution and
+ * preventing further processing of scheduled events and callbacks.
+ *
+ * Expired timeouts and already queued event callbacks are still run to
+ * completion.
+ *
+ * @function module:uloop#end
+ *
+ * @returns {void}
+ * This function does not return any value.
+ *
+ * @example
+ * // Halt the uloop event loop
+ * uloop.end();
+ */
static uc_value_t *
uc_uloop_end(uc_vm_t *vm, size_t nargs)
{
@@ -161,6 +342,22 @@ uc_uloop_end(uc_vm_t *vm, size_t nargs)
ok_return(NULL);
}
+/**
+ * Stops the uloop event loop and cancels pending timeouts and events.
+ *
+ * This function immediately stops the uloop event loop, cancels all pending
+ * timeouts and events, unregisters all handles, and deallocates associated
+ * resources.
+ *
+ * @function module:uloop#done
+ *
+ * @returns {void}
+ * This function does not return any value.
+ *
+ * @example
+ * // Stop the uloop event loop and clean up resources
+ * uloop.done();
+ */
static uc_value_t *
uc_uloop_done(uc_vm_t *vm, size_t nargs)
{
@@ -170,6 +367,23 @@ uc_uloop_done(uc_vm_t *vm, size_t nargs)
}
+/**
+ * Represents a uloop timer instance as returned by
+ * {@link module:uloop#timer|timer()}.
+ *
+ * @class module:uloop.timer
+ * @hideconstructor
+ *
+ * @see {@link module:uloop#timer|timer()}
+ *
+ * @example
+ *
+ * const timeout = uloop.timer(…);
+ *
+ * timeout.set(…);
+ * timeout.remaining();
+ * timeout.cancel();
+ */
typedef struct {
struct uloop_timeout timeout;
size_t registry_index;
@@ -185,6 +399,32 @@ uc_uloop_timeout_clear(uc_uloop_timer_t **timer)
*timer = NULL;
}
+/**
+ * Rearms the uloop timer with the specified timeout.
+ *
+ * This method rearms the uloop timer with the specified timeout value,
+ * allowing it to trigger after the specified amount of time. If no timeout
+ * value is provided or if the provided value is negative, the timer remains
+ * disabled until rearmed with a positive timeout value.
+ *
+ * @function module:uloop.timer#set
+ *
+ * @param {number} [timeout=-1]
+ * Optional. The timeout value in milliseconds until the timer expires.
+ * Defaults to -1, which disables the timer until rearmed with a positive timeout.
+ *
+ * @returns {?boolean}
+ * Returns `true` on success, `null` on error, such as an invalid timeout argument.
+ *
+ * @example
+ * const timeout = uloop.timer(…);
+ *
+ * // Rearm the uloop timer with a timeout of 1000 milliseconds
+ * timeout.set(1000);
+ *
+ * // Disable the uloop timer
+ * timeout.set();
+ */
static uc_value_t *
uc_uloop_timer_set(uc_vm_t *vm, size_t nargs)
{
@@ -206,6 +446,25 @@ uc_uloop_timer_set(uc_vm_t *vm, size_t nargs)
ok_return(ucv_boolean_new(rv == 0));
}
+/**
+ * Returns the number of milliseconds until the uloop timer expires.
+ *
+ * This method returns the remaining time until the uloop timer expires. If
+ * the timer is not armed (i.e., disabled), it returns -1.
+ *
+ * @function module:uloop.timer#remaining
+ *
+ * @returns {number}
+ * The number of milliseconds until the timer expires, or -1 if the timer is not armed.
+ *
+ * @example
+ * // Get the remaining time until the uloop timer expires (~500ms)
+ * const remainingTime = timer.remaining();
+ * if (remainingTime !== -1)
+ * printf("Time remaining until timer expires: %d ms\n", remainingTime);
+ * else
+ * printf("Timer is not armed\n");
+ */
static uc_value_t *
uc_uloop_timer_remaining(uc_vm_t *vm, size_t nargs)
{
@@ -224,6 +483,20 @@ uc_uloop_timer_remaining(uc_vm_t *vm, size_t nargs)
ok_return(ucv_int64_new(rem));
}
+/**
+ * Cancels the uloop timer, disarming it and removing it from the event loop.
+ *
+ * This method destroys the uloop timer and releases its associated resources.
+ *
+ * @function module:uloop.timer#cancel
+ *
+ * @returns {boolean}
+ * Returns `true` on success.
+ *
+ * @example
+ * // Cancel the uloop timer
+ * timer.cancel();
+ */
static uc_value_t *
uc_uloop_timer_cancel(uc_vm_t *vm, size_t nargs)
{
@@ -248,6 +521,39 @@ uc_uloop_timer_cb(struct uloop_timeout *timeout)
uc_uloop_reg_invoke(timer->vm, timer->registry_index, NULL);
}
+/**
+ * Creates a timer instance for scheduling callbacks.
+ *
+ * This function creates a timer instance for scheduling callbacks to be
+ * executed after a specified timeout duration. It takes an optional timeout
+ * parameter, which defaults to -1, indicating that the timer is initially not
+ * armed and can be enabled later by invoking the `.set(timeout)` method on the
+ * instance.
+ *
+ * A callback function must be provided to be executed when the timer expires.
+ *
+ * @function module:uloop#timer
+ *
+ * @param {number} [timeout=-1]
+ * Optional. The timeout duration in milliseconds. Defaults to -1, indicating
+ * the timer is not initially armed.
+ *
+ * @param {Function} callback
+ * The callback function to be executed when the timer expires.
+ *
+ * @returns {?module:uloop.timer}
+ * Returns a timer instance for scheduling callbacks.
+ * Returns `null` when the timeout or callback arguments are invalid.
+ *
+ * @example
+ * // Create a timer with a callback to be executed after 1000 milliseconds
+ * const myTimer = uloop.timer(1000, () => {
+ * printf("Timer expired!\n");
+ * });
+ *
+ * // Later enable the timer with a timeout of 500 milliseconds
+ * myTimer.set(500);
+ */
static uc_value_t *
uc_uloop_timer(uc_vm_t *vm, size_t nargs)
{
@@ -281,6 +587,24 @@ uc_uloop_timer(uc_vm_t *vm, size_t nargs)
}
+/**
+ * Represents a uloop handle instance as returned by
+ * {@link module:uloop#handle|handle()}.
+ *
+ * @class module:uloop.handle
+ * @hideconstructor
+ *
+ * @see {@link module:uloop#handle|handle()}
+ *
+ * @example
+ *
+ * const handle = uloop.handle(…);
+ *
+ * handle.fileno();
+ * handle.handle();
+ *
+ * handle.delete();
+ */
typedef struct {
struct uloop_fd fd;
size_t registry_index;
@@ -298,6 +622,22 @@ uc_uloop_handle_clear(uc_uloop_handle_t **handle)
*handle = NULL;
}
+/**
+ * Returns the file descriptor number.
+ *
+ * This method returns the file descriptor number associated with the underlying
+ * handle, which might refer to a socket or file instance.
+ *
+ * @function module:uloop.handle#fileno
+ *
+ * @returns {number}
+ * The file descriptor number associated with the handle.
+ *
+ * @example
+ * // Get the file descriptor number associated with the uloop handle
+ * const fd = handle.fileno();
+ * printf("File descriptor number: %d\n", fd);
+ */
static uc_value_t *
uc_uloop_handle_fileno(uc_vm_t *vm, size_t nargs)
{
@@ -309,6 +649,22 @@ uc_uloop_handle_fileno(uc_vm_t *vm, size_t nargs)
ok_return(ucv_int64_new((*handle)->fd.fd));
}
+/**
+ * Returns the underlying file or socket instance.
+ *
+ * This method returns the underlying file or socket instance associated with
+ * the uloop handle.
+ *
+ * @function module:uloop.handle#handle
+ *
+ * @returns {module:fs.file|module:fs.proc|module:socket.socket}
+ * The underlying file or socket instance associated with the handle.
+ *
+ * @example
+ * // Get the associated file or socket instance
+ * const fileOrSocket = handle.handle();
+ * printf("Handle: %s\n", fileOrSocket); // e.g. <socket 0x5> or <fs.proc …>
+ */
static uc_value_t *
uc_uloop_handle_handle(uc_vm_t *vm, size_t nargs)
{
@@ -320,6 +676,23 @@ uc_uloop_handle_handle(uc_vm_t *vm, size_t nargs)
ok_return(ucv_get((*handle)->handle));
}
+/**
+ * Unregisters the uloop handle.
+ *
+ * This method unregisters the uloop handle from the uloop event loop and frees
+ * any associated resources. After calling this method, the handle instance
+ * should no longer be used.
+ *
+ * @function module:uloop.handle#delete
+ *
+ * @returns {void}
+ * This function does not return a value.
+ *
+ * @example
+ * // Unregister the uloop handle and free associated resources
+ * handle.delete();
+ * printf("Handle deleted successfully\n");
+ */
static uc_value_t *
uc_uloop_handle_delete(uc_vm_t *vm, size_t nargs)
{
@@ -392,6 +765,44 @@ get_fd(uc_vm_t *vm, uc_value_t *val)
return fd;
}
+/**
+ * Creates a handle instance for monitoring file descriptor events.
+ *
+ * This function creates a handle instance for monitoring events on a file
+ * descriptor, file, or socket. It takes the file or socket handle, a callback
+ * function to be invoked when the specified IO events occur, and bitwise OR-ed
+ * flags of IO events (`ULOOP_READ`, `ULOOP_WRITE`) that the callback should be
+ * invoked for.
+ *
+ * @function module:uloop#handle
+ *
+ * @param {number|module:fs.file|module:fs.proc|module:socket.socket} handle
+ * The file handle (descriptor number, file or socket instance).
+ *
+ * @param {Function} callback
+ * The callback function to be invoked when the specified IO events occur.
+ *
+ * @param {number} events
+ * Bitwise OR-ed flags of IO events (`ULOOP_READ`, `ULOOP_WRITE`) that the
+ * callback should be invoked for.
+ *
+ * @returns {?module:uloop.handle}
+ * Returns a handle instance for monitoring file descriptor events.
+ * Returns `null` when the handle, callback or signal arguments are invalid.
+ *
+ * @example
+ * // Create a handle for monitoring read events on file descriptor 3
+ * const myHandle = uloop.handle(3, (events) => {
+ * if (events & ULOOP_READ)
+ * printf("Read event occurred!\n");
+ * }, uloop.ULOOP_READ);
+ *
+ * // Check socket for writability
+ * const sock = socket.connect("example.org", 80);
+ * uloop.handle(sock, (events) => {
+ * sock.send("GET / HTTP/1.0\r\n\r\n");
+ * }, uloop.ULOOP_WRITE)
+ */
static uc_value_t *
uc_uloop_handle(uc_vm_t *vm, size_t nargs)
{
@@ -440,6 +851,23 @@ uc_uloop_handle(uc_vm_t *vm, size_t nargs)
}
+/**
+ * Represents a uloop process instance as returned by
+ * {@link module:uloop#process|process()}.
+ *
+ * @class module:uloop.process
+ * @hideconstructor
+ *
+ * @see {@link module:uloop#process|process()}
+ *
+ * @example
+ *
+ * const proc = uloop.process(…);
+ *
+ * proc.pid();
+ *
+ * proc.delete();
+ */
typedef struct {
struct uloop_process process;
size_t registry_index;
@@ -454,6 +882,22 @@ uc_uloop_process_clear(uc_uloop_process_t **process)
*process = NULL;
}
+/**
+ * Returns the process ID.
+ *
+ * This method returns the process ID (PID) of the operating system process
+ * launched by {@link module:uloop#process|process().
+ *
+ * @function module:uloop.process#pid
+ *
+ * @returns {number}
+ * The process ID (PID) of the associated launched process.
+ *
+ * @example
+ * const proc = uloop.process(…);
+ *
+ * printf("Process ID: %d\n", proc.pid());
+ */
static uc_value_t *
uc_uloop_process_pid(uc_vm_t *vm, size_t nargs)
{
@@ -465,6 +909,23 @@ uc_uloop_process_pid(uc_vm_t *vm, size_t nargs)
ok_return(ucv_int64_new((*process)->process.pid));
}
+/**
+ * Unregisters the process from uloop.
+ *
+ * This method unregisters the process from the uloop event loop and releases
+ * any associated resources. However, note that the operating system process
+ * itself is not terminated by this method.
+ *
+ * @function module:uloop.process#delete
+ *
+ * @returns {boolean}
+ * Returns `true` on success.
+ *
+ * @example
+ * const proc = uloop.process(…);
+ *
+ * proc.delete();
+ */
static uc_value_t *
uc_uloop_process_delete(uc_vm_t *vm, size_t nargs)
{
@@ -495,6 +956,39 @@ uc_uloop_process_cb(struct uloop_process *proc, int exitcode)
ucv_put(e);
}
+/**
+ * Creates a process instance for executing external programs.
+ *
+ * This function creates a process instance for executing external programs.
+ * It takes the executable path string, an optional string array as the argument
+ * vector, an optional dictionary describing environment variables, and a
+ * callback function to be invoked when the invoked process ends.
+ *
+ * @function module:uloop#process
+ *
+ * @param {string} executable
+ * The path to the executable program.
+ *
+ * @param {string[]} [args]
+ * Optional. An array of strings representing the arguments passed to the
+ * executable.
+ *
+ * @param {Object<string, *>} [env]
+ * Optional. A dictionary describing environment variables for the process.
+ *
+ * @param {Function} callback
+ * The callback function to be invoked when the invoked process ends.
+ *
+ * @returns {?module:uloop.process}
+ * Returns a process instance for executing external programs.
+ * Returns `null` on error, e.g. due to `exec()` failure or invalid arguments.
+ *
+ * @example
+ * // Create a process instance for executing 'ls' command
+ * const myProcess = uloop.process("/bin/ls", ["-l", "/tmp"], null, (code) => {
+ * printf(`Process exited with code ${code}\n`);
+ * });
+ */
static uc_value_t *
uc_uloop_process(uc_vm_t *vm, size_t nargs)
{
@@ -617,6 +1111,25 @@ writeall(int fd, void *buf, size_t len)
return true;
}
+
+/**
+ * Represents a uloop task communication pipe instance, passed as sole argument
+ * to the task function by {@link module:uloop#task|task()}.
+ *
+ * @class module:uloop.pipe
+ * @hideconstructor
+ *
+ * @see {@link module:uloop#task|task()}
+ *
+ * @example *
+ * const task = uloop.task((pipe) => {
+ * …
+ * pipe.send();
+ * …
+ * pipe.receive();
+ * …
+ * }, …);
+ */
typedef struct {
int input;
int output;
@@ -649,6 +1162,33 @@ uc_uloop_pipe_send_common(uc_vm_t *vm, uc_value_t *msg, int fd)
ok_return(ucv_boolean_new(true));
}
+/**
+ * Sends a serialized message to the task handle.
+ *
+ * This method serializes the provided message and sends it over the task
+ * communication pipe. In the main thread, the message is deserialized and
+ * passed as an argument to the output callback function registered with the
+ * task handle.
+ *
+ * @function module:uloop.pipe#send
+ *
+ * @param {*} msg
+ * The message to be serialized and sent over the pipe. It can be of arbitrary type.
+ *
+ * @returns {?boolean}
+ * Returns `true` on success, indicating that the message was successfully sent
+ * over the pipe. Returns `null` on error, such as when there's no output
+ * callback registered with the task handle.
+ *
+ * @example
+ * // Send a message over the uloop pipe
+ * const success = pipe.send(message);
+ *
+ * if (success)
+ * printf("Message sent successfully\n");
+ * else
+ * die(`Error sending message: ${uloop.error()}\n`);
+ */
static uc_value_t *
uc_uloop_pipe_send(uc_vm_t *vm, size_t nargs)
{
@@ -744,6 +1284,30 @@ read_fail:
err_return(errno);
}
+/**
+ * Reads input from the task handle.
+ *
+ * This method reads input from the task communication pipe. The input callback
+ * function registered with the task handle is invoked to return the input data,
+ * which is then serialized, sent over the pipe, and deserialized by the receive
+ * method.
+ *
+ * @function module:uloop.pipe#receive
+ *
+ * @returns {?*}
+ * Returns the deserialized message read from the task communication pipe.
+ * Returns `null` on error, such as when there's no input callback registered
+ * on the task handle.
+ *
+ * @example
+ * // Read input from the task communication pipe
+ * const message = pipe.receive();
+ *
+ * if (message !== null)
+ * printf("Received message: %s\n", message);
+ * else
+ * die(`Error receiving message: ${uloop.error()}\n`);
+ */
static uc_value_t *
uc_uloop_pipe_receive(uc_vm_t *vm, size_t nargs)
{
@@ -766,6 +1330,27 @@ uc_uloop_pipe_receive(uc_vm_t *vm, size_t nargs)
return rv;
}
+/**
+ * Checks if the task handle provides input.
+ *
+ * This method checks if the task handle has an input callback registered.
+ * It returns a boolean value indicating whether an input callback is present.
+ *
+ * @function module:uloop.pipe#sending
+ *
+ * @returns {boolean}
+ * Returns `true` if the remote task handle has an input callback
+ * registered, otherwise returns `false`.
+ *
+ * @example
+ * // Check if the remote task handle has an input callback
+ * const hasInputCallback = pipe.sending();
+ *
+ * if (hasInputCallback)
+ * printf("Input callback is registered on task handle\n");
+ * else
+ * printf("No input callback on the task handle\n");
+ */
static uc_value_t *
uc_uloop_pipe_sending(uc_vm_t *vm, size_t nargs)
{
@@ -777,6 +1362,27 @@ uc_uloop_pipe_sending(uc_vm_t *vm, size_t nargs)
ok_return(ucv_boolean_new((*pipe)->has_sender));
}
+/**
+ * Checks if the task handle reads output.
+ *
+ * This method checks if the task handle has an output callback registered.
+ * It returns a boolean value indicating whether an output callback is present.
+ *
+ * @function module:uloop.pipe#receiving
+ *
+ * @returns {boolean}
+ * Returns `true` if the task handle has an output callback registered,
+ * otherwise returns `false`.
+ *
+ * @example
+ * // Check if the task handle has an output callback
+ * const hasOutputCallback = pipe.receiving();
+ *
+ * if (hasOutputCallback)
+ * printf("Output callback is registered on task handle\n");
+ * else
+ * printf("No output callback on the task handle\n");
+ */
static uc_value_t *
uc_uloop_pipe_receiving(uc_vm_t *vm, size_t nargs)
{
@@ -789,6 +1395,24 @@ uc_uloop_pipe_receiving(uc_vm_t *vm, size_t nargs)
}
+/**
+ * Represents a uloop task instance as returned by
+ * {@link module:uloop#task|task()}.
+ *
+ * @class module:uloop.task
+ * @hideconstructor
+ *
+ * @see {@link module:uloop#task|task()}
+ *
+ * @example
+ *
+ * const task = uloop.task(…);
+ *
+ * task.pid();
+ * task.finished();
+ *
+ * task.kill();
+ */
typedef struct {
struct uloop_process process;
struct uloop_fd output;
@@ -830,6 +1454,22 @@ uc_uloop_task_clear(uc_uloop_task_t **task)
*task = NULL;
}
+/**
+ * Returns the process ID.
+ *
+ * This method returns the process ID (PID) of the underlying forked process
+ * launched by {@link module:uloop#task|task().
+ *
+ * @function module:uloop.task#pid
+ *
+ * @returns {number}
+ * The process ID (PID) of the forked task process.
+ *
+ * @example
+ * const task = uloop.task(…);
+ *
+ * printf("Process ID: %d\n", task.pid());
+ */
static uc_value_t *
uc_uloop_task_pid(uc_vm_t *vm, size_t nargs)
{
@@ -844,6 +1484,29 @@ uc_uloop_task_pid(uc_vm_t *vm, size_t nargs)
ok_return(ucv_int64_new((*task)->process.pid));
}
+/**
+ * Terminates the task process.
+ *
+ * This method terminates the task process. It sends a termination signal to
+ * the task process, causing it to exit. Returns `true` on success, indicating
+ * that the task process was successfully terminated. Returns `null` on error,
+ * such as when the task process has already terminated.
+ *
+ * @function module:uloop.task#kill
+ *
+ * @returns {?boolean}
+ * Returns `true` when the task process was successfully terminated.
+ * Returns `null` on error, such as when the process has already terminated.
+ *
+ * @example
+ * // Terminate the task process
+ * const success = task.kill();
+ *
+ * if (success)
+ * printf("Task process terminated successfully\n");
+ * else
+ * die(`Error terminating task process: ${uloop.error()}\n`);
+ */
static uc_value_t *
uc_uloop_task_kill(uc_vm_t *vm, size_t nargs)
{
@@ -864,6 +1527,28 @@ uc_uloop_task_kill(uc_vm_t *vm, size_t nargs)
ok_return(ucv_boolean_new(true));
}
+/**
+ * Checks if the task ran to completion.
+ *
+ * This method checks if the task function has already run to completion.
+ * It returns a boolean value indicating whether the task function has finished
+ * executing.
+ *
+ * @function module:uloop.task#finished
+ *
+ * @returns {boolean}
+ * Returns `true` if the task function has already run to completion, otherwise
+ * returns `false`.
+ *
+ * @example
+ * // Check if the task function has finished executing
+ * const isFinished = task.finished();
+ *
+ * if (isFinished)
+ * printf("Task function has finished executing\n");
+ * else
+ * printf("Task function is still running\n");
+ */
static uc_value_t *
uc_uloop_task_finished(uc_vm_t *vm, size_t nargs)
{
@@ -948,6 +1633,52 @@ uc_uloop_task_process_cb(struct uloop_process *proc, int exitcode)
uc_uloop_task_output_cb(&task->output, ULOOP_READ);
}
+/**
+ * Creates a task instance for executing background tasks.
+ *
+ * This function creates a task instance for executing background tasks.
+ * It takes the task function to be invoked as a background process,
+ * an optional output callback function to be invoked when output is received
+ * from the task, and an optional input callback function to be invoked
+ * when input is required by the task.
+ *
+ * @function module:uloop#task
+ *
+ * @param {Function} taskFunction
+ * The task function to be invoked as a background process.
+ *
+ * @param {Function} [outputCallback]
+ * Optional. The output callback function to be invoked when output is received
+ * from the task. It is invoked with the output data as the argument.
+ *
+ * @param {Function} [inputCallback]
+ * Optional. The input callback function to be invoked when input is required
+ * by the task. It is invoked with a function to send input to the task
+ * as the argument.
+ *
+ * @returns {?module:uloop.task}
+ * Returns a task instance for executing background tasks.
+ * Returns `null` on error, e.g. due to fork failure or invalid arguments.
+ *
+ * @example
+ * // Create a task instance for executing a background task
+ * const myTask = uloop.task(
+ * (pipe) => {
+ * // Task logic
+ * pipe.send("Hello from the task\n");
+ * const input = pipe.receive();
+ * printf(`Received input from main thread: ${input}\n`);
+ * },
+ * (output) => {
+ * // Output callback, invoked when task function calls pipe.send()
+ * printf(`Received output from task: ${output}\n`);
+ * },
+ * () => {
+ * // Input callback, invoked when task function calls pipe.receive()
+ * return "Input from main thread\n";
+ * }
+ * );
+ */
static uc_value_t *
uc_uloop_task(uc_vm_t *vm, size_t nargs)
{
@@ -1052,6 +1783,24 @@ uc_uloop_task(uc_vm_t *vm, size_t nargs)
}
+/**
+ * Represents a uloop interval timer instance as returned by
+ * {@link module:uloop#interval|interval()}.
+ *
+ * @class module:uloop.interval
+ * @hideconstructor
+ *
+ * @see {@link module:uloop#interval|interval()}
+ *
+ * @example
+ *
+ * const intv = uloop.interval(…);
+ *
+ * intv.set(…);
+ * intv.remaining();
+ * intv.expirations();
+ * intv.cancel();
+ */
#ifdef HAVE_ULOOP_INTERVAL
typedef struct {
struct uloop_interval interval;
@@ -1068,6 +1817,41 @@ uc_uloop_interval_clear(uc_uloop_interval_t **interval)
*interval = NULL;
}
+/**
+ * Rearms the uloop interval timer with the specified interval.
+ *
+ * This method rearms the interval timer with the specified interval value,
+ * allowing it to trigger repeatedly after the specified amount of time. If no
+ * interval value is provided or if the provided value is negative, the interval
+ * remains disabled until rearmed with a positive interval value.
+ *
+ * @function module:uloop.interval#set
+ *
+ * @param {number} [interval=-1]
+ * Optional. The interval value in milliseconds specifying when the interval
+ * triggers again. Defaults to -1, which disables the interval until rearmed
+ * with a positive interval value.
+ *
+ * @returns {?boolean}
+ * Returns `true` on success, `null` on error, such as an invalid interval argument.
+ *
+ * @example
+ * // Rearm the uloop interval with a interval of 1000 milliseconds
+ * const success = interval.set(1000);
+ *
+ * if (success)
+ * printf("Interval rearmed successfully\n");
+ * else
+ * printf("Error occurred while rearming interval: ${uloop.error()}\n");
+ *
+ * // Disable the uloop interval
+ * const success = interval.set();
+ *
+ * if (success)
+ * printf("Interval disabled successfully\n");
+ * else
+ * printf("Error occurred while disabling interval: ${uloop.error()}\n");
+ */
static uc_value_t *
uc_uloop_interval_set(uc_vm_t *vm, size_t nargs)
{
@@ -1089,6 +1873,28 @@ uc_uloop_interval_set(uc_vm_t *vm, size_t nargs)
ok_return(ucv_boolean_new(rv == 0));
}
+/**
+ * Returns the milliseconds until the next expiration.
+ *
+ * This method returns the remaining time until the uloop interval expires
+ * and triggers again. If the interval is not armed (i.e., disabled),
+ * it returns -1.
+ *
+ * @function module:uloop.interval#remaining
+ *
+ * @returns {number}
+ * The milliseconds until the next expiration of the uloop interval, or -1 if
+ * the interval is not armed.
+ *
+ * @example
+ * // Get the milliseconds until the next expiration of the uloop interval
+ * const remainingTime = interval.remaining();
+ *
+ * if (remainingTime !== -1)
+ * printf("Milliseconds until next expiration: %d\n", remainingTime);
+ * else
+ * printf("Interval is not armed\n");
+ */
static uc_value_t *
uc_uloop_interval_remaining(uc_vm_t *vm, size_t nargs)
{
@@ -1100,6 +1906,22 @@ uc_uloop_interval_remaining(uc_vm_t *vm, size_t nargs)
ok_return(ucv_int64_new(uloop_interval_remaining(&(*interval)->interval)));
}
+/**
+ * Returns number of times the interval timer fired.
+ *
+ * This method returns the number of times the uloop interval timer has expired
+ * (fired) since it was instantiated.
+ *
+ * @function module:uloop.interval#expirations
+ *
+ * @returns {number}
+ * The number of times the uloop interval timer has expired (fired).
+ *
+ * @example
+ * // Get the number of times the uloop interval timer has expired
+ * const expirations = interval.expirations();
+ * printf("Number of expirations: %d\n", expirations);
+ */
static uc_value_t *
uc_uloop_interval_expirations(uc_vm_t *vm, size_t nargs)
{
@@ -1111,6 +1933,21 @@ uc_uloop_interval_expirations(uc_vm_t *vm, size_t nargs)
ok_return(ucv_int64_new((*interval)->interval.expirations));
}
+/**
+ * Cancels the uloop interval.
+ *
+ * This method cancels the uloop interval, disarming it and removing it from the
+ * event loop. Associated resources are released.
+ *
+ * @function module:uloop.interval#cancel
+ *
+ * @returns {boolean}
+ * Returns `true` on success.
+ *
+ * @example
+ * // Cancel the uloop interval
+ * interval.cancel();
+ */
static uc_value_t *
uc_uloop_interval_cancel(uc_vm_t *vm, size_t nargs)
{
@@ -1135,6 +1972,37 @@ uc_uloop_interval_cb(struct uloop_interval *uintv)
uc_uloop_reg_invoke(interval->vm, interval->registry_index, NULL);
}
+/**
+ * Creates an interval instance for scheduling repeated callbacks.
+ *
+ * This function creates an interval instance for scheduling repeated callbacks
+ * to be executed at regular intervals. It takes an optional timeout parameter,
+ * which defaults to -1, indicating that the interval is initially not armed
+ * and can be armed later with the `.set(timeout)` method. A callback function
+ * must be provided to be executed when the interval expires.
+ *
+ * @function module:uloop#interval
+ *
+ * @param {number} [timeout=-1]
+ * Optional. The interval duration in milliseconds. Defaults to -1, indicating
+ * the interval is not initially armed.
+ *
+ * @param {Function} callback
+ * The callback function to be executed when the interval expires.
+ *
+ * @returns {?module:uloop.interval}
+ * Returns an interval instance for scheduling repeated callbacks.
+ * Returns `null` when the timeout or callback arguments are invalid.
+ *
+ * @example
+ * // Create an interval with a callback to be executed every 1000 milliseconds
+ * const myInterval = uloop.interval(1000, () => {
+ * printf("Interval callback executed!\n");
+ * });
+ *
+ * // Later arm the interval to start executing the callback every 500 milliseconds
+ * myInterval.set(500);
+ */
static uc_value_t *
uc_uloop_interval(uc_vm_t *vm, size_t nargs)
{
@@ -1168,6 +2036,23 @@ uc_uloop_interval(uc_vm_t *vm, size_t nargs)
}
#endif
+
+/**
+ * Represents a uloop signal Unix process signal handler as returned by
+ * {@link module:uloop#signal|signal()}.
+ *
+ * @class module:uloop.signal
+ * @hideconstructor
+ *
+ * @see {@link module:uloop#signal|signal()}
+ *
+ * @example
+ *
+ * const sighandler = uloop.signal(…);
+ *
+ * sighandler.signo();
+ * sighandler.delete();
+ */
#ifdef HAVE_ULOOP_SIGNAL
typedef struct {
struct uloop_signal signal;
@@ -1184,6 +2069,22 @@ uc_uloop_signal_clear(uc_uloop_signal_t **signal)
*signal = NULL;
}
+/**
+ * Returns the associated signal number.
+ *
+ * This method returns the signal number that this uloop signal handler is
+ * configured to respond to.
+ *
+ * @function module:uloop.signal#signo
+ *
+ * @returns {number}
+ * The signal number that this handler is responding to.
+ *
+ * @example
+ * // Get the signal number that the uloop signal handler is responding to
+ * const sighandler = uloop.signal("SIGINT", () => printf("Cought INT\n"));
+ * printf("Signal number: %d\n", sighandler.signo());
+ */
static uc_value_t *
uc_uloop_signal_signo(uc_vm_t *vm, size_t nargs)
{
@@ -1195,6 +2096,22 @@ uc_uloop_signal_signo(uc_vm_t *vm, size_t nargs)
ok_return(ucv_int64_new((*signal)->signal.signo));
}
+/**
+ * Uninstalls the signal handler.
+ *
+ * This method uninstalls the signal handler, restoring the previous or default
+ * handler for the signal, and releasing any associated resources.
+ *
+ * @function module:uloop.signal#delete
+ *
+ * @returns {boolean}
+ * Returns `true` on success.
+ *
+ * @example
+ * // Uninstall the signal handler and restore the previous/default handler
+ * const sighandler = uloop.signal(…);
+ * sighandler.delete();
+ */
static uc_value_t *
uc_uloop_signal_delete(uc_vm_t *vm, size_t nargs)
{
@@ -1252,6 +2169,32 @@ parse_signo(uc_value_t *sigspec)
return signo;
}
+/**
+ * Creates a signal instance for handling Unix signals.
+ *
+ * This function creates a signal instance for handling Unix signals.
+ * It takes the signal name string (with or without "SIG" prefix) or signal
+ * number, and a callback function to be invoked when the specified Unix signal
+ * is caught.
+ *
+ * @function module:uloop#signal
+ *
+ * @param {string|number} signal
+ * The signal name string (with or without "SIG" prefix) or signal number.
+ *
+ * @param {Function} callback
+ * The callback function to be invoked when the specified Unix signal is caught.
+ *
+ * @returns {?module:uloop.signal}
+ * Returns a signal instance representing the installed signal handler.
+ * Returns `null` when the signal or callback arguments are invalid.
+ *
+ * @example
+ * // Create a signal instance for handling SIGINT
+ * const mySignal = uloop.signal("SIGINT", () => {
+ * printf("SIGINT caught!\n");
+ * });
+ */
static uc_value_t *
uc_uloop_signal(uc_vm_t *vm, size_t nargs)
{
@@ -1457,6 +2400,18 @@ void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
#define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x))
+ /**
+ * @typedef
+ * @name Event Mode Constants
+ * @description
+ * The `ULOOP_*` constants are passed as bitwise OR-ed number to the
+ * {@link module:uloop.handle#handle|handle()} function to specify the IO
+ * events that should be monitored on the given handle.
+ * @property {number} ULOOP_READ - File or socket is readable.
+ * @property {number} ULOOP_WRITE - File or socket is writable.
+ * @property {number} ULOOP_EDGE_TRIGGER - Enable edge-triggered event mode.
+ * @property {number} ULOOP_BLOCKING - Do not make descriptor non-blocking.
+ */
ADD_CONST(ULOOP_READ);
ADD_CONST(ULOOP_WRITE);
ADD_CONST(ULOOP_EDGE_TRIGGER);