diff options
Diffstat (limited to 'lib/uloop.c')
-rw-r--r-- | lib/uloop.c | 955 |
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); |