| <!DOCTYPE html><html><head><meta charset="utf-8" /><meta content="IE=edge" http-equiv="X-UA-Compatible" /><meta content="width=device-width, initial-scale=1, maximum-scale=2.0, user-scalable=yes, minimal-ui=yes" name="viewport" /><title>facil.io - 0.7.x Core Library Documentation</title><meta content="facil.io - 0.7.x Core Library Documentation" name="description" /><link href="https://fonts.googleapis.com/css?family=Montserrat|Quicksand|Karla" rel="stylesheet" type="text/css" /><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script><link href="/assets/styles/main.css" rel="stylesheet" type="text/css" /><script type="application/ld+json">{"@context":"http://schema.org","@type":"WebSite","url":"http://facil.io","name":"facil.io","description":"facil.io - a light web application framework in C, with support for HTTP, WebSockets and Pub/Sub out of the box.","keywords":"C, web, framework, websockets, websocket, realtime, real-time, easy","image":"http://facil.io/website/logo/facil-io.svg","author":[{"@type":"Person","name":"Bo (Myst)","url":"http://stackoverflow.com/users/4025095/myst","email":"bo(at)facil.io"}],"sourceOrganization":{"@context":"http://schema.org","@type":"Organization","name":"Plezi","url":"http://facil.io","description":"facil.io - a light web application framework in C, with support for HTTP, WebSockets and Pub/Sub out of the box.","logo":"http://facil.io/website/logo/facil-io.svg","image":"http://facil.io/website/logo/facil-io.svg","email":"bo(at)facil.io","member":[{"@type":"Person","name":"Bo (Myst)","url":"http://stackoverflow.com/users/4025095/myst","email":"bo(at)facil.io"}]}}</script><link href="/assets/logo/facil-io-logo.svg" rel="icon" sizes="350x350" type="image/svg" /><link href="/assets/logo/facil-io-logo.png" rel="icon" sizes="350x350" type="image/png" /><link href="/assets/logo/facil-io-logo.svg" rel="shortcut icon" sizes="350x350" type="image/svg" /><link href="/assets/logo/facil-io-logo.png" rel="shortcut icon" sizes="350x350" type="image/png" /><link href="/assets/logo/facil-io-logo.svg" rel="apple-touch-icon" sizes="350x350" type="image/svg" /><link href="/assets/logo/facil-io-logo.png" rel="apple-touch-icon" sizes="350x350" type="image/png" /><link href="/assets/logo/facil-io-logo.svg" rel="fluid-icon" sizes="350x350" type="image/svg" /><link href="/assets/logo/facil-io-logo.png" rel="fluid-icon" sizes="350x350" type="image/png" /><link href="/manifest.json" rel="manifest" /><meta content="facil.io" name="apple-mobile-web-app-title" /><meta content="facil.io - the C Web Application Framework" name="application-name" /><meta content="#b91d47" name="msapplication-TileColor" /><meta content="/mstile-144x144.png" name="msapplication-TileImage" /><meta content="#ffffff" name="theme-color" /></head><body><a href="/" id="logo"></a><input id="show_nav" type="checkbox" /><nav id="top_nav"><ul><li><a href="/0.7.x/index">Latest Docs</a></li><li><a href="https://github.com/boazsegev/facil.io" target="_blank">Source Code</a></li><li><a href="javascript: change_themes();" id="theme">Night Theme</a></li></ul></nav><input id="show_sidebar" type="checkbox" /><nav id="side_bar"><h2 id="version-0-7-x"><a href="/0.7.x/index">Version 0.7.x</a></h2> |
| |
| <h3 id="core-library"><a href="/0.7.x/fio">Core Library</a></h3> |
| |
| <ul> |
| <li><a href="/0.7.x/fio#connection-protocol-management">Protocol Management</a></li> |
| <li><a href="/0.7.x/fio#running-facil-io">Running the IO reactor</a></li> |
| <li><a href="/0.7.x/fio#socket-connection-functions">Connection Functions</a></li> |
| <li><a href="/0.7.x/fio#event-task-scheduling">Event / Task Scheduling</a></li> |
| <li><a href="/0.7.x/fio#pub-sub-services">Pub/Sub Services</a></li> |
| <li><a href="/0.7.x/fio#the-custom-memory-allocator">Memory Allocation</a></li> |
| <li><a href="/0.7.x/fio#general-helpers">General Helpers</a></li> |
| <li><a href="/0.7.x/fio#linked-lists">Linked Lists</a></li> |
| <li><a href="/0.7.x/fio#string-helpers">String Helpers</a></li> |
| <li><a href="/0.7.x/fio#dynamic-arrays">Dynamic Arrays</a></li> |
| <li><a href="/0.7.x/fio#hash-maps-sets">Hash Maps / Sets</a></li> |
| <li><a href="/0.7.x/fio#version-and-compilation-related-macros">Compilation Macros</a></li> |
| <li><a href="/0.7.x/fio#weak-functions">Weak Functions</a></li> |
| </ul> |
| |
| <h3 id="extensions"><a href="/0.7.x/extensions">Extensions</a></h3> |
| |
| <!-- * [TLS (SSL)](/0.7.x/fio_tls) --> |
| |
| <ul> |
| <li><a href="/0.7.x/http">HTTP / WebSockets</a></li> |
| <li><a href="/0.7.x/redis">Redis (client)</a></li> |
| <li><a href="/0.7.x/fio_cli">CLI (command line)</a></li> |
| </ul> |
| |
| <h3 id="the-fiobj-types"><a href="/0.7.x/fiobj">The FIOBJ types</a></h3> |
| |
| <ul> |
| <li><a href="/0.7.x/fiobj_core">Core Functions</a></li> |
| <li><a href="/0.7.x/fiobj_primitives">Primitives</a></li> |
| <li><a href="/0.7.x/fiobj_numbers">Numbers</a></li> |
| <li><a href="/0.7.x/fiobj_str">Strings</a></li> |
| <li><a href="/0.7.x/fiobj_ary">Array</a></li> |
| <li><a href="/0.7.x/fiobj_hash">HashMap</a></li> |
| <li><a href="/0.7.x/fiobj_data">Data Streams</a></li> |
| <li><a href="/0.7.x/fiobj_json">JSON</a></li> |
| <li><a href="/0.7.x/fiobj_mustache">Mustache</a></li> |
| </ul> |
| |
| <h3 id="miscellaneous">Miscellaneous</h3> |
| |
| <ul> |
| <li><a href="/0.7.x/riskyhash">Risk Hash</a></li> |
| </ul> |
| </nav><div id="md_container"><div class='toc'><ul> |
| <li> |
| <a href="#facil-io-0-7-x-core-library-documentation">facil.io - 0.7.x Core Library Documentation</a> |
| <ul> |
| <li> |
| <a href="#connection-protocol-management">Connection (Protocol) Management</a> |
| <ul> |
| <li> |
| <a href="#the-fio_protocol_s-structure">The <code>fio_protocol_s</code> structure</a> |
| <ul> |
| <li> |
| <a href="#fio_protocol_s-on_data"><code>fio_protocol_s->on_data</code></a> |
| </li> |
| <li> |
| <a href="#fio_protocol_s-on_ready"><code>fio_protocol_s->on_ready</code></a> |
| </li> |
| <li> |
| <a href="#fio_protocol_s-on_shutdown"><code>fio_protocol_s->on_shutdown</code></a> |
| </li> |
| <li> |
| <a href="#fio_protocol_s-on_close"><code>fio_protocol_s->on_close</code></a> |
| </li> |
| <li> |
| <a href="#fio_protocol_s-ping"><code>fio_protocol_s->ping</code></a> |
| </li> |
| <li> |
| <a href="#fio_protocol_s-rsv"><code>fio_protocol_s->rsv</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#attaching-detaching-protocol-objects">Attaching / Detaching Protocol Objects</a> |
| <ul> |
| <li> |
| <a href="#fio_attach"><code>fio_attach</code></a> |
| </li> |
| <li> |
| <a href="#fio_attach_fd"><code>fio_attach_fd</code></a> |
| </li> |
| <li> |
| <a href="#fio_capa"><code>fio_capa</code></a> |
| </li> |
| <li> |
| <a href="#fio_timeout_set"><code>fio_timeout_set</code></a> |
| </li> |
| <li> |
| <a href="#fio_timeout_get"><code>fio_timeout_get</code></a> |
| </li> |
| <li> |
| <a href="#fio_touch"><code>fio_touch</code></a> |
| </li> |
| <li> |
| <a href="#fio_force_event"><code>fio_force_event</code></a> |
| </li> |
| <li> |
| <a href="#fio_suspend"><code>fio_suspend</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#listening-to-incoming-connections">Listening to incoming connections</a> |
| <ul> |
| <li> |
| <a href="#fio_listen"><code>fio_listen</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#connecting-to-remote-servers-as-a-client">Connecting to remote servers as a client</a> |
| <ul> |
| <li> |
| <a href="#fio_connect"><code>fio_connect</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#url-parsing">URL Parsing</a> |
| <ul> |
| <li> |
| <a href="#fio_url_parse"><code>fio_url_parse</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#manual-protocol-locking">Manual Protocol Locking</a> |
| <ul> |
| <li> |
| <a href="#fio_protocol_try_lock"><code>fio_protocol_try_lock</code></a> |
| </li> |
| <li> |
| <a href="#fio_protocol_unlock"><code>fio_protocol_unlock</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#running-facil-io">Running facil.io</a> |
| <ul> |
| <li> |
| <ul> |
| <li> |
| <a href="#fio_start"><code>fio_start</code></a> |
| </li> |
| <li> |
| <a href="#fio_stop"><code>fio_stop</code></a> |
| </li> |
| <li> |
| <a href="#fio_expected_concurrency"><code>fio_expected_concurrency</code></a> |
| </li> |
| <li> |
| <a href="#fio_is_running"><code>fio_is_running</code></a> |
| </li> |
| <li> |
| <a href="#fio_is_worker"><code>fio_is_worker</code></a> |
| </li> |
| <li> |
| <a href="#fio_parent_pid"><code>fio_parent_pid</code></a> |
| </li> |
| <li> |
| <a href="#fio_reap_children"><code>fio_reap_children</code></a> |
| </li> |
| <li> |
| <a href="#fio_signal_handler_reset"><code>fio_signal_handler_reset</code></a> |
| </li> |
| <li> |
| <a href="#fio_last_tick"><code>fio_last_tick</code></a> |
| </li> |
| <li> |
| <a href="#fio_engine"><code>fio_engine</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#socket-connection-functions">Socket / Connection Functions</a> |
| <ul> |
| <li> |
| <a href="#creating-closing-and-testing-sockets">Creating, closing and testing sockets</a> |
| <ul> |
| <li> |
| <a href="#fio_socket"><code>fio_socket</code></a> |
| </li> |
| <li> |
| <a href="#fio_accept"><code>fio_accept</code></a> |
| </li> |
| <li> |
| <a href="#fio_is_valid"><code>fio_is_valid</code></a> |
| </li> |
| <li> |
| <a href="#fio_is_closed"><code>fio_is_closed</code></a> |
| </li> |
| <li> |
| <a href="#fio_close"><code>fio_close</code></a> |
| </li> |
| <li> |
| <a href="#fio_force_close"><code>fio_force_close</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_non_block"><code>fio_set_non_block</code></a> |
| </li> |
| <li> |
| <a href="#fio_peer_addr"><code>fio_peer_addr</code></a> |
| </li> |
| <li> |
| <a href="#the-fio_str_info_s-return-value">The <code>fio_str_info_s</code> return value</a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#reading-writing">Reading / Writing</a> |
| <ul> |
| <li> |
| <a href="#fio_read"><code>fio_read</code></a> |
| </li> |
| <li> |
| <a href="#fio_write2"><code>fio_write2</code></a> |
| </li> |
| <li> |
| <a href="#fio_write"><code>fio_write</code></a> |
| </li> |
| <li> |
| <a href="#fio_sendfile"><code>fio_sendfile</code></a> |
| </li> |
| <li> |
| <a href="#fio_pending"><code>fio_pending</code></a> |
| </li> |
| <li> |
| <a href="#fio_flush"><code>fio_flush</code></a> |
| </li> |
| <li> |
| <a href="#fio_flush_strong"><code>fio_flush_strong</code></a> |
| </li> |
| <li> |
| <a href="#fio_flush_all"><code>fio_flush_all</code></a> |
| </li> |
| <li> |
| <a href="#fio_uuid2fd"><code>fio_uuid2fd</code></a> |
| </li> |
| <li> |
| <a href="#fio_fd2uuid"><code>fio_fd2uuid</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#connection-object-links">Connection Object Links</a> |
| <ul> |
| <li> |
| <a href="#fio_uuid_link"><code>fio_uuid_link</code></a> |
| </li> |
| <li> |
| <a href="#fio_uuid_unlink"><code>fio_uuid_unlink</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#lower-level-read-write-close-hooks">Lower-Level: Read / Write / Close Hooks</a> |
| <ul> |
| <li> |
| <a href="#fio_rw_hook_set"><code>fio_rw_hook_set</code></a> |
| </li> |
| <li> |
| <a href="#fio_rw_hook_replace_unsafe"><code>fio_rw_hook_replace_unsafe</code></a> |
| </li> |
| <li> |
| <a href="#fio_default_rw_hooks"><code>FIO_DEFAULT_RW_HOOKS</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#event-task-scheduling">Event / Task scheduling</a> |
| <ul> |
| <li> |
| <a href="#the-task-queue-functions">The Task Queue Functions</a> |
| <ul> |
| <li> |
| <a href="#fio_defer"><code>fio_defer</code></a> |
| </li> |
| <li> |
| <a href="#fio_defer_perform"><code>fio_defer_perform</code></a> |
| </li> |
| <li> |
| <a href="#fio_defer_has_queue"><code>fio_defer_has_queue</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#timer-functions">Timer Functions</a> |
| <ul> |
| <li> |
| <a href="#fio_run_every"><code>fio_run_every</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#connection-task-scheduling">Connection task scheduling</a> |
| <ul> |
| <li> |
| <a href="#fio_defer_io_task"><code>fio_defer_io_task</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#startup-state-tasks-fork-start-up-idle-etc">Startup / State Tasks (fork, start up, idle, etc')</a> |
| <ul> |
| <li> |
| <a href="#callback_type_e-state-callback-timing-type"><code>callback_type_e</code>- State callback timing type</a> |
| </li> |
| <li> |
| <a href="#fio_state_callback_add"><code>fio_state_callback_add</code></a> |
| </li> |
| <li> |
| <a href="#fio_state_callback_remove"><code>fio_state_callback_remove</code></a> |
| </li> |
| <li> |
| <a href="#fio_state_callback_force"><code>fio_state_callback_force</code></a> |
| </li> |
| <li> |
| <a href="#fio_state_callback_clear"><code>fio_state_callback_clear</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#pub-sub-services">Pub/Sub Services</a> |
| <ul> |
| <li> |
| <a href="#subscription-control">Subscription Control</a> |
| <ul> |
| <li> |
| <a href="#fio_subscribe"><code>fio_subscribe</code></a> |
| </li> |
| <li> |
| <a href="#fio_subscription_channel"><code>fio_subscription_channel</code></a> |
| </li> |
| <li> |
| <a href="#fio_message_defer"><code>fio_message_defer</code></a> |
| </li> |
| <li> |
| <a href="#fio_unsubscribe"><code>fio_unsubscribe</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#publishing-messages">Publishing messages</a> |
| <ul> |
| <li> |
| <a href="#fio_publish"><code>fio_publish</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#pub-sub-message-middleware-meta-data">Pub/Sub Message MiddleWare Meta-Data</a> |
| <ul> |
| <li> |
| <a href="#fio_message_metadata"><code>fio_message_metadata</code></a> |
| </li> |
| <li> |
| <a href="#fio_message_metadata_callback_set"><code>fio_message_metadata_callback_set</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#external-pub-sub-services">External Pub/Sub Services</a> |
| <ul> |
| <li> |
| <a href="#fio_pubsub_attach"><code>fio_pubsub_attach</code></a> |
| </li> |
| <li> |
| <a href="#fio_pubsub_detach"><code>fio_pubsub_detach</code></a> |
| </li> |
| <li> |
| <a href="#fio_pubsub_reattach"><code>fio_pubsub_reattach</code></a> |
| </li> |
| <li> |
| <a href="#fio_pubsub_is_attached"><code>fio_pubsub_is_attached</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#the-custom-memory-allocator">The Custom Memory Allocator</a> |
| <ul> |
| <li> |
| <a href="#memory-allocator-overview">Memory Allocator Overview</a> |
| </li> |
| <li> |
| <a href="#the-memory-allocator-s-api">The Memory Allocator's API</a> |
| <ul> |
| <li> |
| <a href="#fio_malloc"><code>fio_malloc</code></a> |
| </li> |
| <li> |
| <a href="#fio_calloc"><code>fio_calloc</code></a> |
| </li> |
| <li> |
| <a href="#fio_free"><code>fio_free</code></a> |
| </li> |
| <li> |
| <a href="#fio_realloc"><code>fio_realloc</code></a> |
| </li> |
| <li> |
| <a href="#fio_realloc2"><code>fio_realloc2</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#linked-lists">Linked Lists</a> |
| <ul> |
| <li> |
| <a href="#independent-linked-list-api">Independent Linked List API</a> |
| <ul> |
| <li> |
| <a href="#fio_ls_init"><code>FIO_LS_INIT</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_push"><code>fio_ls_push</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_unshift"><code>fio_ls_unshift</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_pop"><code>fio_ls_pop</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_shift"><code>fio_ls_shift</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_remove"><code>fio_ls_remove</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_is_empty"><code>fio_ls_is_empty</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_any"><code>fio_ls_any</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_for"><code>FIO_LS_FOR</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#embedded-linked-list-api">Embedded Linked List API</a> |
| <ul> |
| <li> |
| <a href="#fio_ls_embd_push"><code>fio_ls_embd_push</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_embd_unshift"><code>fio_ls_embd_unshift</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_embd_pop"><code>fio_ls_embd_pop</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_embd_shift"><code>fio_ls_embd_shift</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_embd_remove"><code>fio_ls_embd_remove</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_embd_is_empty"><code>fio_ls_embd_is_empty</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_embd_any"><code>fio_ls_embd_any</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_embd_for"><code>FIO_LS_EMBD_FOR</code></a> |
| </li> |
| <li> |
| <a href="#fio_ls_embd_obj"><code>FIO_LS_EMBD_OBJ</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#string-helpers">String Helpers</a> |
| <ul> |
| <li> |
| <a href="#string-api-initialization-and-destruction">String API - Initialization and Destruction</a> |
| <ul> |
| <li> |
| <a href="#string-memory-allocation">String Memory Allocation</a> |
| </li> |
| <li> |
| <a href="#fio_str_init"><code>FIO_STR_INIT</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_init_existing"><code>FIO_STR_INIT_EXISTING</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_init_static"><code>FIO_STR_INIT_STATIC</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_init_static2"><code>FIO_STR_INIT_STATIC2</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_new2"><code>fio_str_new2</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_new_copy2"><code>fio_str_new_copy2</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_dup"><code>fio_str_dup</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_free"><code>fio_str_free</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_free2"><code>fio_str_free2</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_send_free2"><code>fio_str_send_free2</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_detach"><code>fio_str_detach</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#string-api-string-state-data-pointers-length-capacity-etc">String API - String state (data pointers, length, capacity, etc')</a> |
| <ul> |
| <li> |
| <a href="#fio_str_info"><code>fio_str_info</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_len"><code>fio_str_len</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_data"><code>fio_str_data</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_bytes"><code>fio_str_bytes</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_capa"><code>fio_str_capa</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_resize"><code>fio_str_resize</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_clear"><code>fio_str_clear</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_hash"><code>fio_str_hash</code></a> |
| </li> |
| <li> |
| <a href="#fio_risky_hash"><code>fio_risky_hash</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#string-api-memory-management">String API - Memory management</a> |
| <ul> |
| <li> |
| <a href="#fio_str_compact"><code>fio_str_compact</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_capa_assert"><code>fio_str_capa_assert</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#string-api-utf-8-state">String API - UTF-8 State</a> |
| <ul> |
| <li> |
| <a href="#fio_str_utf8_valid"><code>fio_str_utf8_valid</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_utf8_len"><code>fio_str_utf8_len</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_utf8_select"><code>fio_str_utf8_select</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_utf8_code_point"><code>FIO_STR_UTF8_CODE_POINT</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#string-api-content-manipulation-and-review">String API - Content Manipulation and Review</a> |
| <ul> |
| <li> |
| <a href="#fio_str_write"><code>fio_str_write</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_write_i"><code>fio_str_write_i</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_concat"><code>fio_str_concat</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_join"><code>fio_str_join</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_replace"><code>fio_str_replace</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_vprintf"><code>fio_str_vprintf</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_printf"><code>fio_str_printf</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_readfile"><code>fio_str_readfile</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_freeze"><code>fio_str_freeze</code></a> |
| </li> |
| <li> |
| <a href="#fio_str_iseq"><code>fio_str_iseq</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#dynamic-arrays">Dynamic Arrays</a> |
| <ul> |
| <li> |
| <a href="#array-memory-allocation">Array Memory allocation</a> |
| </li> |
| <li> |
| <a href="#defining-the-array">Defining the Array</a> |
| <ul> |
| <li> |
| <a href="#fio_ary_name"><code>FIO_ARY_NAME</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_type"><code>FIO_ARY_TYPE</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_invalid"><code>FIO_ARY_INVALID</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_compare"><code>FIO_ARY_COMPARE</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_copy"><code>FIO_ARY_COPY</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_destroy"><code>FIO_ARY_DESTROY</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_malloc"><code>FIO_ARY_MALLOC</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_realloc"><code>FIO_ARY_REALLOC</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_dealloc"><code>FIO_ARY_DEALLOC</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#naming-the-array">Naming the Array</a> |
| </li> |
| <li> |
| <a href="#array-initialization-and-state">Array Initialization and State</a> |
| <ul> |
| <li> |
| <a href="#fio_ary_name-s"><code>FIO_ARY_NAME(s)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_init"><code>FIO_ARY_INIT</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-free"><code>FIO_ARY_NAME(free)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-count"><code>FIO_ARY_NAME(count)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-capa"><code>FIO_ARY_NAME(capa)</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#array-data-management">Array data management</a> |
| <ul> |
| <li> |
| <a href="#fio_ary_name-concat"><code>FIO_ARY_NAME(concat)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-set"><code>FIO_ARY_NAME(set)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-get"><code>FIO_ARY_NAME(get)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-find"><code>FIO_ARY_NAME(find)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-remove"><code>FIO_ARY_NAME(remove)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-remove2"><code>FIO_ARY_NAME(remove2)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-to_a"><code>FIO_ARY_NAME(to_a)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-push"><code>FIO_ARY_NAME(push)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-pop"><code>FIO_ARY_NAME(pop)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-unshift"><code>FIO_ARY_NAME(unshift)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-shift"><code>FIO_ARY_NAME(shift)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-each"><code>FIO_ARY_NAME(each)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_name-compact"><code>FIO_ARY_NAME(compact)</code></a> |
| </li> |
| <li> |
| <a href="#fio_ary_for-ary-pos"><code>FIO_ARY_FOR(ary, pos)</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#hash-maps-sets">Hash Maps / Sets</a> |
| <ul> |
| <li> |
| <a href="#security-concerns">Security Concerns</a> |
| </li> |
| <li> |
| <a href="#hash-map-set-memory-allocation">Hash Map / Set Memory allocation</a> |
| </li> |
| <li> |
| <a href="#defining-the-set-hash-map">Defining the Set / Hash Map</a> |
| <ul> |
| <li> |
| <a href="#fio_set_obj_type"><code>FIO_SET_OBJ_TYPE</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_obj_compare"><code>FIO_SET_OBJ_COMPARE</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_obj_copy"><code>FIO_SET_OBJ_COPY</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_obj_destroy"><code>FIO_SET_OBJ_DESTROY</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_key_type"><code>FIO_SET_KEY_TYPE</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_key_compare"><code>FIO_SET_KEY_COMPARE</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_key_copy"><code>FIO_SET_KEY_COPY</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_key_destroy"><code>FIO_SET_KEY_DESTROY</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_realloc"><code>FIO_SET_REALLOC</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_calloc"><code>FIO_SET_CALLOC</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_free"><code>FIO_SET_FREE</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#naming-the-set-hash-map">Naming the Set / Hash Map</a> |
| </li> |
| <li> |
| <a href="#set-hash-map-initialization">Set / Hash Map Initialization</a> |
| <ul> |
| <li> |
| <a href="#fio_set_name-s"><code>FIO_SET_NAME(s)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_init"><code>FIO_SET_INIT</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_name-free"><code>FIO_SET_NAME(free)</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#hash-map-find-insert">Hash Map Find / Insert</a> |
| <ul> |
| <li> |
| <a href="#fio_set_name-find-hash-map"><code>FIO_SET_NAME(find)</code> (Hash Map)</a> |
| </li> |
| <li> |
| <a href="#fio_set_name-insert-hash-map"><code>FIO_SET_NAME(insert)</code> (Hash Map)</a> |
| </li> |
| <li> |
| <a href="#fio_set_name-remove-hash-map"><code>FIO_SET_NAME(remove)</code> (Hash Map)</a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#set-find-insert">Set Find / Insert</a> |
| <ul> |
| <li> |
| <a href="#fio_set_name-find-set"><code>FIO_SET_NAME(find)</code> (Set)</a> |
| </li> |
| <li> |
| <a href="#fio_set_name-insert-set"><code>FIO_SET_NAME(insert)</code> (Set)</a> |
| </li> |
| <li> |
| <a href="#fio_set_name-overwrite-set"><code>FIO_SET_NAME(overwrite)</code> (Set)</a> |
| </li> |
| <li> |
| <a href="#fio_set_name-remove-set"><code>FIO_SET_NAME(remove)</code> (Set)</a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#set-hash-map-data">Set / Hash Map Data</a> |
| <ul> |
| <li> |
| <a href="#fio_set_name-last"><code>FIO_SET_NAME(last)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_name-pop"><code>FIO_SET_NAME(pop)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_name-count"><code>FIO_SET_NAME(count)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_name-capa"><code>FIO_SET_NAME(capa)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_name-capa_require"><code>FIO_SET_NAME(capa_require)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_name-is_fragmented"><code>FIO_SET_NAME(is_fragmented)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_name-compact"><code>FIO_SET_NAME(compact)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_name-rehash"><code>FIO_SET_NAME(rehash)</code></a> |
| </li> |
| <li> |
| <a href="#fio_set_for_loop"><code>FIO_SET_FOR_LOOP</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#general-helpers">General Helpers</a> |
| <ul> |
| <li> |
| <a href="#atomic-operations">Atomic operations</a> |
| <ul> |
| <li> |
| <a href="#fio_atomic_xchange"><code>fio_atomic_xchange</code></a> |
| </li> |
| <li> |
| <a href="#fio_atomic_add"><code>fio_atomic_add</code></a> |
| </li> |
| <li> |
| <a href="#fio_atomic_sub"><code>fio_atomic_sub</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#atomic-locks">Atomic locks</a> |
| <ul> |
| <li> |
| <a href="#fio_trylock"><code>fio_trylock</code></a> |
| </li> |
| <li> |
| <a href="#fio_lock"><code>fio_lock</code></a> |
| </li> |
| <li> |
| <a href="#fio_is_locked"><code>fio_is_locked</code></a> |
| </li> |
| <li> |
| <a href="#fio_unlock"><code>fio_unlock</code></a> |
| </li> |
| <li> |
| <a href="#fio_reschedule_thread"><code>fio_reschedule_thread</code></a> |
| </li> |
| <li> |
| <a href="#fio_throttle_thread"><code>fio_throttle_thread</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#byte-ordering-helpers-network-vs-local">Byte Ordering Helpers (Network vs. Local)</a> |
| <ul> |
| <li> |
| <a href="#fio_lton16"><code>fio_lton16</code></a> |
| </li> |
| <li> |
| <a href="#fio_lton32"><code>fio_lton32</code></a> |
| </li> |
| <li> |
| <a href="#fio_lton64"><code>fio_lton64</code></a> |
| </li> |
| <li> |
| <a href="#fio_str2u16"><code>fio_str2u16</code></a> |
| </li> |
| <li> |
| <a href="#fio_str2u32"><code>fio_str2u32</code></a> |
| </li> |
| <li> |
| <a href="#fio_str2u64"><code>fio_str2u64</code></a> |
| </li> |
| <li> |
| <a href="#fio_u2str16"><code>fio_u2str16</code></a> |
| </li> |
| <li> |
| <a href="#fio_u2str32"><code>fio_u2str32</code></a> |
| </li> |
| <li> |
| <a href="#fio_u2str64"><code>fio_u2str64</code></a> |
| </li> |
| <li> |
| <a href="#fio_ntol16"><code>fio_ntol16</code></a> |
| </li> |
| <li> |
| <a href="#fio_ntol32"><code>fio_ntol32</code></a> |
| </li> |
| <li> |
| <a href="#fio_ntol64"><code>fio_ntol64</code></a> |
| </li> |
| <li> |
| <a href="#fio_bswap16"><code>fio_bswap16</code></a> |
| </li> |
| <li> |
| <a href="#fio_bswap32"><code>fio_bswap32</code></a> |
| </li> |
| <li> |
| <a href="#fio_bswap64"><code>fio_bswap64</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#strings-to-numbers">Strings to Numbers</a> |
| <ul> |
| <li> |
| <a href="#fio_atol"><code>fio_atol</code></a> |
| </li> |
| <li> |
| <a href="#fio_atof"><code>fio_atof</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#numbers-to-strings">Numbers to Strings</a> |
| <ul> |
| <li> |
| <a href="#fio_ltoa"><code>fio_ltoa</code></a> |
| </li> |
| <li> |
| <a href="#fio_ftoa"><code>fio_ftoa</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#random-data-generation">Random data Generation</a> |
| <ul> |
| <li> |
| <a href="#fio_rand64"><code>fio_rand64</code></a> |
| </li> |
| <li> |
| <a href="#fio_rand_bytes"><code>fio_rand_bytes</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#base64">Base64</a> |
| <ul> |
| <li> |
| <a href="#fio_base64_encode"><code>fio_base64_encode</code></a> |
| </li> |
| <li> |
| <a href="#fio_base64url_encode"><code>fio_base64url_encode</code></a> |
| </li> |
| <li> |
| <a href="#fio_base64_decode"><code>fio_base64_decode</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#siphash">SipHash</a> |
| <ul> |
| <li> |
| <a href="#fio_siphash24"><code>fio_siphash24</code></a> |
| </li> |
| <li> |
| <a href="#fio_siphash13"><code>fio_siphash13</code></a> |
| </li> |
| <li> |
| <a href="#fio_siphash"><code>fio_siphash</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#sha-1">SHA-1</a> |
| <ul> |
| <li> |
| <a href="#fio_sha1_init"><code>fio_sha1_init</code></a> |
| </li> |
| <li> |
| <a href="#fio_sha1"><code>fio_sha1</code></a> |
| </li> |
| <li> |
| <a href="#fio_sha1_write"><code>fio_sha1_write</code></a> |
| </li> |
| <li> |
| <a href="#fio_sha1_result"><code>fio_sha1_result</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#sha-2">SHA-2</a> |
| <ul> |
| <li> |
| <a href="#fio_sha2_init"><code>fio_sha2_init</code></a> |
| </li> |
| <li> |
| <a href="#fio_sha2_write"><code>fio_sha2_write</code></a> |
| </li> |
| <li> |
| <a href="#fio_sha2_result"><code>fio_sha2_result</code></a> |
| </li> |
| <li> |
| <a href="#fio_sha2_512"><code>fio_sha2_512</code></a> |
| </li> |
| <li> |
| <a href="#fio_sha2_256"><code>fio_sha2_256</code></a> |
| </li> |
| <li> |
| <a href="#fio_sha2_256"><code>fio_sha2_256</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#version-and-compilation-related-macros">Version and Compilation Related Macros</a> |
| <ul> |
| <li> |
| <a href="#version-macros">Version Macros</a> |
| <ul> |
| <li> |
| <a href="#fio_version_major"><code>FIO_VERSION_MAJOR</code></a> |
| </li> |
| <li> |
| <a href="#fio_version_minor"><code>FIO_VERSION_MINOR</code></a> |
| </li> |
| <li> |
| <a href="#fio_version_patch"><code>FIO_VERSION_PATCH</code></a> |
| </li> |
| <li> |
| <a href="#fio_version_beta"><code>FIO_VERSION_BETA</code></a> |
| </li> |
| <li> |
| <a href="#fio_version_string"><code>FIO_VERSION_STRING</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#logging-macros">Logging Macros</a> |
| <ul> |
| <li> |
| <a href="#fio_log_level"><code>FIO_LOG_LEVEL</code></a> |
| </li> |
| <li> |
| <a href="#fio_log_fatal"><code>FIO_LOG_FATAL</code></a> |
| </li> |
| <li> |
| <a href="#fio_log_error"><code>FIO_LOG_ERROR</code></a> |
| </li> |
| <li> |
| <a href="#fio_log_warning"><code>FIO_LOG_WARNING</code></a> |
| </li> |
| <li> |
| <a href="#fio_log_info"><code>FIO_LOG_INFO</code></a> |
| </li> |
| <li> |
| <a href="#fio_log_debug"><code>FIO_LOG_DEBUG</code></a> |
| </li> |
| <li> |
| <a href="#fio_log_length_limit"><code>FIO_LOG_LENGTH_LIMIT</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#compilation-macros">Compilation Macros</a> |
| <ul> |
| <li> |
| <a href="#fio_max_sock_capacity"><code>FIO_MAX_SOCK_CAPACITY</code></a> |
| </li> |
| <li> |
| <a href="#fio_engine_poll"><code>FIO_ENGINE_POLL</code></a> |
| </li> |
| <li> |
| <a href="#fio_cpu_cores_limit"><code>FIO_CPU_CORES_LIMIT</code></a> |
| </li> |
| <li> |
| <a href="#fio_defer_throttle_progressive"><code>FIO_DEFER_THROTTLE_PROGRESSIVE</code></a> |
| </li> |
| <li> |
| <a href="#fio_print_state"><code>FIO_PRINT_STATE</code></a> |
| </li> |
| <li> |
| <a href="#fio_poll_max_events"><code>FIO_POLL_MAX_EVENTS</code></a> |
| </li> |
| <li> |
| <a href="#fio_use_urgent_queue"><code>FIO_USE_URGENT_QUEUE</code></a> |
| </li> |
| <li> |
| <a href="#fio_pubsub_support"><code>FIO_PUBSUB_SUPPORT</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#weak-functions">Weak functions</a> |
| <ul> |
| <li> |
| <a href="#forking">Forking</a> |
| <ul> |
| <li> |
| <a href="#fio_fork"><code>fio_fork</code></a> |
| </li> |
| </ul> |
| </li> |
| <li> |
| <a href="#thread-creation">Thread Creation</a> |
| <ul> |
| <li> |
| <a href="#fio_thread_new"><code>fio_thread_new</code></a> |
| </li> |
| <li> |
| <a href="#fio_thread_free"><code>fio_thread_free</code></a> |
| </li> |
| <li> |
| <a href="#fio_thread_join"><code>fio_thread_join</code></a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div><h1 id="facil-io-0-7-x-core-library-documentation">facil.io - 0.7.x Core Library Documentation</h1> |
| |
| <p>The core library types and functions can be found in the header <code>fio.h</code>.</p> |
| |
| <p>The header is well documented and very long, and as a result, so is this documentation.</p> |
| |
| <p>The header can be included more than once to produce multiple types of Hash Maps or data Sets. As well as to include some of it's optional features such as the binary String helpers and the linked list types.</p> |
| |
| <h2 id="connection-protocol-management">Connection (Protocol) Management</h2> |
| |
| <p>This section includes information about listening to incoming connections, connecting to remote machines and managing the protocol callback system.</p> |
| |
| <p>The facil.io library is an evented library and the <code>fio_protocol_s</code> structure is at the core of the network evented design, so we'll start with the Protocol object.</p> |
| |
| <h3 id="the-fio_protocol_s-structure">The <code>fio_protocol_s</code> structure</h3> |
| |
| <p>The Protocol structure defines the callbacks used for the connection and sets it's |
| behavior.</p> |
| |
| <p>For concurrency reasons, a protocol instance SHOULD be unique to each connection and dynamically allocated. In single threaded applications, this is less relevant.</p> |
| |
| <p>All the callbacks receive a unique connection ID (un-aptly named <code>uuid</code>) that can be |
| converted to the original file descriptor when in need.</p> |
| |
| <p>This allows facil.io to prevent old connection handles from sending data |
| to new connections after a file descriptor is "recycled" by the OS.</p> |
| |
| <p>The structure looks like this:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">struct</span> <span class="n">fio_protocol_s</span> <span class="p">{</span> |
| <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">on_data</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">on_ready</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| <span class="kt">uint8_t</span> <span class="p">(</span><span class="o">*</span><span class="n">on_shutdown</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">on_close</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">ping</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| <span class="kt">size_t</span> <span class="n">rsv</span><span class="p">;</span> |
| <span class="p">};</span> |
| </code></pre></div> |
| <h4 id="fio_protocol_s-on_data"><code>fio_protocol_s->on_data</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">on_data</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Called when a data is available.</p> |
| |
| <p>The function is called under the protocol's main lock (<code>FIO_PR_LOCK_TASK</code>), safeguarding the connection against collisions (the function will not run concurrently with itself for the same connection.</p> |
| |
| <h4 id="fio_protocol_s-on_ready"><code>fio_protocol_s->on_ready</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">on_ready</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Called once all pending <a href="#fio_write"><code>fio_write</code></a> calls are finished.</p> |
| |
| <p>For new connections this callback is also called once a connection was established and the connection can be written to.</p> |
| |
| <h4 id="fio_protocol_s-on_shutdown"><code>fio_protocol_s->on_shutdown</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">uint8_t</span> <span class="n">on_shutdown</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Called when the server is shutting down, immediately before closing the connection.</p> |
| |
| <p>The callback runs within a <code>FIO_PR_LOCK_TASK</code> lock, so it will never run concurrently with <code>on_data</code> or other connection specific tasks <a href="#fio_defer_io_task"><code>fio_defer_io_task</code></a>.</p> |
| |
| <p>The <code>on_shutdown</code> callback should return 0 under normal circumstances. This will mark the connection for immediate closure and allow 8 seconds for all pending data to be sent.</p> |
| |
| <p>The <code>on_shutdown</code> callback may also return any number between 1..254 to delay the socket closure by that amount of time. </p> |
| |
| <p>If the <code>on_shutdown</code> returns 255, the socket is ignored and it will be abruptly terminated when all other sockets have finished their graceful shutdown procedure.</p> |
| |
| <h4 id="fio_protocol_s-on_close"><code>fio_protocol_s->on_close</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">uint8_t</span> <span class="n">on_close</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Called when the connection was closed, but will not run concurrently with other callbacks.</p> |
| |
| <h4 id="fio_protocol_s-ping"><code>fio_protocol_s->ping</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">uint8_t</span> <span class="n">ping</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Called when a connection's timeout was reached.</p> |
| |
| <p>This callback is called outside of the protocol's normal locks to support pinging in cases where the <code>on_data</code> callback is running in the background (which shouldn't happen, but we know it sometimes does).</p> |
| |
| <h4 id="fio_protocol_s-rsv"><code>fio_protocol_s->rsv</code></h4> |
| |
| <p>This is private metadata used by facil. In essence it holds the locking data and overwriting this data is extremely volatile.</p> |
| |
| <p>The data MUST be set to 0 before <a href="#fio_attach">attaching a protocol</a> to facil.io.</p> |
| |
| <h3 id="attaching-detaching-protocol-objects">Attaching / Detaching Protocol Objects</h3> |
| |
| <p>Once a protocol object was created, it should be attached to the fail.io library.</p> |
| |
| <p>Detaching is also possible by attaching a NULL protocol (used for "hijacking" the socket from <code>facil.io</code>).</p> |
| |
| <h4 id="fio_attach"><code>fio_attach</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_attach</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Attaches (or updates) a protocol object to a connection's uuid.</p> |
| |
| <p>The new protocol object can be NULL, which will detach ("hijack") the socket.</p> |
| |
| <p>The old protocol's <code>on_close</code> (if any) will be scheduled.</p> |
| |
| <p>On error, the new protocol's <code>on_close</code> callback will be called immediately.</p> |
| |
| <p><strong>Note</strong>: before attaching a file descriptor that was created outside of facil.io's library, make sure it is set to non-blocking mode (see <a href="#fio_set_non_block"><code>fio_set_non_block</code></a>). facil.io file descriptors are all non-blocking and it will assumes this is the case for the attached fd.</p> |
| |
| <h4 id="fio_attach_fd"><code>fio_attach_fd</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_attach_fd</span><span class="p">(</span><span class="kt">int</span> <span class="n">fd</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">protocol</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Attaches (or updates) a protocol object to a file descriptor (fd).</p> |
| |
| <p>The new protocol object can be NULL, which will detach ("hijack") the socket.</p> |
| |
| <p>The <code>fd</code> can be one created outside of facil.io if it was set in to non-blocking mode (see <a href="#fio_set_non_block"><code>fio_set_non_block</code></a>).</p> |
| |
| <p>The old protocol's <code>on_close</code> (if any) will be scheduled.</p> |
| |
| <p>On error, the new protocol's <code>on_close</code> callback will be called immediately.</p> |
| |
| <h4 id="fio_capa"><code>fio_capa</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">size_t</span> <span class="n">fio_capa</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the maximum number of open files facil.io can handle per worker process.</p> |
| |
| <p>In practice, this number represents the maximum <code>fd</code> value + 1.</p> |
| |
| <p>Total OS limits might apply as well but aren't tested or known by facil.io.</p> |
| |
| <p>The value of 0 indicates either that the facil.io library wasn't initialized |
| yet or that it's resources were already released.</p> |
| |
| <h4 id="fio_timeout_set"><code>fio_timeout_set</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_timeout_set</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">timeout</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Sets a timeout for a specific connection (only when running and valid).</p> |
| |
| <h4 id="fio_timeout_get"><code>fio_timeout_get</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">uint8_t</span> <span class="n">fio_timeout_get</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Gets a timeout for a specific connection. Returns 0 if none.</p> |
| |
| <h4 id="fio_touch"><code>fio_touch</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_touch</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p>"Touches" a socket connection, resetting it's timeout counter.</p> |
| |
| <h4 id="fio_force_event"><code>fio_force_event</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_force_event</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="k">enum</span> <span class="n">fio_io_event</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Schedules an IO event, even if it did not occur.</p> |
| |
| <p>Possible events are:</p> |
| |
| <ul> |
| <li><code>FIO_EVENT_ON_DATA</code> - as if data is available to be read.</li> |
| <li><code>FIO_EVENT_ON_READY</code> - as if the connection can be written to (if there's data in the buffer, <code>fio_flush</code> will be called).</li> |
| <li><code>FIO_EVENT_ON_TIMEOUT</code> - as if the connection timed out (<code>ping</code>).</li> |
| </ul> |
| |
| <h4 id="fio_suspend"><code>fio_suspend</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_suspend</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Temporarily prevents <code>on_data</code> events from firing.</p> |
| |
| <p>Resume listening to <code>on_data</code> events by calling the <code>fio_force_event(uuid, FIO_EVENT_ON_DATA</code>.</p> |
| |
| <p>Note: the function will work as expected when called within the protocol's <code>on_data</code> callback and the <code>uuid</code> refers to a valid socket. Otherwise the function might quietly fail.</p> |
| |
| <h3 id="listening-to-incoming-connections">Listening to incoming connections</h3> |
| |
| <p>Listening to incoming connections is pretty straight forward and performed using the <a href="#facil_listen"><code>facil_listen</code></a> function.</p> |
| |
| <p>After a new connection is accepted, the <code>on_open</code> callback passed to <a href="#facil_listen"><code>facil_listen</code></a> is called.</p> |
| |
| <p>The <code>on_open</code> callback should allocate the new connection's protocol and call <a href="#fio_attach"><code>fio_attach</code></a> to attach a protocol to the connection's uuid.</p> |
| |
| <p>The protocol's <code>on_close</code> callback is expected to handle any cleanup required.</p> |
| |
| <p>The following is an example for a TCP/IP echo server using facil.io:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#include <fio.h> |
| </span> |
| <span class="c1">// A callback to be called whenever data is available on the socket</span> |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">echo_on_data</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">prt</span><span class="p">)</span> <span class="p">{</span> |
| <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">prt</span><span class="p">;</span> <span class="c1">// we can ignore the unused argument</span> |
| <span class="c1">// echo buffer</span> |
| <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">1024</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="sc">'E'</span><span class="p">,</span> <span class="sc">'c'</span><span class="p">,</span> <span class="sc">'h'</span><span class="p">,</span> <span class="sc">'o'</span><span class="p">,</span> <span class="sc">':'</span><span class="p">,</span> <span class="sc">' '</span><span class="p">};</span> |
| <span class="kt">ssize_t</span> <span class="n">len</span><span class="p">;</span> |
| <span class="c1">// Read to the buffer, starting after the "Echo: "</span> |
| <span class="k">while</span> <span class="p">((</span><span class="n">len</span> <span class="o">=</span> <span class="n">fio_read</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="n">buffer</span> <span class="o">+</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">1018</span><span class="p">))</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Read: %.*s"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">len</span><span class="p">,</span> <span class="n">buffer</span> <span class="o">+</span> <span class="mi">6</span><span class="p">);</span> |
| <span class="c1">// Write back the message</span> |
| <span class="n">fio_write</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">len</span> <span class="o">+</span> <span class="mi">6</span><span class="p">);</span> |
| <span class="c1">// Handle goodbye</span> |
| <span class="k">if</span> <span class="p">((</span><span class="n">buffer</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">|</span> <span class="mi">32</span><span class="p">)</span> <span class="o">==</span> <span class="sc">'b'</span> <span class="o">&&</span> <span class="p">(</span><span class="n">buffer</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="o">|</span> <span class="mi">32</span><span class="p">)</span> <span class="o">==</span> <span class="sc">'y'</span> <span class="o">&&</span> |
| <span class="p">(</span><span class="n">buffer</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="o">|</span> <span class="mi">32</span><span class="p">)</span> <span class="o">==</span> <span class="sc">'e'</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">fio_write</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="s">"Goodbye.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span> |
| <span class="n">fio_close</span><span class="p">(</span><span class="n">uuid</span><span class="p">);</span> |
| <span class="k">return</span><span class="p">;</span> |
| <span class="p">}</span> |
| <span class="p">}</span> |
| <span class="p">}</span> |
| |
| <span class="c1">// A callback called whenever a timeout is reach</span> |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">echo_ping</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">prt</span><span class="p">)</span> <span class="p">{</span> |
| <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">prt</span><span class="p">;</span> <span class="c1">// we can ignore the unused argument</span> |
| <span class="n">fio_write</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="s">"Server: Are you there?</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="mi">23</span><span class="p">);</span> |
| <span class="p">}</span> |
| |
| <span class="c1">// A callback called if the server is shutting down...</span> |
| <span class="c1">// ... while the connection is still open</span> |
| <span class="k">static</span> <span class="kt">uint8_t</span> <span class="nf">echo_on_shutdown</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">prt</span><span class="p">)</span> <span class="p">{</span> |
| <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">prt</span><span class="p">;</span> <span class="c1">// we can ignore the unused argument</span> |
| <span class="n">fio_write</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="s">"Echo server shutting down</span><span class="se">\n</span><span class="s">Goodbye.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="mi">35</span><span class="p">);</span> |
| <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> |
| <span class="p">}</span> |
| |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">echo_on_close</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">proto</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Connection %p closed.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">proto</span><span class="p">);</span> |
| <span class="n">free</span><span class="p">(</span><span class="n">proto</span><span class="p">);</span> |
| <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">uuid</span><span class="p">;</span> |
| <span class="p">}</span> |
| |
| <span class="c1">// A callback called for new connections</span> |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">echo_on_open</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">)</span> <span class="p">{</span> |
| <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">udata</span><span class="p">;</span> <span class="c1">// ignore this</span> |
| <span class="c1">// Protocol objects MUST be dynamically allocated when multi-threading.</span> |
| <span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">echo_proto</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">echo_proto</span><span class="p">));</span> |
| <span class="n">echo_proto</span> <span class="o">=</span> <span class="p">(</span><span class="n">fio_protocol_s</span><span class="p">){.</span><span class="n">service</span> <span class="o">=</span> <span class="s">"echo"</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">on_data</span> <span class="o">=</span> <span class="n">echo_on_data</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">on_shutdown</span> <span class="o">=</span> <span class="n">echo_on_shutdown</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">on_close</span> <span class="o">=</span> <span class="n">echo_on_close</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">ping</span> <span class="o">=</span> <span class="n">echo_ping</span><span class="p">};</span> |
| <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"New Connection %p received from %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">echo_proto</span><span class="p">,</span> |
| <span class="n">fio_peer_addr</span><span class="p">(</span><span class="n">uuid</span><span class="p">).</span><span class="n">data</span><span class="p">);</span> |
| <span class="n">fio_attach</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="n">echo_proto</span><span class="p">);</span> |
| <span class="n">fio_write2</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">buffer</span> <span class="o">=</span> <span class="s">"Echo Service: Welcome</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">.</span><span class="n">length</span> <span class="o">=</span> <span class="mi">22</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">after</span><span class="p">.</span><span class="n">dealloc</span> <span class="o">=</span> <span class="n">FIO_DEALLOC_NOOP</span><span class="p">);</span> |
| <span class="n">fio_timeout_set</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span> |
| <span class="p">}</span> |
| |
| <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> |
| <span class="c1">// Setup a listening socket</span> |
| <span class="k">if</span> <span class="p">(</span><span class="n">fio_listen</span><span class="p">(.</span><span class="n">port</span> <span class="o">=</span> <span class="s">"3000"</span><span class="p">,</span> <span class="p">.</span><span class="n">on_open</span> <span class="o">=</span> <span class="n">echo_on_open</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">perror</span><span class="p">(</span><span class="s">"No listening socket available on port 3000"</span><span class="p">);</span> |
| <span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> |
| <span class="p">}</span> |
| <span class="c1">// Run the server and hang until a stop signal is received.</span> |
| <span class="n">fio_start</span><span class="p">(.</span><span class="n">threads</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="p">.</span><span class="n">workers</span> <span class="o">=</span> <span class="mi">1</span><span class="p">);</span> |
| <span class="p">}</span> |
| </code></pre></div> |
| <h4 id="fio_listen"><code>fio_listen</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">intptr_t</span> <span class="n">fio_listen</span><span class="p">(</span><span class="k">struct</span> <span class="n">fio_listen_args</span> <span class="n">args</span><span class="p">);</span> |
| <span class="cp">#define fio_listen(...) fio_listen((struct fio_listen_args){__VA_ARGS__}) |
| </span></code></pre></div> |
| <p>The <code>fio_listen</code> function is shadowed by the <code>fio_listen</code> MACRO, which allows the function to accept "named arguments", as shown above in the example code:</p> |
| <div class="highlight"><pre class="highlight c"><code> <span class="k">if</span> <span class="p">(</span><span class="n">fio_listen</span><span class="p">(.</span><span class="n">port</span> <span class="o">=</span> <span class="s">"3000"</span><span class="p">,</span> <span class="p">.</span><span class="n">on_open</span> <span class="o">=</span> <span class="n">echo_on_open</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">perror</span><span class="p">(</span><span class="s">"No listening socket available on port 3000"</span><span class="p">);</span> |
| <span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> |
| <span class="p">}</span> |
| </code></pre></div> |
| <p>The following arguments are supported:</p> |
| |
| <ul> |
| <li><p><code>on_open</code>:</p> |
| |
| <p>This callback will be called whenever a new connection is accepted. It <strong>must</strong> either call <a href="#fio_attach"><code>fio_attach</code></a> or close the connection.</p> |
| |
| <p>The callback should accept the new connection's uuid and a void pointer (the optional <code>udata</code> pointer one passed to <code>fio_listen</code>)</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// callback example: |
| void on_open(intptr_t uuid, void *udata); |
| </code></pre></div></li> |
| <li><p><code>port</code>:</p> |
| |
| <p>The network service / port. A NULL or "0" port indicates a Unix socket should be used.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| const char *port; |
| </code></pre></div></li> |
| <li><p><code>address</code>:</p> |
| |
| <p>The socket binding address. Defaults to the recommended NULL (recommended for TCP/IP).</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| const char *address; |
| </code></pre></div></li> |
| <li><p><code>udata</code>:</p> |
| |
| <p>Opaque user data. This will be passed along to the <code>on_open</code> callback.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| void *udata; |
| </code></pre></div></li> |
| <li><p><code>on_start</code>:</p> |
| |
| <p>A callback to be called when the server starts (or a worker process is re-spawned), allowing for further initialization, such as timed event scheduling or VM initialization.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// callback example: |
| void on_start(intptr_t uuid, void *udata); |
| </code></pre></div></li> |
| <li><p><code>on_finish</code>:</p> |
| |
| <p>A callback to be called for every process once the listening socket is closed.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// callback example: |
| void on_finish(intptr_t uuid, void *udata); |
| </code></pre></div></li> |
| </ul> |
| |
| <h3 id="connecting-to-remote-servers-as-a-client">Connecting to remote servers as a client</h3> |
| |
| <p>Establishing a client connection is about as easy as setting up a listening socket, and follows, give or take, the same procedure.</p> |
| |
| <h4 id="fio_connect"><code>fio_connect</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">intptr_t</span> <span class="n">fio_connect</span><span class="p">(</span><span class="k">struct</span> <span class="n">fio_connect_args</span> <span class="n">args</span><span class="p">);</span> |
| <span class="cp">#define fio_connect(...) fio_connect((struct fio_connect_args){__VA_ARGS__}) |
| </span></code></pre></div> |
| <p>The <code>fio_connect</code> function is shadowed by the <code>fio_connect</code> MACRO, which allows the function to accept "named arguments", similar to <a href="#fio_listen">`fio_listen</a>.</p> |
| |
| <p>The following arguments are supported:</p> |
| |
| <ul> |
| <li><p><code>port</code>:</p> |
| |
| <p>The remote network service / port. A NULL or "0" port indicates a Unix socket connection should be attempted.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| const char *port; |
| </code></pre></div></li> |
| <li><p><code>address</code>:</p> |
| |
| <p>The remote (or Unix socket) address. Defaults to the recommended NULL (recommended for TCP/IP).</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| const char *address; |
| </code></pre></div></li> |
| <li><p><code>on_connect</code>:</p> |
| |
| <p>This callback will be called once the new connection is established. It <strong>must</strong> either call <a href="#fio_attach"><code>fio_attach</code></a> or close the connection.</p> |
| |
| <p>The callback should accept the new connection's uuid and a void pointer (the optional <code>udata</code> pointer one passed to <code>fio_connect</code>)</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// callback example: |
| void on_connect(intptr_t uuid, void *udata); |
| </code></pre></div></li> |
| <li><p><code>on_connect</code>:</p> |
| |
| <p>This callback will be called when a socket fails to connect. It's often a good place for cleanup.</p> |
| |
| <p>The callback should accept the attempted connection's uuid (might be -1) and a void pointer (the optional <code>udata</code> pointer one passed to <code>fio_connect</code>)</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// callback example: |
| void on_connect(intptr_t uuid, void *udata); |
| </code></pre></div></li> |
| <li><p><code>udata</code>:</p> |
| |
| <p>Opaque user data. This will be passed along to the <code>on_connect</code> or <code>on_fail</code> callback.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| void *udata; |
| </code></pre></div></li> |
| <li><p><code>timeout</code>:</p> |
| |
| <p>A non-system timeout after which connection is assumed to have failed.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| uint8_t timeout; |
| </code></pre></div></li> |
| </ul> |
| |
| <h3 id="url-parsing">URL Parsing</h3> |
| |
| <h4 id="fio_url_parse"><code>fio_url_parse</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_url_s</span> <span class="n">fio_url_parse</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">url</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Parses the URI returning it's components and their lengths - no decoding |
| performed, doesn't accept decoded URIs.</p> |
| |
| <p>the result returned by <code>fio_url_parse</code> is a <code>fio_url_s</code> structure:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> |
| <span class="n">fio_str_info_s</span> <span class="n">scheme</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">user</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">password</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">host</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">port</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">path</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">query</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">target</span><span class="p">;</span> |
| <span class="p">}</span> <span class="n">fio_url_s</span><span class="p">;</span> |
| </code></pre></div> |
| <p>The returned string are NOT NUL terminated, they are merely locations within the original string.</p> |
| |
| <p>This function attempts to accept different formats, including any of the following formats:</p> |
| |
| <ul> |
| <li><p><code>/complete_path?query#target</code></p> |
| |
| <p>i.e.:</p> |
| |
| <ul> |
| <li>/index.html?page=1#list</li> |
| </ul></li> |
| <li><p><code>host:port/complete_path?query#target</code></p> |
| |
| <p>i.e.:</p> |
| |
| <ul> |
| <li>example.com</li> |
| <li>example.com:8080</li> |
| <li>example.com/index.html</li> |
| <li>example.com:8080/index.html</li> |
| </ul></li> |
| <li><p><code>user:password@host:port[/path?query#target]</code></p> |
| |
| <p>i.e.:</p> |
| |
| <ul> |
| <li>user:<a href="mailto:1234@example.com">1234@example.com</a>:8080/index.html</li> |
| <li>user:<a href="mailto:1234@example.com">1234@example.com</a>?query=1</li> |
| <li>john:<a href="mailto:1234@example.com">1234@example.com</a></li> |
| </ul></li> |
| <li><p><code>scheme://user:password@host:port/path?query#target</code></p> |
| |
| <p>i.e.:</p> |
| |
| <ul> |
| <li><a href="http://example.com/index.html?page=1#list">http://example.com/index.html?page=1#list</a></li> |
| <li>tcp://example.com</li> |
| </ul></li> |
| </ul> |
| |
| <p>Invalid formats might produce unexpected results. No error testing is performed.</p> |
| |
| <h3 id="manual-protocol-locking">Manual Protocol Locking</h3> |
| |
| <h4 id="fio_protocol_try_lock"><code>fio_protocol_try_lock</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">fio_protocol_try_lock</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="k">enum</span> <span class="n">fio_protocol_lock_e</span><span class="p">);</span> |
| </code></pre></div> |
| <p>This function allows out-of-task access to a connection's <code>fio_protocol_s</code> object by attempting to acquire a locked pointer.</p> |
| |
| <p>CAREFUL: mostly, the protocol object will be locked and a pointer will be sent to the connection event's callback. However, if you need access to the protocol object from outside a running connection task, you might need to lock the protocol to prevent it from being closed / freed in the background.</p> |
| |
| <p>facil.io uses three different locks (see <a href="#fio_defer_io_task"><code>fio_defer_io_task</code></a> for more information):</p> |
| |
| <ul> |
| <li><p><code>FIO_PR_LOCK_TASK</code> locks the protocol for normal tasks (i.e. <code>on_data</code>).</p></li> |
| <li><p><code>FIO_PR_LOCK_WRITE</code> locks the protocol for high priority <code>fio_write</code> |
| oriented tasks (i.e. <code>ping</code>, <code>on_ready</code>).</p></li> |
| <li><p><code>FIO_PR_LOCK_STATE</code> locks the protocol for quick operations that need to copy |
| data from the protocol's data structure.</p></li> |
| </ul> |
| |
| <p>IMPORTANT: Remember to call <a href="fio_protocol_unlock"><code>fio_protocol_unlock</code></a> using the same lock type.</p> |
| |
| <p>Returns a pointer to a protocol object on success and NULL on error and setting <code>errno</code> (lock busy == <code>EWOULDBLOCK</code>, connection invalid == <code>EBADF</code>).</p> |
| |
| <p>On error, consider calling <code>fio_defer</code> or <code>fio_defer_io_task</code> instead of busy waiting. Busy waiting SHOULD be avoided whenever possible.</p> |
| |
| <h4 id="fio_protocol_unlock"><code>fio_protocol_unlock</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_protocol_unlock</span><span class="p">(</span><span class="n">fio_protocol_s</span> <span class="o">*</span><span class="n">pr</span><span class="p">,</span> <span class="k">enum</span> <span class="n">fio_protocol_lock_e</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Don't unlock what you didn't lock with <code>fio_protocol_try_lock</code>... see <a href="#fio_protocol_try_lock"><code>fio_protocol_try_lock</code></a> for details.</p> |
| |
| <h2 id="running-facil-io">Running facil.io</h2> |
| |
| <p>The facil.io IO reactor can be started in single-threaded, multi-threaded, forked (multi-process) and hybrid (forked + multi-threads) modes.</p> |
| |
| <p>In cluster mode (when running more than a single process), a crashed worker process will be automatically re-spawned and "hot restart" is enabled (using the USR1 signal).</p> |
| |
| <h4 id="fio_start"><code>fio_start</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_start</span><span class="p">(</span><span class="k">struct</span> <span class="n">fio_start_args</span> <span class="n">args</span><span class="p">);</span> |
| <span class="cp">#define fio_start(...) fio_start((struct fio_start_args){__VA_ARGS__}) |
| </span></code></pre></div> |
| <p>Starts the facil.io event loop. This function will return after facil.io is done (after shutdown).</p> |
| |
| <p>This method blocks the current thread until the server is stopped (when a SIGINT/SIGTERM is received).</p> |
| |
| <p>The <code>fio_start</code> function is shadowed by the <code>fio_start</code> MACRO, which allows the function to accept "named arguments", i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_start</span><span class="p">(.</span><span class="n">threads</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="p">.</span><span class="n">workers</span> <span class="o">=</span> <span class="mi">2</span><span class="p">);</span> |
| </code></pre></div> |
| <p>The following arguments are supported:</p> |
| |
| <ul> |
| <li><p><code>threads</code>:</p> |
| |
| <p>The number of threads to run in the thread pool.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| int16_t threads; |
| </code></pre></div></li> |
| <li><p><code>workers</code>:</p> |
| |
| <p>The number of worker processes to run (in addition to a root process)</p> |
| |
| <p>This invokes facil.io's cluster mode, where a crashed worker will be automatically re-spawned and "hot restart" is enabled (using the USR1 signal).</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| int16_t workers; |
| </code></pre></div></li> |
| </ul> |
| |
| <p>Negative thread / worker values indicate a fraction of the number of CPU cores. i.e., -2 will normally indicate "half" (1/2) the number of cores.</p> |
| |
| <p>If the other option (i.e. <code>.workers</code> when setting <code>.threads</code>) is zero, it will be automatically updated to reflect the option's absolute value. i.e.: if .threads == -2 and .workers == 0, than facil.io will run 2 worker processes with (cores/2) threads per process.</p> |
| |
| <h4 id="fio_stop"><code>fio_stop</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_stop</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Attempts to stop the facil.io application. This only works within the Root |
| process. A worker process will simply re-spawn itself (hot-restart).</p> |
| |
| <h4 id="fio_expected_concurrency"><code>fio_expected_concurrency</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_expected_concurrency</span><span class="p">(</span><span class="kt">int16_t</span> <span class="o">*</span><span class="n">threads</span><span class="p">,</span> <span class="kt">int16_t</span> <span class="o">*</span><span class="n">workers</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the number of expected threads / processes to be used by facil.io.</p> |
| |
| <p>The pointers should start with valid values that match the expected threads / |
| processes values passed to <code>fio_start</code>.</p> |
| |
| <p>The data in the pointers will be overwritten with the result.</p> |
| |
| <h4 id="fio_is_running"><code>fio_is_running</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int16_t</span> <span class="n">fio_is_running</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the number of worker processes if facil.io is running (1 is returned when in single process mode, otherwise the number of workers).</p> |
| |
| <p>Returns 0 if facil.io isn't running or is winding down (during shutdown).</p> |
| |
| <h4 id="fio_is_worker"><code>fio_is_worker</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_is_worker</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns 1 if the current process is a worker process or a single process.</p> |
| |
| <p>Otherwise returns 0.</p> |
| |
| <p><strong>Note</strong>: When cluster mode is off, the root process is also the worker process. This means that single process instances don't automatically re-spawn after critical errors.</p> |
| |
| <h4 id="fio_parent_pid"><code>fio_parent_pid</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">pid_t</span> <span class="n">fio_parent_pid</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns facil.io's parent (root) process pid.</p> |
| |
| <h4 id="fio_reap_children"><code>fio_reap_children</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_reap_children</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Initializes zombie reaping for the process. Call before <code>fio_start</code> to enable |
| global zombie reaping.</p> |
| |
| <h4 id="fio_signal_handler_reset"><code>fio_signal_handler_reset</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_signal_handler_reset</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Resets any existing signal handlers, restoring their state to before they were set by facil.io.</p> |
| |
| <p>This stops both child reaping (<code>fio_reap_children</code>) and the default facil.io signal handlers (i.e., CTRL-C).</p> |
| |
| <p>This function will be called automatically by facil.io whenever facil.io stops.</p> |
| |
| <h4 id="fio_last_tick"><code>fio_last_tick</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">struct</span> <span class="n">timespec</span> <span class="n">fio_last_tick</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the last time facil.io reviewed any pending IO events.</p> |
| |
| <h4 id="fio_engine"><code>fio_engine</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">char</span> <span class="k">const</span> <span class="o">*</span><span class="n">fio_engine</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns a C string detailing the IO engine selected during compilation.</p> |
| |
| <p>Valid values are "kqueue", "epoll" and "poll".</p> |
| |
| <h2 id="socket-connection-functions">Socket / Connection Functions</h2> |
| |
| <h3 id="creating-closing-and-testing-sockets">Creating, closing and testing sockets</h3> |
| |
| <h4 id="fio_socket"><code>fio_socket</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">intptr_t</span> <span class="n">fio_socket</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">address</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">port</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">is_server</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Creates a TCP/IP or Unix socket and returns it's unique identifier.</p> |
| |
| <p>The socket is non-blocking and the <code>O_CLOEXEC</code> flag will be set.</p> |
| |
| <p>For TCP/IP server sockets (<code>is_server</code> is <code>1</code>), a NULL <code>address</code> variable is recommended. Use "localhost" or "127.0.0.1" to limit access to the server application.</p> |
| |
| <p>For TCP/IP client sockets (<code>is_server</code> is <code>0</code>), a remote <code>address</code> and <code>port</code> combination will be required</p> |
| |
| <p>For Unix server or client sockets, set the <code>port</code> variable to NULL or <code>0</code> (and the <code>is_server</code> to <code>1</code>).</p> |
| |
| <p>Returns -1 on error. Any other value is a valid unique identifier.</p> |
| |
| <p><strong>Note</strong>: facil.io uses unique identifiers to protect sockets from collisions. However these identifiers can be converted to the underlying file descriptor using the <a href="#fio_uuid2fd"><code>fio_uuid2fd</code></a> macro.</p> |
| |
| <h4 id="fio_accept"><code>fio_accept</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">intptr_t</span> <span class="n">fio_accept</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">srv_uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_accept</code> accepts a new socket connection from a server socket - see the server flag on <a href="#fio_socket"><code>fio_socket</code></a>.</p> |
| |
| <p>Accepted connection are automatically set to non-blocking mode and the <code>O_CLOEXEC</code> flag is set.</p> |
| |
| <p><strong>Note</strong>: this function does NOT attach the socket to the IO reactor - see <a href="#fio_attach"><code>fio_attach</code></a>.</p> |
| |
| <h4 id="fio_is_valid"><code>fio_is_valid</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_is_valid</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns 1 if the uuid refers to a valid and open, socket.</p> |
| |
| <p>Returns 0 if not.</p> |
| |
| <h4 id="fio_is_closed"><code>fio_is_closed</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_is_closed</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns 1 if the uuid is invalid or the socket is flagged to be closed.</p> |
| |
| <p>Returns 0 if the socket is valid, open and isn't flagged to be closed.</p> |
| |
| <h4 id="fio_close"><code>fio_close</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_close</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_close</code> marks the connection for disconnection once all the data was sent. The actual disconnection will be managed by the <a href="#fio_flush"><code>fio_flush</code></a> function.</p> |
| |
| <p><a href="#fio_flash"><code>fio_flash</code></a> will be automatically scheduled.</p> |
| |
| <h4 id="fio_force_close"><code>fio_force_close</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_force_close</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_force_close</code> closes the connection immediately, without adhering to any protocol restrictions and without sending any remaining data in the connection buffer.</p> |
| |
| <h4 id="fio_set_non_block"><code>fio_set_non_block</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_set_non_block</span><span class="p">(</span><span class="kt">int</span> <span class="n">fd</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Sets a socket to non blocking state.</p> |
| |
| <p>This will also set the <code>O_CLOEXEC</code> flag for the file descriptor.</p> |
| |
| <p>This function is called automatically for the new socket, when using |
| <code>fio_socket</code>, <code>fio_accept</code>, <code>fio_listen</code> or <code>fio_connect</code>.</p> |
| |
| <p>Call this function before attaching an <code>fd</code> that was created outside of facil.io.</p> |
| |
| <h4 id="fio_peer_addr"><code>fio_peer_addr</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_str_info_s</span> <span class="n">fio_peer_addr</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the information available about the socket's peer address.</p> |
| |
| <p>If no information is available, the structure will be initialized with zero (<code>.data == NULL</code>).</p> |
| |
| <p>The information is only available when the socket was accepted using <code>fio_accept</code> or opened using <code>fio_connect</code>.</p> |
| |
| <h4 id="the-fio_str_info_s-return-value">The <code>fio_str_info_s</code> return value</h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">fio_str_info_s</span> <span class="p">{</span> |
| <span class="kt">size_t</span> <span class="n">capa</span><span class="p">;</span> <span class="cm">/* Buffer capacity, if the string is writable. */</span> |
| <span class="kt">size_t</span> <span class="n">len</span><span class="p">;</span> <span class="cm">/* String length. */</span> |
| <span class="kt">char</span> <span class="o">*</span><span class="n">data</span><span class="p">;</span> <span class="cm">/* Pointer to the string's first byte. */</span> |
| <span class="p">}</span> <span class="n">fio_str_info_s</span><span class="p">;</span> |
| </code></pre></div> |
| <p>A string information type, reports information about a C string.</p> |
| |
| <h3 id="reading-writing">Reading / Writing</h3> |
| |
| <h4 id="fio_read"><code>fio_read</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">ssize_t</span> <span class="n">fio_read</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_read</code> attempts to read up to count bytes from the socket into the buffer starting at <code>buffer</code>.</p> |
| |
| <p><code>fio_read</code>'s return values are wildly different then the native return values and they aim at making far simpler sense.</p> |
| |
| <p><code>fio_read</code> returns the number of bytes read (0 is a valid return value which simply means that no bytes were read from the buffer).</p> |
| |
| <p>On a fatal connection error that leads to the connection being closed (or if the connection is already closed), <code>fio_read</code> returns -1.</p> |
| |
| <p>The value 0 is the valid value indicating no data was read.</p> |
| |
| <p>Data might be available in the kernel's buffer while it is not available to be read using <code>fio_read</code> (i.e., when using a transport layer, such as TLS, with Read/Write hooks).</p> |
| |
| <h4 id="fio_write2"><code>fio_write2</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">ssize_t</span> <span class="n">fio_write2_fn</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_write_args_s</span> <span class="n">options</span><span class="p">);</span> |
| <span class="cp">#define fio_write2(uuid, ...) \ |
| fio_write2_fn(uuid, (fio_write_args_s){__VA_ARGS__}) |
| </span></code></pre></div> |
| <p>Schedules data to be written to the socket.</p> |
| |
| <p><code>fio_write2</code> is similar to <code>fio_write</code>, except that it allows far more flexibility.</p> |
| |
| <p><strong>Note</strong>: The data is "moved" to the ownership of the socket, not copied. By default, <code>free</code> (not <code>fio_free</code> will be called to deallocate the data. This can be controlled by the <code>.after.dealloc</code> function pointer argument.</p> |
| |
| <p>The following arguments are supported (in addition to the <code>uuid</code> argument):</p> |
| |
| <ul> |
| <li><p><code>data.buffer</code> OR <code>data.fd</code>:</p> |
| |
| <p>The data to be sent. This can be either a block of memory or a file descriptor.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| union { |
| /** The in-memory data to be sent. */ |
| const void *buffer; |
| /** The data to be sent, if this is a file. */ |
| const intptr_t fd; |
| } data; |
| </code></pre></div></li> |
| <li><p><code>after.dealloc</code> OR <code>after.close</code>:</p> |
| |
| <p>The deallocation function. This function will be called to either free the memory of close the file once the data was sent.</p> |
| |
| <p>The default for memory is the system's <code>free</code> and for files the system <code>close</code> is called (using a wrapper function).</p> |
| |
| <p>A no-operation (do nothing) function is provided for sending static data: <code>FIO_DEALLOC_NOOP</code>. Use this: <code>.after.dealloc = FIO_DEALLOC_NOOP</code></p> |
| |
| <p>Note: connection library functions MUST NEVER be called by a callback, or a deadlock might occur.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| union { |
| void (*dealloc)(void *buffer); |
| void (*close)(intptr_t fd); |
| } after; |
| </code></pre></div></li> |
| <li><p><code>length</code>:</p> |
| |
| <p>The length (size) of the buffer, or the amount of data to be sent from the file descriptor.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| uintptr_t length; |
| </code></pre></div></li> |
| <li><p><code>offset</code>:</p> |
| |
| <p>Starting point offset from the buffer or file descriptor's beginning.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| uintptr_t offset; |
| </code></pre></div></li> |
| <li><p><code>urgent</code>:</p> |
| |
| <p>The data will be sent as soon as possible, moving forward in the connection's queue as much as possible without fragmenting other <code>fio_write2</code> calls.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| unsigned urgent : 1; |
| </code></pre></div></li> |
| <li><p><code>is_fd</code>:</p> |
| |
| <p>The <code>data</code> union contains the value of a file descriptor (<code>intptr_t</code>). i.e.: <code>.data.fd = fd</code> or <code>.data.buffer = (void*)fd;</code></p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| unsigned is_fd : 1; |
| </code></pre></div></li> |
| </ul> |
| |
| <p>On error, -1 will be returned. Otherwise returns 0.</p> |
| |
| <h4 id="fio_write"><code>fio_write</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">ssize_t</span> <span class="n">fio_write</span><span class="p">(</span><span class="k">const</span> <span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> |
| <span class="k">const</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_write</code> copies <code>legnth</code> data from the buffer and schedules the data to |
| be sent over the socket.</p> |
| |
| <p>On error, -1 will be returned. Otherwise returns 0.</p> |
| |
| <p>Returns the same values as <code>fio_write2</code> and is equivalent to:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">ssize_t</span> <span class="nf">fio_write</span><span class="p">(</span><span class="k">const</span> <span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> |
| <span class="k">const</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">)</span> <span class="p">{</span> |
| <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">length</span> <span class="o">||</span> <span class="o">!</span><span class="n">buffer</span><span class="p">)</span> |
| <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> |
| <span class="kt">void</span> <span class="o">*</span><span class="n">cpy</span> <span class="o">=</span> <span class="n">fio_malloc</span><span class="p">(</span><span class="n">length</span><span class="p">);</span> |
| <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">cpy</span><span class="p">)</span> |
| <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> |
| <span class="n">memcpy</span><span class="p">(</span><span class="n">cpy</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">length</span><span class="p">);</span> |
| <span class="k">return</span> <span class="n">fio_write2</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">cpy</span><span class="p">,</span> <span class="p">.</span><span class="n">length</span> <span class="o">=</span> <span class="n">length</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">after</span><span class="p">.</span><span class="n">dealloc</span> <span class="o">=</span> <span class="n">fio_free</span><span class="p">);</span> |
| <span class="p">}</span> |
| </code></pre></div> |
| <h4 id="fio_sendfile"><code>fio_sendfile</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="k">static</span> <span class="kt">ssize_t</span> <span class="n">fio_sendfile</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="n">source_fd</span><span class="p">,</span> |
| <span class="kt">off_t</span> <span class="n">offset</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Sends data from a file as if it were a single atomic packet (sends up to <code>length</code> bytes or until EOF is reached).</p> |
| |
| <p>Once the file was sent, the <code>source_fd</code> will be closed using <code>close</code>.</p> |
| |
| <p>The file will be buffered to the socket chunk by chunk, so that memory consumption is capped. The system's <code>sendfile</code> might be used if conditions permit.</p> |
| |
| <p><code>offset</code> dictates the starting point for the data to be sent and length sets the maximum amount of data to be sent.</p> |
| |
| <p>Returns -1 and closes the file on error. Returns 0 on success.</p> |
| |
| <p>Returns the same values as <code>fio_write2</code> and is equivalent to:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">ssize_t</span> <span class="nf">fio_sendfile</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="n">source_fd</span><span class="p">,</span> |
| <span class="kt">off_t</span> <span class="n">offset</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">)</span> <span class="p">{</span> |
| <span class="k">return</span> <span class="n">fio_write2</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">fd</span> <span class="o">=</span> <span class="n">source_fd</span><span class="p">,</span> <span class="p">.</span><span class="n">length</span> <span class="o">=</span> <span class="n">length</span><span class="p">,</span> <span class="p">.</span><span class="n">is_fd</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">offset</span> <span class="o">=</span> <span class="n">offset</span><span class="p">);</span> |
| <span class="p">}</span> |
| </code></pre></div> |
| <h4 id="fio_pending"><code>fio_pending</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">size_t</span> <span class="n">fio_pending</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the number of <code>fio_write</code> calls that are waiting in the connection's queue and haven't been processed.</p> |
| |
| <h4 id="fio_flush"><code>fio_flush</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">ssize_t</span> <span class="n">fio_flush</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_flush</code> attempts to write any remaining data in the internal buffer to the underlying file descriptor and closes the underlying file descriptor once if it's marked for closure (and all the data was sent).</p> |
| |
| <p>Return values: 1 will be returned if data remains in the buffer. 0 will be returned if the buffer was fully drained. -1 will be returned on an error or when the connection is closed.</p> |
| |
| <p><code>errno</code> will be set to EWOULDBLOCK if the socket's lock is busy.</p> |
| |
| <h4 id="fio_flush_strong"><code>fio_flush_strong</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_flush_strong(uuid) \ |
| do { \ |
| errno = 0; \ |
| } while (fio_flush(uuid) > 0 || errno == EWOULDBLOCK) |
| </span></code></pre></div> |
| <p>Blocks until all the data was flushed from the buffer.</p> |
| |
| <h4 id="fio_flush_all"><code>fio_flush_all</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">size_t</span> <span class="n">fio_flush_all</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_flush_all</code> attempts flush all the open connections.</p> |
| |
| <p>Returns the number of sockets still in need to be flushed.</p> |
| |
| <h4 id="fio_uuid2fd"><code>fio_uuid2fd</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_uuid2fd(uuid) ((int)((uintptr_t)uuid >> 8)) |
| </span></code></pre></div> |
| <p>Convert between a facil.io connection's identifier (uuid) and system's fd.</p> |
| |
| <h4 id="fio_fd2uuid"><code>fio_fd2uuid</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">intptr_t</span> <span class="n">fio_fd2uuid</span><span class="p">(</span><span class="kt">int</span> <span class="n">fd</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_fd2uuid</code> takes an existing file decriptor <code>fd</code> and returns it's active <code>uuid</code>.</p> |
| |
| <p>If the file descriptor was closed, <strong>it will be registered as open</strong>.</p> |
| |
| <p>If the file descriptor was closed directly (not using <code>fio_close</code>) or the closure event hadn't been processed, a false positive will be possible.</p> |
| |
| <p>This is not an issue, since the use of an invalid fd will result in the registry being updated and the fd being closed.</p> |
| |
| <p>Returns -1 on error. Returns a valid socket (non-random) UUID.</p> |
| |
| <h3 id="connection-object-links">Connection Object Links</h3> |
| |
| <p>Connection object links can links an object to a connection's lifetime rather than it's Protocol's lifetime.</p> |
| |
| <p>This is can be useful and is used internally by the <code>fio_subscribe</code> function to attach subscriptions to connections (when requested).</p> |
| |
| <h4 id="fio_uuid_link"><code>fio_uuid_link</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_uuid_link</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">obj</span><span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">on_close</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="n">obj</span><span class="p">));</span> |
| </code></pre></div> |
| <p>Links an object to a connection's lifetime, calling the <code>on_close</code> callback once the connection has died.</p> |
| |
| <p>If the <code>uuid</code> is invalid, the <code>on_close</code> callback will be called immediately.</p> |
| |
| <p><strong>Note</strong>: the <code>on_close</code> callback will be called with high priority. Long tasks should be deferred using <a href="#fio_defer"><code>fio_defer</code></a>.</p> |
| |
| <h4 id="fio_uuid_unlink"><code>fio_uuid_unlink</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_uuid_unlink</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">obj</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Un-links an object from the connection's lifetime, so it's <code>on_close</code> callback will NOT be called.</p> |
| |
| <h3 id="lower-level-read-write-close-hooks">Lower-Level: Read / Write / Close Hooks</h3> |
| |
| <p>facil.io's behavior can be altered to support complex networking needs, such as SSL/TLS integration.</p> |
| |
| <p>This can be achieved using connection hooks for the common read/write/close operations.</p> |
| |
| <p>To do so, a <code>fio_rw_hook_s</code> object must be created (a static object can be used as well).</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">fio_rw_hook_s</span> <span class="p">{</span> |
| <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">read</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">);</span> |
| <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">write</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">);</span> |
| <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">flush</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span> |
| <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">before_close</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span> |
| <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">cleanup</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span> |
| <span class="p">}</span> <span class="n">fio_rw_hook_s</span><span class="p">;</span> |
| </code></pre></div> |
| <ul> |
| <li><p>The <code>read</code> hook callback:</p> |
| |
| <p>This callback should implement the reading function from the file descriptor. It must behave the same as the system's <code>read</code> call, including the setting <code>errno</code> to <code>EAGAIN</code> / <code>EWOULDBLOCK</code>.</p> |
| |
| <p>Note: facil.io library functions MUST NEVER be called by any r/w hook, or a deadlock might occur.</p></li> |
| <li><p>The <code>write</code> hook callback:</p> |
| |
| <p>This callback should implement the writing function to the file descriptor. It must behave like the file system's <code>write</code> call, including the setting <code>errno</code> to <code>EAGAIN</code> / <code>EWOULDBLOCK</code>.</p> |
| |
| <p>The function is expected to call the <code>flush</code> callback (or it's logic) internally. Either <code>write</code> <strong>or</strong> <code>flush</code> are called, but not both.</p> |
| |
| <p>Note: facil.io library functions MUST NEVER be called by any r/w hook, or a deadlock might occur.</p></li> |
| <li><p>The <code>flush</code> hook callback:</p> |
| |
| <p>When implemented, this function will be called to flush any data remaining in the read/write hook's internal buffer.</p> |
| |
| <p>This callback should return the number of bytes remaining in the internal buffer (0 is a valid response) or -1 (on error).</p> |
| |
| <p>Note: facil.io library functions MUST NEVER be called by any r/w hook, or a deadlock might occur.</p></li> |
| <li><p>The <code>before_close</code> hook callback:</p> |
| |
| <p>The <code>before_close</code> callback is called only once before closing the <code>uuid</code> and it might not get called if an abnormal closure is detected.</p> |
| |
| <p>If the function returns a non-zero value, than closure will be delayed until the <code>flush</code> returns 0 (or less). This allows a closure signal to be sent by the read/write hook when such a signal is required.</p> |
| |
| <p>Note: facil.io library functions MUST NEVER be called by any r/w hook, or a deadlock might occur.</p></li> |
| <li><p>The <code>cleanup</code> hook callback:</p> |
| |
| <p>Called when the hook is removed from the <code>uuid</code>, either because of a call to <code>fio_rw_hook_set</code> or because the connection was closed.</p> |
| |
| <p>This callback is always called, even if <code>fio_rw_hook_set</code> fails.</p></li> |
| </ul> |
| |
| <h4 id="fio_rw_hook_set"><code>fio_rw_hook_set</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_rw_hook_set</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_rw_hook_s</span> <span class="o">*</span><span class="n">rw_hooks</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Sets a connection's hook callback object (<code>fio_rw_hook_s</code>).</p> |
| |
| <p>Returns 0 on success or -1 on error (closed / invalid <code>uuid</code>).</p> |
| |
| <p>If the function fails, than the <code>cleanup</code> callback will be called before the function returns.</p> |
| |
| <h4 id="fio_rw_hook_replace_unsafe"><code>fio_rw_hook_replace_unsafe</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_rw_hook_replace_unsafe</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_rw_hook_s</span> <span class="o">*</span><span class="n">rw_hooks</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Replaces an existing read/write hook with another from within a read/write hook callback.</p> |
| |
| <p>Returns 0 on success or -1 on error (closed / invalid <code>uuid</code>).</p> |
| |
| <p>Does NOT call any cleanup callbacks.</p> |
| |
| <p>Replaces existing <code>udata</code>. Call with the existing <code>udata</code> to keep it.</p> |
| |
| <p><strong>Note</strong>: this function is marked as unsafe, since it should only be called from within an existing read/write hook callback. Otherwise, data corruption might occur.</p> |
| |
| <h4 id="fio_default_rw_hooks"><code>FIO_DEFAULT_RW_HOOKS</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">extern</span> <span class="k">const</span> <span class="n">fio_rw_hook_s</span> <span class="n">FIO_DEFAULT_RW_HOOKS</span><span class="p">;</span> |
| </code></pre></div> |
| <p>The default Read/Write hooks used for system Read/Write (<code>udata</code> == <code>NULL</code>).</p> |
| |
| <h2 id="event-task-scheduling">Event / Task scheduling</h2> |
| |
| <p>facil.io allows a number of ways to schedule events / tasks:</p> |
| |
| <ul> |
| <li><p>Queue - schedules an event / task to be performed as soon as possible.</p></li> |
| <li><p>Timer - the event / task will be scheduled in the Queue after the designated period.</p></li> |
| <li><p>State - the event / task will be called during a specific change in facil.io's state (starting up, cleaning up, etc').</p></li> |
| </ul> |
| |
| <h3 id="the-task-queue-functions">The Task Queue Functions</h3> |
| |
| <h4 id="fio_defer"><code>fio_defer</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_defer</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">task</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="p">),</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata1</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata2</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Defers a task's execution.</p> |
| |
| <p>The task will be executed after all currently scheduled tasks (placed at the end of the scheduling queue).</p> |
| |
| <p>Tasks are functions of the type <code>void task(void *, void *)</code>, they return nothing (void) and accept two opaque <code>void *</code> pointers, user-data 1 (<code>udata1</code>) and user-data 2 (<code>udata2</code>).</p> |
| |
| <p>Returns -1 or error, 0 on success.</p> |
| |
| <h4 id="fio_defer_perform"><code>fio_defer_perform</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_defer_perform</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Performs all deferred tasks.</p> |
| |
| <h4 id="fio_defer_has_queue"><code>fio_defer_has_queue</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_defer_has_queue</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns true if there are deferred functions waiting for execution.</p> |
| |
| <h3 id="timer-functions">Timer Functions</h3> |
| |
| <h4 id="fio_run_every"><code>fio_run_every</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_run_every</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">milliseconds</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">repetitions</span><span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">task</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">),</span> |
| <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">on_finish</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">));</span> |
| </code></pre></div> |
| <p>Creates a timer to run a task at the specified interval.</p> |
| |
| <p>Timer tasks accept only a single user data pointer (<code>udata</code> ).</p> |
| |
| <p>The task will repeat <code>repetitions</code> times. If <code>repetitions</code> is set to 0, task |
| will repeat forever.</p> |
| |
| <p>The <code>on_finish</code> handler is always called (even on error).</p> |
| |
| <p>Returns -1 on error.</p> |
| |
| <h3 id="connection-task-scheduling">Connection task scheduling</h3> |
| |
| <p>Connection tasks are performed within one of the connection's locks (<code>FIO_PR_LOCK_TASK</code>, <code>FIO_PR_LOCK_WRITE</code>, <code>FIO_PR_LOCK_STATE</code>), assuring a measure of safety.</p> |
| |
| <h4 id="fio_defer_io_task"><code>fio_defer_io_task</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_defer_io_task</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">fio_defer_iotask_args_s</span> <span class="n">args</span><span class="p">);</span> |
| <span class="cp">#define fio_defer_io_task(uuid, ...) \ |
| fio_defer_connection_task((uuid), (fio_defer_iotask_args_s){__VA_ARGS__}) |
| </span></code></pre></div> |
| <p>This function schedules an IO task using the specified lock type.</p> |
| |
| <p>This function is shadowed by a macro, allowing it to accept named arguments, much like <a href="#fio_start">fio_start</a>. The following arguments are recognized:</p> |
| |
| <ul> |
| <li><p><code>type</code>:</p> |
| |
| <p>The type of lock that should be used to protect the IO task. Defaults to <code>FIO_PR_LOCK_TASK</code> (see later).</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| enum fio_protocol_lock_e type; |
| </code></pre></div></li> |
| <li><p><code>task</code>:</p> |
| |
| <p>The task (function) to be performed. The tasks accepts the connection's <code>uuid</code>, a pointer to the protocol object and the opaque <code>udata</code> pointer passed to <code>fio_defer_io_task</code>.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// Callback example: |
| void task(intptr_t uuid, fio_protocol_s *, void *udata); |
| </code></pre></div></li> |
| <li><p><code>fallback</code>:</p> |
| |
| <p>A fallback task (function) to be performed in cases where the <code>uuid</code> isn't valid by the time the task should be executed. The fallback task accepts the connection's <code>uuid</code> and the opaque <code>udata</code> pointer passed to <code>fio_defer_io_task</code>.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// Callback example: |
| void fallback(intptr_t uuid, void *udata); |
| </code></pre></div></li> |
| <li><p><code>udata</code>:</p> |
| |
| <p>An opaque pointer that's passed along to the task.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| void *udata; |
| </code></pre></div></li> |
| </ul> |
| |
| <p>Lock types are one of the following:</p> |
| |
| <ul> |
| <li><p><code>FIO_PR_LOCK_TASK</code> - a task lock locks might change data owned by the protocol object. This task is used for tasks such as <code>on_data</code>.</p></li> |
| <li><p><code>FIO_PR_LOCK_WRITE</code> - a lock that promises only to use static data (data that tasks never changes) in order to write to the underlying socket. This lock is used for tasks such as <code>on_ready</code> and <code>ping</code></p></li> |
| <li><p><code>FIO_PR_LOCK_STATE</code> - a lock that promises only to retrieve static data (data that tasks never changes), performing no actions. This usually isn't used for client side code (used internally by facil) and is only meant for very short locks.</p></li> |
| </ul> |
| |
| <h3 id="startup-state-tasks-fork-start-up-idle-etc">Startup / State Tasks (fork, start up, idle, etc')</h3> |
| |
| <p>facil.io allows callbacks to be called when certain events occur (such as before and after forking etc').</p> |
| |
| <p>Callbacks will be called from last to first (last callback added executes first), allowing for logical layering of dependencies.</p> |
| |
| <p>During an event, changes to the callback list are ignored (callbacks can't remove other callbacks for the same event).</p> |
| |
| <h4 id="callback_type_e-state-callback-timing-type"><code>callback_type_e</code>- State callback timing type</h4> |
| |
| <p>The <code>fio_state_callback_*</code> functions manage callbacks for a specific timing. Valid timings values are:</p> |
| |
| <ul> |
| <li><p><code>FIO_CALL_ON_INITIALIZE</code>: Called once during library initialization.</p></li> |
| <li><p><code>FIO_CALL_PRE_START</code>: Called once before starting up the IO reactor.</p></li> |
| <li><p><code>FIO_CALL_BEFORE_FORK</code>: Called before each time the IO reactor forks a new worker.</p></li> |
| <li><p><code>FIO_CALL_AFTER_FORK</code>: Called after each fork (both in parent and workers).</p></li> |
| <li><p><code>FIO_CALL_IN_CHILD</code>: Called by a worker process right after forking (and after <code>FIO_CALL_AFTER_FORK</code>).</p></li> |
| <li><p><code>FIO_CALL_IN_MASTER</code>: Called by the root / master process after forking (and after <code>FIO_CALL_AFTER_FORK</code>).</p></li> |
| <li><p><code>FIO_CALL_ON_START</code>: Called every time a <em>Worker</em> proceess starts.</p></li> |
| <li><p><code>FIO_CALL_ON_IDLE</code>: Called when facil.io enters idling mode (idle callbacks might be performed out of order).</p></li> |
| <li><p><code>FIO_CALL_ON_SHUTDOWN</code>: Called before starting the shutdown sequence.</p></li> |
| <li><p><code>FIO_CALL_ON_FINISH</code>: Called just before finishing up (both on chlid and parent processes).</p></li> |
| <li><p><code>FIO_CALL_ON_PARENT_CRUSH</code>: Called by each worker the moment it detects the master process crashed.</p></li> |
| <li><p><code>FIO_CALL_ON_CHILD_CRUSH</code>: Called by the parent (master) after a worker process crashed.</p></li> |
| <li><p><code>FIO_CALL_AT_EXIT</code>: An alternative to the system's at_exit.</p></li> |
| </ul> |
| |
| <p>Callbacks will be called using logical order for build-up and tear-down.</p> |
| |
| <p>During initialization related events, FIFO will be used (first in/scheduled, first out/executed).</p> |
| |
| <p>During shut-down related tasks, LIFO will be used (last in/scheduled, first out/executed).</p> |
| |
| <p>Idling callbacks are scheduled rather than performed during the event, so they might be performed out of order or concurrently when running in multi-threaded mode.</p> |
| |
| <h4 id="fio_state_callback_add"><code>fio_state_callback_add</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_state_callback_add</span><span class="p">(</span><span class="n">callback_type_e</span><span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">func</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">),</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Adds a callback to the list of callbacks to be called for the event.</p> |
| |
| <p>Callbacks will be called using logical order for build-up and tear-down, according to the event's context.</p> |
| |
| <h4 id="fio_state_callback_remove"><code>fio_state_callback_remove</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_state_callback_remove</span><span class="p">(</span><span class="n">callback_type_e</span><span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">func</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">),</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes a callback from the list of callbacks to be called for the event.</p> |
| |
| <p>Callbacks will be called using logical order for build-up and tear-down, according to the event's context.</p> |
| |
| <h4 id="fio_state_callback_force"><code>fio_state_callback_force</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_state_callback_force</span><span class="p">(</span><span class="n">callback_type_e</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Forces all the existing callbacks to run, as if the event occurred.</p> |
| |
| <p>Callbacks will be called using logical order for build-up and tear-down, according to the event's context.</p> |
| |
| <p>During an event, changes to the callback list are ignored (callbacks can't remove other callbacks for the same event).</p> |
| |
| <h4 id="fio_state_callback_clear"><code>fio_state_callback_clear</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_state_callback_clear</span><span class="p">(</span><span class="n">callback_type_e</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Clears all the existing callbacks for the event (doesn't effect a currently firing event).</p> |
| |
| <h2 id="pub-sub-services">Pub/Sub Services</h2> |
| |
| <p>facil.io supports a <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">Publish–Subscribe Pattern</a> API which can be used for Inter Process Communication (IPC), messaging, horizontal scaling and similar use-cases.</p> |
| |
| <h3 id="subscription-control">Subscription Control</h3> |
| |
| <h4 id="fio_subscribe"><code>fio_subscribe</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">subscription_s</span> <span class="o">*</span><span class="n">fio_subscribe</span><span class="p">(</span><span class="n">subscribe_args_s</span> <span class="n">args</span><span class="p">);</span> |
| <span class="cp">#define fio_subscribe(...) fio_subscribe((subscribe_args_s){__VA_ARGS__}) |
| </span></code></pre></div> |
| <p>This function subscribes to either a numerical "filter" or a named channel (but not both).</p> |
| |
| <p>The <code>fio_subscribe</code> function is shadowed by the <code>fio_subscribe</code> MACRO, which allows the function to accept "named arguments", as shown in the following example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">static</span> <span class="kt">void</span> <span class="n">my_message_handler</span><span class="p">(</span><span class="n">fio_msg_s</span> <span class="o">*</span><span class="n">msg</span><span class="p">);</span> |
| <span class="c1">//...</span> |
| <span class="n">subscription_s</span> <span class="o">*</span> <span class="n">s</span> <span class="o">=</span> <span class="n">fio_subscribe</span><span class="p">(.</span><span class="n">channel</span> <span class="o">=</span> <span class="p">{.</span><span class="n">data</span><span class="o">=</span><span class="s">"name"</span><span class="p">,</span> <span class="p">.</span><span class="n">len</span> <span class="o">=</span> <span class="mi">4</span><span class="p">},</span> |
| <span class="p">.</span><span class="n">on_message</span> <span class="o">=</span> <span class="n">my_message_handler</span><span class="p">);</span> |
| </code></pre></div> |
| <p>The function accepts the following named arguments:</p> |
| |
| <ul> |
| <li><p><code>filter</code>:</p> |
| |
| <p>If <code>filter</code> is set, all messages that match the filter's numerical value will be forwarded to the subscription's callback.</p> |
| |
| <p>Subscriptions can either require a match by filter or match by channel. This will match the subscription by filter.</p> |
| |
| <p><strong>Note</strong>: filter based messages are considered internal. They aren't shared with external pub/sub services (such as Redis) and they are ignored by meta-data callbacks (both subjects are covered later on).</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| int32_t filter; |
| </code></pre></div></li> |
| <li><p><code>channel</code>:</p> |
| |
| <p>If <code>filter == 0</code> (or unset), than the subscription will be made using <code>channel</code> binary name matching. Note that and empty string (NULL pointer and 0 length) is a valid channel name.</p> |
| |
| <p>Subscriptions can either require a match by filter or match by channel. This will match the subscription by channel (only messages with no <code>filter</code> will be received).</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| fio_str_info_s channel; |
| </code></pre></div></li> |
| <li><p><code>match</code>:</p> |
| |
| <p>If an optional <code>match</code> callback is provided, pattern matching will be used as an alternative to exact channel name matching.</p> |
| |
| <p>A single matching function is bundled with facil.io (<code>FIO_MATCH_GLOB</code>), which follows the Redis matching logic.</p> |
| |
| <p>This is significantly slower, as no Hash Map can be used to locate a match - each message published to a channel will be tested for a match against each pattern.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// callback example: |
| int foo_bar_match_fn(fio_str_info_s pattern, fio_str_info_s channel); |
| // type: |
| typedef int (*fio_match_fn)(fio_str_info_s pattern, fio_str_info_s channel); |
| fio_match_fn match; |
| extern fio_match_fn FIO_MATCH_GLOB; |
| </code></pre></div></li> |
| <li><p><code>on_message</code>:</p> |
| |
| <p>The callback will be called for each message forwarded to the subscription.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// callback example: |
| void on_message(fio_msg_s *msg); |
| </code></pre></div></li> |
| <li><p><code>on_unsubscribe</code>:</p> |
| |
| <p>The callback will be called once the subscription is canceled, allowing it's resources to be freed.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// callback example: |
| void (*on_unsubscribe)(void *udata1, void *udata2); |
| </code></pre></div></li> |
| <li><p><code>udata1</code> and <code>udata2</code>:</p> |
| |
| <p>These are the opaque user data pointers passed to <code>on_message</code> and <code>on_unsubscribe</code>.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| void *udata1; |
| void *udata2; |
| </code></pre></div></li> |
| </ul> |
| |
| <p>The function returns a pointer to the opaque subscription type <code>subscription_s</code>.</p> |
| |
| <p>On error, <code>NULL</code> will be returned and the <code>on_unsubscribe</code> callback will be called.</p> |
| |
| <p>The <code>on_message</code> should accept a pointer to the <code>fio_msg_s</code> type:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">fio_msg_s</span> <span class="p">{</span> |
| <span class="kt">int32_t</span> <span class="n">filter</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">;</span> |
| <span class="n">fio_str_info_s</span> <span class="n">msg</span><span class="p">;</span> |
| <span class="kt">void</span> <span class="o">*</span><span class="n">udata1</span><span class="p">;</span> |
| <span class="kt">void</span> <span class="o">*</span><span class="n">udata2</span><span class="p">;</span> |
| <span class="kt">uint8_t</span> <span class="n">is_json</span><span class="p">;</span> |
| <span class="p">}</span> <span class="n">fio_msg_s</span><span class="p">;</span> |
| </code></pre></div> |
| <ul> |
| <li><p><code>filter</code> is the numerical filter (if any) used in the <code>fio_subscribe</code> and <code>fio_publish</code> functions. Negative values are reserved and 0 == channel name matching.</p></li> |
| <li><p><code>channel</code> is an immutable binary string containing the channel name given to <code>fio_publish</code>. See the <a href="%60#the-fio_str_info_s-return-value%60"><code>fio_str_info_s</code> return value</a> for details.</p></li> |
| <li><p><code>msg</code> is an immutable binary string containing the message data given to <code>fio_publish</code>. See the <a href="%60#the-fio_str_info_s-return-value%60"><code>fio_str_info_s</code> return value</a> for details.</p></li> |
| <li><p><code>is_json</code> is a binary flag (1 or 0) that marks the message as JSON. This is the flag passed as passed to the <code>fio_publish</code> function.</p></li> |
| <li><p><code>udata1</code> and <code>udata2</code> are the opaque user data pointers passed to <code>fio_subscribe</code> during the subscription.</p></li> |
| </ul> |
| |
| <p><strong>Note (1)</strong>: if a subscription object is no longer required, i.e., if <code>fio_unsubscribe</code> will only be called once a connection was closed or once facil.io is shutting down, consider using <a href="#fio_uuid_link"><code>fio_uuid_link</code></a> or <a href="#fio_state_callback_add"><code>fio_state_callback_add</code></a> to control the subscription's lifetime.</p> |
| |
| <p><strong>Note (2)</strong>: passing protocol object pointers to the <code>udata</code> is not safe, since protocol objects might be destroyed or invalidated due to either network events (socket closure) or internal changes (i.e., <code>fio_attach</code> being called). The preferred way is to add the <code>uuid</code> to the <code>udata</code> field and call <a href="#fio_protocol_try_lock"><code>fio_protocol_try_lock</code></a> to access the protocol object.</p> |
| |
| <h4 id="fio_subscription_channel"><code>fio_subscription_channel</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_str_info_s</span> <span class="n">fio_subscription_channel</span><span class="p">(</span><span class="n">subscription_s</span> <span class="o">*</span><span class="n">subscription</span><span class="p">);</span> |
| </code></pre></div> |
| <p>This helper returns a temporary String with the subscription's channel (or a binary |
| string representing the filter).</p> |
| |
| <p>To keep the string beyond the lifetime of the subscription, copy the string.</p> |
| |
| <h4 id="fio_message_defer"><code>fio_message_defer</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_message_defer</span><span class="p">(</span><span class="n">fio_msg_s</span> <span class="o">*</span><span class="n">msg</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Defers the subscription's callback handler, so the subscription will be called again for the same message.</p> |
| |
| <p>A classic use case allows facil.io to handle other events while waiting on a lock / mutex to become available in a multi-threaded environment.</p> |
| |
| <h4 id="fio_unsubscribe"><code>fio_unsubscribe</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_unsubscribe</span><span class="p">(</span><span class="n">subscription_s</span> <span class="o">*</span><span class="n">subscription</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Cancels an existing subscription.</p> |
| |
| <p>This function will block if a subscription task is running on a different thread.</p> |
| |
| <p>The subscription task won't be called after the function returns.</p> |
| |
| <h3 id="publishing-messages">Publishing messages</h3> |
| |
| <h4 id="fio_publish"><code>fio_publish</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_publish</span><span class="p">(</span><span class="n">fio_publish_args_s</span> <span class="n">args</span><span class="p">);</span> |
| </code></pre></div> |
| <p>This function publishes a message to either a numerical "filter" or a named channel (but not both).</p> |
| |
| <p>The message can be a <code>NULL</code> or an empty message.</p> |
| |
| <p>The <code>fio_publish</code> function is shadowed by the <code>fio_publish</code> MACRO, which allows the function to accept "named arguments", as shown in the following example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_publish</span><span class="p">(.</span><span class="n">channel</span> <span class="o">=</span> <span class="p">{.</span><span class="n">data</span><span class="o">=</span><span class="s">"name"</span><span class="p">,</span> <span class="p">.</span><span class="n">len</span> <span class="o">=</span> <span class="mi">4</span><span class="p">},</span> |
| <span class="p">.</span><span class="n">message</span> <span class="o">=</span> <span class="p">{.</span><span class="n">data</span> <span class="o">=</span> <span class="s">"foo"</span><span class="p">,</span> <span class="p">.</span><span class="n">len</span> <span class="o">=</span> <span class="mi">3</span><span class="p">});</span> |
| </code></pre></div> |
| <p>The function accepts the following named arguments:</p> |
| |
| <ul> |
| <li><p><code>filter</code>:</p> |
| |
| <p>If <code>filter</code> is set, all messages that match the filter's numerical value will be forwarded to the subscription's callback.</p> |
| |
| <p>Subscriptions can either require a match by filter or match by channel. This will match the subscription by filter.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| int32_t filter; |
| </code></pre></div></li> |
| <li><p><code>channel</code>:</p> |
| |
| <p>If <code>filter == 0</code> (or unset), than the subscription will be made using <code>channel</code> binary name matching. Note that and empty string (NULL pointer and 0 length) is a valid channel name.</p> |
| |
| <p>Subscriptions can either require a match by filter or match by channel. This will match the subscription by channel (only messages with no <code>filter</code> will be received).</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| fio_str_info_s channel; |
| </code></pre></div></li> |
| <li><p><code>message</code>:</p> |
| |
| <p>The message data to be sent.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| fio_str_info_s message; |
| </code></pre></div></li> |
| <li><p><code>is_json</code>:</p> |
| |
| <p>A flag indicating if the message is JSON data or binary/text.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| uint8_t is_json; |
| </code></pre></div></li> |
| <li><p><code>engine</code>:</p> |
| |
| <p>The pub/sub engine that should be used to forward this message (see later). Defaults to <code>FIO_PUBSUB_DEFAULT</code> (or <code>FIO_PUBSUB_CLUSTER</code>).</p> |
| |
| <p>Pub/Sub engines dictate the behavior of the pub/sub instructions. The possible internal pub/sub engines are:</p> |
| |
| <ul> |
| <li><code>FIO_PUBSUB_CLUSTER</code> - used to publish the message to all clients in the cluster.</li> |
| <li><code>FIO_PUBSUB_PROCESS</code> - used to publish the message only within the current process.</li> |
| <li><code>FIO_PUBSUB_SIBLINGS</code> - used to publish the message except within the current process.</li> |
| <li><code>FIO_PUBSUB_ROOT</code> - used to publish the message exclusively to the root / master process.</li> |
| </ul> |
| |
| <p>The default pub/sub can be changed globally by assigning a new default engine to the <code>FIO_PUBSUB_DEFAULT</code> global variable.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>// type: |
| fio_pubsub_engine_s const *engine; |
| // default engine: |
| extern fio_pubsub_engine_s *FIO_PUBSUB_DEFAULT; |
| </code></pre></div></li> |
| </ul> |
| |
| <h3 id="pub-sub-message-middleware-meta-data">Pub/Sub Message MiddleWare Meta-Data</h3> |
| |
| <p>It's possible to attach meta-data to facil.io pub/sub messages before they are published.</p> |
| |
| <p>This is only available for named channels (filter == 0).</p> |
| |
| <p>This allows, for example, messages to be encoded as network packets for |
| outgoing protocols (i.e., encoding for WebSocket transmissions), improving |
| performance in large network based broadcasting.</p> |
| |
| <p><strong>Note</strong>: filter based messages are considered internal. They aren't shared with external pub/sub services (such as Redis) and they are ignored by meta-data callbacks.</p> |
| |
| <h4 id="fio_message_metadata"><code>fio_message_metadata</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="o">*</span><span class="n">fio_message_metadata</span><span class="p">(</span><span class="n">fio_msg_s</span> <span class="o">*</span><span class="n">msg</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="n">type_id</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Finds the message's meta-data by the meta-data's type ID. Returns the data or NULL.</p> |
| |
| <h4 id="fio_message_metadata_callback_set"><code>fio_message_metadata_callback_set</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="c1">// The function:</span> |
| <span class="kt">void</span> <span class="n">fio_message_metadata_callback_set</span><span class="p">(</span><span class="n">fio_msg_metadata_fn</span> <span class="n">callback</span><span class="p">,</span> |
| <span class="kt">int</span> <span class="n">enable</span><span class="p">);</span> |
| <span class="c1">// The callback type:</span> |
| <span class="k">typedef</span> <span class="n">fio_msg_metadata_s</span> <span class="p">(</span><span class="o">*</span><span class="n">fio_msg_metadata_fn</span><span class="p">)(</span><span class="n">fio_str_info_s</span> <span class="n">ch</span><span class="p">,</span> |
| <span class="n">fio_str_info_s</span> <span class="n">msg</span><span class="p">,</span> |
| <span class="kt">uint8_t</span> <span class="n">is_json</span><span class="p">);</span> |
| <span class="c1">// Example callback</span> |
| <span class="n">fio_msg_metadata_s</span> <span class="n">foo_metadata</span><span class="p">(</span><span class="n">fio_str_info_s</span> <span class="n">ch</span><span class="p">,</span> |
| <span class="n">fio_str_info_s</span> <span class="n">msg</span><span class="p">,</span> |
| <span class="kt">uint8_t</span> <span class="n">is_json</span><span class="p">);</span> |
| </code></pre></div> |
| <p>The callback should return a <code>fio_msg_metadata_s</code> object. The object looks like this:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">fio_msg_metadata_s</span> <span class="n">fio_msg_metadata_s</span><span class="p">;</span> |
| <span class="k">struct</span> <span class="n">fio_msg_metadata_s</span> <span class="p">{</span> |
| <span class="cm">/** A type ID used to identify the meta-data. Negative values are reserved. */</span> |
| <span class="kt">intptr_t</span> <span class="n">type_id</span><span class="p">;</span> |
| <span class="cm">/** Called by facil.io to cleanup the meta-data resources. */</span> |
| <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">on_finish</span><span class="p">)(</span><span class="n">fio_msg_s</span> <span class="o">*</span><span class="n">msg</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">metadata</span><span class="p">);</span> |
| <span class="cm">/** The pointer to be disclosed to the subscription client. */</span> |
| <span class="kt">void</span> <span class="o">*</span><span class="n">metadata</span><span class="p">;</span> |
| <span class="cm">/** RESERVED for internal use (Metadata linked list): */</span> |
| <span class="n">fio_msg_metadata_s</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> |
| <span class="p">};</span> |
| </code></pre></div> |
| <p>If the the returned <code>.metadata</code> field is NULL than the result will be ignored.</p> |
| |
| <p>To remove a callback, set the <code>enable</code> flag to false (<code>0</code>).</p> |
| |
| <p>The cluster messaging system allows some messages to be flagged as JSON and this flag is available to the meta-data callback.</p> |
| |
| <h3 id="external-pub-sub-services">External Pub/Sub Services</h3> |
| |
| <p>facil.io can be linked with external Pub/Sub services using "engines" (<code>fio_pubsub_engine_s</code>).</p> |
| |
| <p>Pub/Sub engines dictate the behavior of the pub/sub instructions. </p> |
| |
| <p>This allows for an application to connect to a service such as Redis or NATs for horizontal pub/sub scaling.</p> |
| |
| <p>A <a href="redis">Redis engine</a> is bundled as part of the facio.io extensions but isn't part of the core library.</p> |
| |
| <p>The default engine can be set using the <code>FIO_PUBSUB_DEFAULT</code> global variable. It's initial default is <code>FIO_PUBSUB_CLUSTER</code> (see <a href="#fio_publish"><code>fio_publish</code></a>).</p> |
| |
| <p><strong>Note</strong>: filter based messages are considered internal. They aren't shared with external pub/sub services (such as Redis) and they are ignored by meta-data callbacks.</p> |
| |
| <p>Engines MUST provide the listed function pointers and should be attached using the <code>fio_pubsub_attach</code> function.</p> |
| |
| <p>Engines should disconnect / detach, before being destroyed, by using the <code>fio_pubsub_detach</code> function.</p> |
| |
| <p>When an engine received a message to publish, it should call the <code>fio_publish</code> function with the engine to which the message is forwarded. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_publish</span><span class="p">(</span> |
| <span class="p">.</span><span class="n">engine</span> <span class="o">=</span> <span class="n">FIO_PROCESS_ENGINE</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">channel</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s">"name"</span><span class="p">},</span> |
| <span class="p">.</span><span class="n">message</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s">"data"</span><span class="p">}</span> <span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_pubsub_attach"><code>fio_pubsub_attach</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_pubsub_attach</span><span class="p">(</span><span class="n">fio_pubsub_engine_s</span> <span class="o">*</span><span class="n">engine</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Attaches an engine, so it's callbacks can be called by facil.io.</p> |
| |
| <p>The <code>subscribe</code> callback will be called for every existing channel.</p> |
| |
| <p>The engine type defines the following callback:</p> |
| |
| <ul> |
| <li><p><code>subscribe</code> - Should subscribe channel. Failures are ignored.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>void subscribe(const fio_pubsub_engine_s *eng, |
| fio_str_info_s channel, |
| fio_match_fn match); |
| </code></pre></div></li> |
| <li><p><code>unsubscribe</code> - Should unsubscribe channel. Failures are ignored.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>void unsubscribe(const fio_pubsub_engine_s *eng, |
| fio_str_info_s channel, |
| fio_match_fn match); |
| </code></pre></div></li> |
| <li><p><code>publish</code> - Should publish a message through the engine. Failures are ignored.</p> |
| <div class="highlight"><pre class="highlight plaintext"><code>int publish(const fio_pubsub_engine_s *eng, |
| fio_str_info_s channel, |
| fio_str_info_s msg, uint8_t is_json); |
| </code></pre></div></li> |
| </ul> |
| |
| <p><strong>Note</strong>: the root (master) process will call <code>subscribe</code> for any channel <strong>in any process</strong>, while all the other processes will call <code>subscribe</code> only for their own channels. This allows engines to use the root (master) process as an exclusive subscription process.</p> |
| |
| <p><strong>IMPORTANT</strong>: The <code>subscribe</code> and <code>unsubscribe</code> callbacks are called from within an internal lock. They MUST NEVER call pub/sub functions except by exiting the lock using <code>fio_defer</code>.</p> |
| |
| <h4 id="fio_pubsub_detach"><code>fio_pubsub_detach</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_pubsub_detach</span><span class="p">(</span><span class="n">fio_pubsub_engine_s</span> <span class="o">*</span><span class="n">engine</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Detaches an engine, so it could be safely destroyed.</p> |
| |
| <h4 id="fio_pubsub_reattach"><code>fio_pubsub_reattach</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_pubsub_reattach</span><span class="p">(</span><span class="n">fio_pubsub_engine_s</span> <span class="o">*</span><span class="n">eng</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Engines can ask facil.io to call the <code>subscribe</code> callback for all active channels.</p> |
| |
| <p>This allows engines that lost their connection to their Pub/Sub service to resubscribe all the currently active channels with the new connection.</p> |
| |
| <p>CAUTION: This is an evented task... try not to free the engine's memory while re-subscriptions are under way...</p> |
| |
| <p><strong>Note</strong>: the root (master) process will call <code>subscribe</code> for any channel <strong>in any process</strong>, while all the other processes will call <code>subscribe</code> only for their own channels. This allows engines to use the root (master) process as an exclusive subscription process.</p> |
| |
| <p><strong>IMPORTANT</strong>: The <code>subscribe</code> and <code>unsubscribe</code> callbacks are called from within an internal lock. They MUST NEVER call pub/sub functions except by exiting the lock using <code>fio_defer</code>.</p> |
| |
| <h4 id="fio_pubsub_is_attached"><code>fio_pubsub_is_attached</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_pubsub_is_attached</span><span class="p">(</span><span class="n">fio_pubsub_engine_s</span> <span class="o">*</span><span class="n">engine</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns true (1) if the engine is attached to the system.</p> |
| |
| <h2 id="the-custom-memory-allocator">The Custom Memory Allocator</h2> |
| |
| <p>facil.io includes a custom memory allocator designed for network application use.</p> |
| |
| <p>The allocator is very fast (tested with <code>tests/malloc_speed.c</code>) and protects against fragmentation issues when used correctly (when abused, fragmentation will increase).</p> |
| |
| <p>Allocated memory is always zeroed out and aligned on a 16 byte boundary.</p> |
| |
| <p>Reallocated memory is always aligned on a 16 byte boundary but it might be filled with junk data after the valid data (this can be minimized by using <a href="#fio_realloc2"><code>fio_realloc2</code></a>).</p> |
| |
| <p>Memory allocation overhead is ~ 0.1% (1/1000 per byte, or 32 bytes per 32Kb). In addition there's a small per-process overhead for the allocator's state-machine (1 page / 4Kb per process). </p> |
| |
| <p>The memory allocator assumes multiple concurrent allocation/deallocation, short to medium life spans (memory is freed shortly, but not immediately, after it was allocated) and relatively small allocations (anything over 16Kb is forwarded to <code>mmap</code>).</p> |
| |
| <p>This allocator should prevent memory fragmentation when allocating memory for shot / medium object life-spans (classic network use).</p> |
| |
| <p>The memory allocator can be used in conjuncture with the system's <code>malloc</code> to minimize heap fragmentation (long-life objects use <code>malloc</code>, short life objects use <code>fio_malloc</code>).</p> |
| |
| <p>Long term allocation can use <code>fio_mmap</code> to directly allocate memory from the system. The overhead for <code>fio_mmap</code> is 16 bytes per allocation (freed with <code>fio_free</code>).</p> |
| |
| <p><strong>Note</strong>: this custom allocator could increase memory fragmentation if long-life allocations are performed periodically (rather than performed during startup). Use <a href="#fio_mmap"><code>fio_mmap</code></a> or the system's <code>malloc</code> for long-term allocations.</p> |
| |
| <h3 id="memory-allocator-overview">Memory Allocator Overview</h3> |
| |
| <p>The memory allocator uses <code>mmap</code> to collect memory from the system.</p> |
| |
| <p>Each allocation collects ~8Mb from the system, aligned on a 32Kb alignment boundary (except direct <code>mmap</code> allocation for large <code>fio_malloc</code> or <code>fio_mmap</code> calls). This memory is divided into 32Kb blocks which are added to a doubly linked "free" list.</p> |
| |
| <p>The allocator utilizes per-CPU arenas / bins to allow for concurrent memory allocations across threads and to minimize lock contention.</p> |
| |
| <p>Each arena / bin collects a 32Kb block and allocates "slices" as required by <code>fio_malloc</code>/<code>fio_realloc</code>.</p> |
| |
| <p>The <code>fio_free</code> function will free the whole 32Kb block as a single unit once the whole of the allocations for that block were freed (no small-allocation "free list" and no per-slice meta-data).</p> |
| |
| <p>The memory collected from the system (the 8Mb) will be returned to the system once all the memory was both allocated and freed (or during cleanup).</p> |
| |
| <p>To replace the system's <code>malloc</code> function family compile with the <code>FIO_OVERRIDE_MALLOC</code> defined (<code>-DFIO_OVERRIDE_MALLOC</code>).</p> |
| |
| <p>It should be possible to use tcmalloc or jemalloc alongside facil.io's allocator.It's also possible to prevent facil.io's custom allocator from compiling by defining <code>FIO_FORCE_MALLOC</code> (<code>-DFIO_FORCE_MALLOC</code>).</p> |
| |
| <p>More details in the <code>fio.h</code> header.</p> |
| |
| <h3 id="the-memory-allocators-api">The Memory Allocator's API</h3> |
| |
| <p>The functions were designed to be a drop in replacement to the system's memory allocation functions (<code>malloc</code>, <code>free</code> and friends).</p> |
| |
| <p>Where some improvement could be made, it was made using an added function name to add improved functionality (such as <code>fio_realloc2</code>).</p> |
| |
| <h4 id="fio_malloc"><code>fio_malloc</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="o">*</span><span class="n">fio_malloc</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size</span><span class="p">)</span> |
| </code></pre></div> |
| <p>Allocates memory using a per-CPU core block memory pool.</p> |
| |
| <p>Memory is always zeroed out.</p> |
| |
| <p>Allocations above <code>FIO_MEMORY_BLOCK_ALLOC_LIMIT</code> (16Kb bytes when using the default 32Kb blocks) will be redirected to <code>mmap</code>, as if <code>fio_mmap</code> was called.</p> |
| |
| <h4 id="fio_calloc"><code>fio_calloc</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="o">*</span><span class="n">fio_calloc</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size_per_unit</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">unit_count</span><span class="p">)</span> |
| </code></pre></div> |
| <p>Same as calling <code>fio_malloc(size_per_unit * unit_count)</code>;</p> |
| |
| <p>Allocations above <code>FIO_MEMORY_BLOCK_ALLOC_LIMIT</code> (16Kb bytes when using the default 32Kb blocks) will be redirected to <code>mmap</code>, as if <code>fio_mmap</code> was called.</p> |
| |
| <h4 id="fio_free"><code>fio_free</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_free</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Frees memory that was allocated using this library.</p> |
| |
| <h4 id="fio_realloc"><code>fio_realloc</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="o">*</span><span class="n">fio_realloc</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">new_size</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Re-allocates memory. An attempt to avoid copying the data is made only for big |
| memory allocations (larger than <code>FIO_MEMORY_BLOCK_ALLOC_LIMIT</code>).</p> |
| |
| <h4 id="fio_realloc2"><code>fio_realloc2</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="o">*</span><span class="n">fio_realloc2</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">new_size</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">copy_length</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Re-allocates memory. An attempt to avoid copying the data is made only for big |
| memory allocations (larger than <code>FIO_MEMORY_BLOCK_ALLOC_LIMIT</code>).</p> |
| |
| <p>This variation is slightly faster as it might copy less data.</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="o">*</span><span class="n">fio_mmap</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Allocates memory directly using <code>mmap</code>, this is prefered for objects that |
| both require almost a page of memory (or more) and expect a long lifetime.</p> |
| |
| <p>However, since this allocation will invoke the system call (<code>mmap</code>), it will |
| be inherently slower.</p> |
| |
| <p><code>fio_free</code> can be used for deallocating the memory.</p> |
| |
| <h2 id="linked-lists">Linked Lists</h2> |
| |
| <p>Linked list helpers are inline functions that become available when (and if) the <code>fio_h</code> file is included with the <code>FIO_INCLUDE_LINKED_LIST</code> macro.</p> |
| |
| <p>This can be performed even after if the <code>fio.h</code> file was previously included. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#include <fio.h> // No linked list helpers |
| #define FIO_INCLUDE_LINKED_LIST |
| #include <fio.h> // Linked list helpers become available |
| </span></code></pre></div> |
| <p>Linked lists come in two types:</p> |
| |
| <ol> |
| <li><p>Independent Object Lists:</p> |
| |
| <p>Used when a single object might belong to more than a single list, or when the object can't be edited.</p></li> |
| <li><p>Embedded Linked Lists</p> |
| |
| <p>Used when a single object always belongs to a single list and can be edited to add a <code>node</code> filed. This improves memory locality and performance, as well as minimizes memory allocations.</p></li> |
| </ol> |
| |
| <h3 id="independent-linked-list-api">Independent Linked List API</h3> |
| |
| <p>The independent object lists uses the following type:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cm">/** an independent linked list. */</span> |
| <span class="k">typedef</span> <span class="k">struct</span> <span class="n">fio_ls_s</span> <span class="p">{</span> |
| <span class="k">struct</span> <span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> |
| <span class="k">struct</span> <span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> |
| <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">obj</span><span class="p">;</span> |
| <span class="p">}</span> <span class="n">fio_ls_s</span><span class="p">;</span> |
| </code></pre></div> |
| <p>It can be initialized using the <code>FIO_LS_INIT</code> macro.</p> |
| |
| <h4 id="fio_ls_init"><code>FIO_LS_INIT</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LS_INIT(name) \ |
| { .next = &(name), .prev = &(name) } |
| </span></code></pre></div> |
| <p>Initializes the list container. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_ls_s</span> <span class="n">my_list</span> <span class="o">=</span> <span class="n">FIO_LS_INIT</span><span class="p">(</span><span class="n">my_list</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_ls_push"><code>fio_ls_push</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">fio_ls_push</span><span class="p">(</span><span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">pos</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">obj</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Adds an object to the list's head.</p> |
| |
| <p>Returns a pointer to the object's position (can be used in <code>fio_ls_remove</code>).</p> |
| |
| <h4 id="fio_ls_unshift"><code>fio_ls_unshift</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">fio_ls_unshift</span><span class="p">(</span><span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">pos</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">obj</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Adds an object to the list's tail.</p> |
| |
| <p>Returns a pointer to the object's position (can be used in <code>fio_ls_remove</code>).</p> |
| |
| <h4 id="fio_ls_pop"><code>fio_ls_pop</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="o">*</span><span class="n">fio_ls_pop</span><span class="p">(</span><span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">list</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes an object from the list's head.</p> |
| |
| <h4 id="fio_ls_shift"><code>fio_ls_shift</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="o">*</span><span class="n">fio_ls_shift</span><span class="p">(</span><span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">list</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes an object from the list's tail.</p> |
| |
| <h4 id="fio_ls_remove"><code>fio_ls_remove</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="o">*</span><span class="n">fio_ls_remove</span><span class="p">(</span><span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">node</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes a node from the list, returning the contained object.</p> |
| |
| <h4 id="fio_ls_is_empty"><code>fio_ls_is_empty</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_ls_is_empty</span><span class="p">(</span><span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">list</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Tests if the list is empty.</p> |
| |
| <h4 id="fio_ls_any"><code>fio_ls_any</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_ls_any</span><span class="p">(</span><span class="n">fio_ls_s</span> <span class="o">*</span><span class="n">list</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Tests if the list is NOT empty (contains any nodes).</p> |
| |
| <h4 id="fio_ls_for"><code>FIO_LS_FOR</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LS_FOR(list, pos) |
| </span></code></pre></div> |
| <p>Iterates through the list using a <code>for</code> loop.</p> |
| |
| <p>Access the data with <code>pos->obj</code> (<code>pos</code> can be named however you please).</p> |
| |
| <h3 id="embedded-linked-list-api">Embedded Linked List API</h3> |
| |
| <p>The embedded object lists uses the following node type:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cm">/** an embeded linked list. */</span> |
| <span class="k">typedef</span> <span class="k">struct</span> <span class="n">fio_ls_embd_s</span> <span class="p">{</span> |
| <span class="k">struct</span> <span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> |
| <span class="k">struct</span> <span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> |
| <span class="p">}</span> <span class="n">fio_ls_embd_s</span><span class="p">;</span> |
| </code></pre></div> |
| <p>It can be initialized using the <a href="#FIO_LS_INIT"><code>FIO_LS_INIT</code></a> macro (see above).</p> |
| |
| <h4 id="fio_ls_embd_push"><code>fio_ls_embd_push</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="n">fio_ls_embd_push</span><span class="p">(</span><span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">node</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Adds a node to the list's head.</p> |
| |
| <h4 id="fio_ls_embd_unshift"><code>fio_ls_embd_unshift</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="n">fio_ls_embd_unshift</span><span class="p">(</span><span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">node</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Adds a node to the list's tail.</p> |
| |
| <h4 id="fio_ls_embd_pop"><code>fio_ls_embd_pop</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">fio_ls_embd_pop</span><span class="p">(</span><span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">list</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes a node from the list's head.</p> |
| |
| <h4 id="fio_ls_embd_shift"><code>fio_ls_embd_shift</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">fio_ls_embd_shift</span><span class="p">(</span><span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">list</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes a node from the list's tail.</p> |
| |
| <h4 id="fio_ls_embd_remove"><code>fio_ls_embd_remove</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">fio_ls_embd_remove</span><span class="p">(</span><span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">node</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes a node from the containing node.</p> |
| |
| <h4 id="fio_ls_embd_is_empty"><code>fio_ls_embd_is_empty</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_ls_embd_is_empty</span><span class="p">(</span><span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">list</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Tests if the list is empty.</p> |
| |
| <h4 id="fio_ls_embd_any"><code>fio_ls_embd_any</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_ls_embd_any</span><span class="p">(</span><span class="n">fio_ls_embd_s</span> <span class="o">*</span><span class="n">list</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Tests if the list is NOT empty (contains any nodes).</p> |
| |
| <h4 id="fio_ls_embd_for"><code>FIO_LS_EMBD_FOR</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LS_EMBD_FOR(list, node) |
| </span></code></pre></div> |
| <p>Iterates through the list using a <code>for</code> loop.</p> |
| |
| <p>Access the data with <code>pos->obj</code> (<code>pos</code> can be named however you please).</p> |
| |
| <h4 id="fio_ls_embd_obj"><code>FIO_LS_EMBD_OBJ</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LS_EMBD_OBJ(type, member, plist) \ |
| ((type *)((uintptr_t)(plist) - (uintptr_t)(&(((type *)0)->member)))) |
| </span></code></pre></div> |
| <p>Takes a list pointer <code>plist</code> (node) and returns a pointer to it's container.</p> |
| |
| <p>This uses pointer offset calculations and can be used to calculate any structure's pointer (not just list containers) as an offset from a pointer of one of it's members.</p> |
| |
| <p>Very useful.</p> |
| |
| <h2 id="string-helpers">String Helpers</h2> |
| |
| <p>String helpers are inline functions that become available when (and if) the <code>fio_h</code> file is included with the <code>FIO_INCLUDE_STR</code> macro.</p> |
| |
| <p>This can be performed even after if the <code>fio.h</code> file was previously included. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#include <fio.h> // No string helpers |
| #define FIO_INCLUDE_STR |
| #include <fio.h> // String helpers become available |
| </span></code></pre></div> |
| <h3 id="string-api-initialization-and-destruction">String API - Initialization and Destruction</h3> |
| |
| <p>The String API is used to manage binary strings, allowing the NUL byte to be a valid byte in the middle of the string (unlike C strings)</p> |
| |
| <p>The String API uses the type <code>fio_str_s</code>, which shouldn't be accessed directly.</p> |
| |
| <p>The <code>fio_str_s</code> objects can be allocated either on the stack or on the heap.</p> |
| |
| <p>However, reference counting provided by the <code>fio_free2</code> and the <code>fio_str_send_free2</code> functions, requires that the <code>fio_str_s</code> object be allocated on the heap using <code>fio_malloc</code> or <code>fio_str_new2</code>.</p> |
| |
| <h4 id="string-memory-allocation">String Memory Allocation</h4> |
| |
| <p>String memory is managed by facil.io's allocation / deallocation routines (<code>fio_malloc</code>, etc').</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <p>A definition of <code>FIO_FORCE_MALLOC_TMP</code> doesn't persist, it will be cleared away once <code>fio.h</code> was included.</p> |
| |
| <p>A definition of <code>FIO_FORCE_MALLOC</code> will persist for all the types defined by <code>fio.h</code> until undefined but might be defined during compilation and shouldn't be manually unset.</p> |
| |
| <p>For example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_INCLUDE_STR 1 |
| #define FIO_FORCE_MALLOC_TMP 1 |
| #include <fio.h> |
| #ifdef FIO_FORCE_MALLOC_TMP |
| #error "FIO_FORCE_MALLOC_TMP is removed after it's used." |
| #undef |
| </span></code></pre></div> |
| <h4 id="fio_str_init"><code>FIO_STR_INIT</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_STR_INIT ((fio_str_s){.data = NULL, .small = 1}) |
| </span></code></pre></div> |
| <p>This value should be used for initialization. For example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="c1">// on the stack</span> |
| <span class="n">fio_str_s</span> <span class="n">str</span> <span class="o">=</span> <span class="n">FIO_STR_INIT</span><span class="p">;</span> |
| |
| <span class="c1">// or on the heap</span> |
| <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">str</span> <span class="o">=</span> <span class="n">fio_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">str</span><span class="p">);</span> |
| <span class="o">*</span><span class="n">str</span> <span class="o">=</span> <span class="n">FIO_STR_INIT</span><span class="p">;</span> |
| </code></pre></div> |
| <p>Remember to cleanup:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="c1">// on the stack</span> |
| <span class="n">fio_str_free</span><span class="p">(</span><span class="o">&</span><span class="n">str</span><span class="p">);</span> |
| |
| <span class="c1">// or on the heap</span> |
| <span class="n">fio_str_free</span><span class="p">(</span><span class="n">str</span><span class="p">);</span> |
| <span class="n">fio_free</span><span class="p">(</span><span class="n">str</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_str_init_existing"><code>FIO_STR_INIT_EXISTING</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_STR_INIT_EXISTING(buffer, length, capacity) \ |
| ((fio_str_s){.data = (buffer), \ |
| .len = (length), \ |
| .capa = (capacity), \ |
| .dealloc = fio_free}) |
| </span></code></pre></div> |
| <p>This macro allows the container to be initialized with existing data, as long as it's memory was allocated using <code>fio_malloc</code>.</p> |
| |
| <p>The <code>capacity</code> value should exclude the NUL character (if exists).</p> |
| |
| <h4 id="fio_str_init_static"><code>FIO_STR_INIT_STATIC</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_STR_INIT_STATIC(buffer) \ |
| ((fio_str_s){.data = (buffer), .len = strlen((buffer)), .dealloc = NULL}) |
| </span></code></pre></div> |
| <p>This macro allows the container to be initialized with existing static data, that shouldn't be freed.</p> |
| |
| <h4 id="fio_str_init_static2"><code>FIO_STR_INIT_STATIC2</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_STR_INIT_STATIC2(buffer, length) \ |
| ((fio_str_s){.data = (buffer), .len = (length), .dealloc = NULL}) |
| </span></code></pre></div> |
| <p>This macro allows the container to be initialized with existing static data, that shouldn't be freed.</p> |
| |
| <h4 id="fio_str_new2"><code>fio_str_new2</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">fio_str_new2</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Allocates a new fio_str_s object on the heap and initializes it.</p> |
| |
| <p>Use <code>fio_str_free2</code> to free both the String data and the container.</p> |
| |
| <p><strong>Note</strong>: This makes the allocation and reference counting logic more intuitive.</p> |
| |
| <h4 id="fio_str_new_copy2"><code>fio_str_new_copy2</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">fio_str_new_copy2</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">src</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Allocates a new fio_str_s object on the heap, initializes it and copies the |
| original (<code>src</code>) string into the new string.</p> |
| |
| <p>Use <code>fio_str_free2</code> to free the new string's data and it's container.</p> |
| |
| <h4 id="fio_str_dup"><code>fio_str_dup</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">fio_str_dup</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Adds a references to the current String object and returns itself.</p> |
| |
| <p><strong>Note</strong>: Nothing is copied, reference Strings are referencing the same String. Editing one reference will effect the other.</p> |
| |
| <p>The originals' String container should remain in scope (if on the stack) or remain allocated (if on the heap) until all the references were freed using <code>fio_str_free</code> / <code>fio_str_free2</code> or discarded.</p> |
| |
| <h4 id="fio_str_free"><code>fio_str_free</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_str_free</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Frees the String's resources and reinitializes the container.</p> |
| |
| <p>Note: if the container isn't allocated on the stack, it should be freed |
| separately using <code>free</code> or <code>fio_free</code>.</p> |
| |
| <p>Returns 0 if the data was freed and -1 if the String is NULL or has un-freed |
| references (see fio_str_dup).</p> |
| |
| <h4 id="fio_str_free2"><code>fio_str_free2</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_str_free2</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Frees the String's resources AS WELL AS the container.</p> |
| |
| <p>Note: the container is freed using <code>fio_free</code>, make sure <code>fio_malloc</code> was used to allocate it.</p> |
| |
| <h4 id="fio_str_send_free2"><code>fio_str_send_free2</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">ssize_t</span> <span class="n">fio_str_send_free2</span><span class="p">(</span><span class="k">const</span> <span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> |
| <span class="k">const</span> <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">str</span><span class="p">);</span> |
| </code></pre></div> |
| <p><code>fio_str_send_free2</code> sends the fio_str_s using <code>fio_write2</code>, freeing both the String and the container once the data was sent.</p> |
| |
| <p>As the naming indicates, the String is assumed to have been allocated using <code>fio_str_new2</code> or <code>fio_malloc</code>.</p> |
| |
| <h4 id="fio_str_detach"><code>fio_str_detach</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kt">char</span> <span class="o">*</span><span class="n">fio_str_detach</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns a C string with the existing data, clearing the <code>fio_str_s</code> object's String.</p> |
| |
| <p>Note: the String data is removed from the container, but the container isn't freed.</p> |
| |
| <p>Returns NULL if there's no String data.</p> |
| |
| <p>Remember to <code>fio_free</code> the returned data and - if required - <code>fio_str_free2</code> the container.</p> |
| |
| <h3 id="string-api-string-state-data-pointers-length-capacity-etc">String API - String state (data pointers, length, capacity, etc')</h3> |
| |
| <p>Many of the String state functions return a <code>fio_str_info_s</code> structure with information about the String:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> |
| <span class="kt">size_t</span> <span class="n">capa</span><span class="p">;</span> <span class="cm">/* String capacity */</span> |
| <span class="kt">size_t</span> <span class="n">len</span><span class="p">;</span> <span class="cm">/* String length */</span> |
| <span class="kt">char</span> <span class="o">*</span><span class="n">data</span><span class="p">;</span> <span class="cm">/* String data */</span> |
| <span class="p">}</span> <span class="n">fio_str_info_s</span><span class="p">;</span> |
| </code></pre></div> |
| <p>Using this approach is safer than accessing the String data directly, since the short Strings behave differently than long strings and the <code>fio_str_s</code> structure fields are only valid for long strings.</p> |
| |
| <h4 id="fio_str_info"><code>fio_str_info</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_str_info_s</span> <span class="n">fio_str_info</span><span class="p">(</span><span class="k">const</span> <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the String's complete state (capacity, length and pointer). </p> |
| |
| <h4 id="fio_str_len"><code>fio_str_len</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">fio_str_len</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the String's length in bytes.</p> |
| |
| <h4 id="fio_str_data"><code>fio_str_data</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">char</span> <span class="o">*</span><span class="n">fio_str_data</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns a pointer (<code>char *</code>) to the String's content.</p> |
| |
| <h4 id="fio_str_bytes"><code>fio_str_bytes</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_str_bytes(s) ((uint8_t *)fio_str_data((s))) |
| </span></code></pre></div> |
| <p>Returns a byte pointer (<code>uint8_t *</code>) to the String's unsigned content.</p> |
| |
| <h4 id="fio_str_capa"><code>fio_str_capa</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">fio_str_capa</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the String's existing capacity (total used & available memory).</p> |
| |
| <h4 id="fio_str_resize"><code>fio_str_resize</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_str_info_s</span> <span class="n">fio_str_resize</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Sets the new String size without reallocating any memory (limited by existing capacity).</p> |
| |
| <p>Returns the updated state of the String.</p> |
| |
| <p>Note: When shrinking, any existing data beyond the new size may be corrupted.</p> |
| |
| <h4 id="fio_str_clear"><code>fio_str_clear</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_str_clear(s) fio_str_resize((s), 0) |
| </span></code></pre></div> |
| <p>Clears the string (retaining the existing capacity).</p> |
| |
| <h4 id="fio_str_hash"><code>fio_str_hash</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">uint64_t</span> <span class="n">fio_str_hash</span><span class="p">(</span><span class="k">const</span> <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the String's Risky Hash (see <a href="#fio_risky_hash"><code>fio_risky_hash</code></a>).</p> |
| |
| <p>This value is machine/instance specific (hash seed is a memory address).</p> |
| |
| <p>NOTE: the hashing function might be changed at any time without notice. It wasn't cryptographically analyzed and safety against malicious data can't be guaranteed. Use <a href="#fio_siphash13"><code>fio_siphash13</code></a> or <a href="#fio_siphash24"><code>fio_siphash24</code></a> when hashing data from external sources.</p> |
| |
| <h4 id="fio_risky_hash"><code>fio_risky_hash</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">static</span> <span class="kr">inline</span> <span class="kt">uintptr_t</span> <span class="n">fio_risky_hash</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">seed</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Computes a facil.io <a href="riskyhash">Risky Hash</a> - modeled after the amazing <a href="https://github.com/Cyan4973/xxHash">xxHash</a> (which has a BSD license) and named "Risky Hash" because writing your own hashing function is a risky business, full of pitfalls and hours of testing...</p> |
| |
| <p>Risky Hash passed the <a href="https://github.com/rurban/smhasher">SMHasher</a> tests with wonderful results and can be safely used for hash maps when hashing safe data.</p> |
| |
| <p>However, Risky Hash isn't as battle tested as SipHash and because of the great unknown, it should be considered "risky" and might be exposed to malicious attacks, such as <a href="https://medium.freecodecamp.org/hash-table-attack-8e4371fc5261">Hash Flooding Attacks</a>.</p> |
| |
| <p><strong>Note</strong>: Although this function can be used independently of the <code>fio_str_s</code> object and functions, it is only available if the <code>FIO_INCLUDE_STR</code> flag was defined.</p> |
| |
| <h3 id="string-api-memory-management">String API - Memory management</h3> |
| |
| <h4 id="fio_str_compact"><code>fio_str_compact</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_str_compact</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Performs a best attempt at minimizing memory consumption.</p> |
| |
| <p>Actual effects depend on the underlying memory allocator and it's implementation. Not all allocators will free any memory.</p> |
| |
| <h4 id="fio_str_capa_assert"><code>fio_str_capa_assert</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_str_info_s</span> <span class="n">fio_str_capa_assert</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">needed</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Requires the String to have at least <code>needed</code> capacity (including existing data).</p> |
| |
| <p>Returns the current state of the String.</p> |
| |
| <h3 id="string-api-utf-8-state">String API - UTF-8 State</h3> |
| |
| <h4 id="fio_str_utf8_valid"><code>fio_str_utf8_valid</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">size_t</span> <span class="n">fio_str_utf8_valid</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns 1 if the String is UTF-8 valid and 0 if not.</p> |
| |
| <h4 id="fio_str_utf8_len"><code>fio_str_utf8_len</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">size_t</span> <span class="n">fio_str_utf8_len</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the String's length in UTF-8 characters.</p> |
| |
| <h4 id="fio_str_utf8_select"><code>fio_str_utf8_select</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_str_utf8_select</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="o">*</span><span class="n">pos</span><span class="p">,</span> <span class="kt">size_t</span> <span class="o">*</span><span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Takes a UTF-8 character selection information (UTF-8 position and length) and updates the same variables so they reference the raw byte slice information.</p> |
| |
| <p>If the String isn't UTF-8 valid up to the requested selection, than <code>pos</code> will be updated to <code>-1</code> otherwise values are always positive.</p> |
| |
| <p>The returned <code>len</code> value may be shorter than the original if there wasn't enough data left to accomodate the requested length. When a <code>len</code> value of <code>0</code> is returned, this means that <code>pos</code> marks the end of the String.</p> |
| |
| <p>Returns -1 on error and 0 on success.</p> |
| |
| <h4 id="fio_str_utf8_code_point"><code>FIO_STR_UTF8_CODE_POINT</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_STR_UTF8_CODE_POINT(ptr, end, i32) // ... |
| </span></code></pre></div> |
| <p>Advances the <code>ptr</code> by one utf-8 character, placing the value of the UTF-8 character into the i32 variable (which must be a signed integer with 32bits or more). On error, <code>i32</code> will be equal to <code>-1</code> and <code>ptr</code> will not step forwards.</p> |
| |
| <p>The <code>end</code> value is only used for overflow protection.</p> |
| |
| <p>This helper macro is used internally but left exposed for external use.</p> |
| |
| <h3 id="string-api-content-manipulation-and-review">String API - Content Manipulation and Review</h3> |
| |
| <h4 id="fio_str_write"><code>fio_str_write</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_str_info_s</span> <span class="n">fio_str_write</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">src</span><span class="p">,</span> |
| <span class="kt">size_t</span> <span class="n">src_len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Writes data at the end of the String (similar to <code>fio_str_insert</code> with the argument <code>pos == -1</code>).</p> |
| |
| <h4 id="fio_str_write_i"><code>fio_str_write_i</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_str_info_s</span> <span class="n">fio_str_write_i</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">num</span><span class="p">);</span> |
| |
| </code></pre></div> |
| <p>Writes a number at the end of the String using normal base 10 notation.</p> |
| |
| <h4 id="fio_str_concat"><code>fio_str_concat</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">fio_str_info_s</span> <span class="n">fio_str_concat</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> |
| <span class="n">fio_str_s</span> <span class="k">const</span> <span class="o">*</span><span class="n">src</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Appens the <code>src</code> String to the end of the <code>dest</code> String.</p> |
| |
| <p>If <code>dest</code> is empty, the resulting Strings will be equal.</p> |
| |
| <h4 id="fio_str_join"><code>fio_str_join</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_str_join(dest, src) fio_str_concat((dest), (src)) |
| </span></code></pre></div> |
| <p>Alias for <a href="#fio_str_concat"><code>fio_str_concat</code></a>.</p> |
| |
| <h4 id="fio_str_replace"><code>fio_str_replace</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_str_info_s</span> <span class="n">fio_str_replace</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="n">start_pos</span><span class="p">,</span> |
| <span class="kt">size_t</span> <span class="n">old_len</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">src</span><span class="p">,</span> |
| <span class="kt">size_t</span> <span class="n">src_len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Replaces the data in the String - replacing <code>old_len</code> bytes starting at <code>start_pos</code>, with the data at <code>src</code> (<code>src_len</code> bytes long).</p> |
| |
| <p>Negative <code>start_pos</code> values are calculated backwards, <code>-1</code> == end of String.</p> |
| |
| <p>When <code>old_len</code> is zero, the function will insert the data at <code>start_pos</code>.</p> |
| |
| <p>If <code>src_len == 0</code> than <code>src</code> will be ignored and the data marked for replacement will be erased.</p> |
| |
| <h4 id="fio_str_vprintf"><code>fio_str_vprintf</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_str_info_s</span> <span class="n">fio_str_vprintf</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">format</span><span class="p">,</span> |
| <span class="kt">va_list</span> <span class="n">argv</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Writes to the String using a vprintf like interface.</p> |
| |
| <p>Data is written to the end of the String.</p> |
| |
| <h4 id="fio_str_printf"><code>fio_str_printf</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_str_info_s</span> <span class="n">fio_str_printf</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">format</span><span class="p">,</span> <span class="p">...);</span> |
| </code></pre></div> |
| <p>Writes to the String using a printf like interface.</p> |
| |
| <p>Data is written to the end of the String.</p> |
| |
| <h4 id="fio_str_readfile"><code>fio_str_readfile</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_str_info_s</span> <span class="n">fio_str_readfile</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">filename</span><span class="p">,</span> |
| <span class="kt">intptr_t</span> <span class="n">start_at</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="n">limit</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Opens the file <code>filename</code> and pastes it's contents (or a slice ot it) at the |
| end of the String. If <code>limit == 0</code>, than the data will be read until EOF.</p> |
| |
| <p>If the file can't be located, opened or read, or if <code>start_at</code> is beyond |
| the EOF position, NULL is returned in the state's <code>data</code> field.</p> |
| |
| <p>Works on POSIX only.</p> |
| |
| <h4 id="fio_str_freeze"><code>fio_str_freeze</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="n">fio_str_freeze</span><span class="p">(</span><span class="n">fio_str_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Prevents further manipulations to the String's content.</p> |
| |
| <h4 id="fio_str_iseq"><code>fio_str_iseq</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_str_iseq</span><span class="p">(</span><span class="k">const</span> <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">str1</span><span class="p">,</span> <span class="k">const</span> <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">str2</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Binary comparison returns <code>1</code> if both strings are equal and <code>0</code> if not.</p> |
| |
| <h2 id="dynamic-arrays">Dynamic Arrays</h2> |
| |
| <p>The <code>fio.h</code> header includes a simple typed dynamic array with a minimal API that can be adapted to any type.</p> |
| |
| <p><strong>Note</strong>: <a href="fiobj_ary">The API for the <code>FIOBJ</code> Array is located here</a>. This is the documentation for the core library Array.</p> |
| |
| <p>To create an Array type, define the macro FIO_ARY_NAME. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_ARY_NAME fio_cstr_ary |
| #define FIO_ARY_TYPE char * |
| #define FIO_ARY_COMPARE(k1, k2) (!strcmp((k1), (k2))) |
| #include <fio.h> |
| </span></code></pre></div> |
| <p>It's possible to create a number of Set or Array types by re-including the <code>fio.h</code> header. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_INCLUDE_STR |
| #include <fio.h> // adds the fio_str_s types and functions |
| </span> |
| <span class="cp">#define FIO_ARY_NAME fio_int_ary |
| #define FIO_ARY_TYPE int |
| #include <fio.h> // creates the fio_int_ary_s Array and functions |
| </span> |
| <span class="cp">#define FIO_ARY_NAME fio_str_ary |
| #define FIO_ARY_TYPE fio_str_s * |
| #define FIO_ARY_COMPARE(k1, k2) (fio_str_iseq((k1), (k2))) |
| #define FIO_ARY_COPY(key) fio_str_dup((key)) |
| #define FIO_ARY_DESTROY(key) fio_str_free2((key)) |
| #include <fio.h> // creates the fio_str_ary_s Array and functions |
| </span></code></pre></div> |
| <h3 id="array-memory-allocation">Array Memory allocation</h3> |
| |
| <p>The Array's memory is managed by facil.io's allocation / deallocation routines (<code>fio_malloc</code>, etc').</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <p>A definition of <code>FIO_FORCE_MALLOC_TMP</code> doesn't persist, it will be cleared away once <code>fio.h</code> was included.</p> |
| |
| <p>A definition of <code>FIO_FORCE_MALLOC</code> will persist for all the types defined by <code>fio.h</code> until undefined but might be defined during compilation and shouldn't be manually unset.</p> |
| |
| <p>For example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_FORCE_MALLOC_TMP 1 |
| #define FIO_ARY_NAME fio_int_ary |
| #define FIO_ARY_TYPE int |
| #include <fio.h> // creates the fio_int_ary_s Array and functions |
| #ifdef FIO_FORCE_MALLOC_TMP |
| #error "FIO_FORCE_MALLOC_TMP is removed after it's used." |
| #undef |
| </span></code></pre></div> |
| <p>More flexibility (such as using a third memory allocation scheme) can be achieved using the <code>FIO_ARRAY_MALLOC</code> type macros, as detailed below.</p> |
| |
| <h3 id="defining-the-array">Defining the Array</h3> |
| |
| <h4 id="fio_ary_name"><code>FIO_ARY_NAME</code></h4> |
| |
| <p>The <code>FIO_ARY_NAME</code> is required and will be used to set a for the Array's type and functions.</p> |
| |
| <p>The Array type will be <code>FIO_ARY_NAME_s</code> and each function will be translated to <code>FIO_ARY_NAME_func</code>, where <code>FIO_ARY_NAME</code> is replaced by the macro set.</p> |
| |
| <p>For example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_ARY_NAME fio_cstr_ary |
| #define FIO_ARY_TYPE char * |
| #define FIO_ARY_COMPARE(k1, k2) (!strcmp((k1), (k2))) |
| #include <fio.h> |
| </span> |
| <span class="n">fio_cstr_ary_s</span> <span class="n">global_array</span> <span class="o">=</span> <span class="n">FIO_ARY_INIT</span><span class="p">;</span> |
| |
| <span class="kt">void</span> <span class="nf">populate_array</span><span class="p">(</span><span class="kt">char</span> <span class="o">**</span> <span class="n">data</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">)</span> <span class="p">{</span> |
| <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">len</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> |
| <span class="p">{</span> |
| <span class="n">fio_cstr_ary_push</span><span class="p">(</span><span class="o">&</span><span class="n">global_array</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> |
| <span class="p">}</span> |
| <span class="p">}</span> |
| </code></pre></div> |
| <h4 id="fio_ary_type"><code>FIO_ARY_TYPE</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#if !defined(FIO_ARY_TYPE) |
| #define FIO_ARY_TYPE void * |
| #endif |
| </span></code></pre></div> |
| <p>The default Array object type is <code>void *</code> */</p> |
| |
| <h4 id="fio_ary_invalid"><code>FIO_ARY_INVALID</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#if !defined(FIO_ARY_INVALID) |
| </span><span class="k">static</span> <span class="n">FIO_ARY_TYPE</span> <span class="k">const</span> <span class="n">FIO_NAME</span><span class="p">(</span><span class="n">s___const_invalid_object</span><span class="p">);</span> |
| <span class="cp">#define FIO_ARY_INVALID FIO_NAME(s___const_invalid_object) |
| #endif |
| </span></code></pre></div> |
| <p>The <code>FIO_ARY_INVALID</code> value should be an object with all bytes set to 0. Since <code>FIO_ARY_TYPE</code> type is unknown, a constant static object is created. However, it is better to manually define <code>FIO_ARY_INVALID</code>.</p> |
| |
| <h4 id="fio_ary_compare"><code>FIO_ARY_COMPARE</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#if !defined(FIO_ARY_COMPARE) |
| #define FIO_ARY_COMPARE(o1, o2) ((o1) == (o2)) |
| #endif |
| </span></code></pre></div> |
| <p>The default object comparison assumes a simple type.</p> |
| |
| <h4 id="fio_ary_copy"><code>FIO_ARY_COPY</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#ifndef FIO_ARY_COPY |
| #define FIO_ARY_COPY(dest, obj) ((dest) = (obj)) |
| #endif |
| </span></code></pre></div> |
| <p>The default object copy is a simple assignment.</p> |
| |
| <h4 id="fio_ary_destroy"><code>FIO_ARY_DESTROY</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#ifndef FIO_ARY_DESTROY |
| #define FIO_ARY_DESTROY(obj) ((void)0) |
| #endif |
| </span></code></pre></div> |
| <p>The default object destruction is a no-op.</p> |
| |
| <p><strong>Note</strong>: Before freeing the Array, <code>FIO_ARY_DESTROY</code> will be automatically called for every existing object, including any invalid objects (if any). It is important that the <code>FIO_ARY_DESTROY</code> macro allows for invalid data (all bytes are <code>0</code>).</p> |
| |
| <h4 id="fio_ary_malloc"><code>FIO_ARY_MALLOC</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#ifndef FIO_ARY_MALLOC |
| #define FIO_ARY_MALLOC(size) fio_malloc((size)) |
| #endif |
| </span></code></pre></div> |
| <p>The default Array allocator is set to <code>fio_malloc</code>.</p> |
| |
| <p>It's important to note that the default allocator <strong>must</strong> set all the allocated bytes to zero, exactly as <code>fio_malloc</code> does.</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <h4 id="fio_ary_realloc"><code>FIO_ARY_REALLOC</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#ifndef FIO_ARY_REALLOC </span><span class="cm">/* NULL ptr indicates new allocation */</span><span class="cp"> |
| #define FIO_ARY_REALLOC(ptr, original_size, new_size, valid_data_length) \ |
| fio_realloc2((ptr), (new_size), (valid_data_length)) |
| #endif |
| </span></code></pre></div> |
| <p>The default Array re-allocator is set to <code>fio_realloc2</code>. All bytes will be set to zero except the copied data and - in some cases, where copy alignment error occurs - the last 16 bytes.</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <h4 id="fio_ary_dealloc"><code>FIO_ARY_DEALLOC</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#ifndef FIO_ARY_DEALLOC |
| #define FIO_ARY_DEALLOC(ptr, size) fio_free((ptr)) |
| #endif |
| </span></code></pre></div> |
| <p>The default Array deallocator is set to <code>fio_free</code>.</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <h3 id="naming-the-array">Naming the Array</h3> |
| |
| <p>Because the type and function names are dictated by the <code>FIO_ARY_NAME</code>, it's impossible to name the functions and types that will be created.</p> |
| |
| <p>For the purpose of this documentation, the <code>FIO_ARY_NAME(name)</code> will mark a type / function name so that it's equal to <code>FIO_ARY_NAME + "_" + name</code>. |
| i.e., if <code>FIO_SET_NAME</code> is <code>foo</code> than <code>FIO_SET_NAME(s)</code> is <code>foo_s</code>.</p> |
| |
| <h3 id="array-initialization-and-state">Array Initialization and State</h3> |
| |
| <h4 id="fio_ary_name-s"><code>FIO_ARY_NAME(s)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> |
| <span class="k">struct</span> <span class="nf">FIO_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span> |
| <span class="kt">size_t</span> <span class="n">start</span><span class="p">;</span> <span class="cm">/* first index where data was already written */</span> |
| <span class="kt">size_t</span> <span class="n">end</span><span class="p">;</span> <span class="cm">/* next spot to write at tail */</span> |
| <span class="kt">size_t</span> <span class="n">capa</span><span class="p">;</span> <span class="cm">/* existing capacity */</span> |
| <span class="n">FIO_ARY_TYPE</span> <span class="o">*</span><span class="n">arry</span><span class="p">;</span> <span class="cm">/* the actual array's memory, if any */</span> |
| <span class="p">};</span> |
| </code></pre></div> |
| <p>The Array container type. It is advised that the container be considered opaque and that the functions provided are used to access it's data (instead of direct data access).</p> |
| |
| <h4 id="fio_ary_init"><code>FIO_ARY_INIT</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#ifndef FIO_ARY_INIT |
| #define FIO_ARY_INIT \ |
| { .capa = 0 } |
| #endif |
| </span></code></pre></div> |
| <p>Initializes the Array.</p> |
| |
| <h4 id="fio_ary_name-free"><code>FIO_ARY_NAME(free)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">free</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Frees the array's internal data.</p> |
| |
| <h4 id="fio_ary_name-count"><code>FIO_ARY_NAME(count)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">count</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the number of elements in the Array.</p> |
| |
| <h4 id="fio_ary_name-capa"><code>FIO_ARY_NAME(capa)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">capa</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the current, temporary, array capacity (it's dynamic).</p> |
| |
| <hr> |
| |
| <h3 id="array-data-management">Array data management</h3> |
| |
| <h4 id="fio_ary_name-concat"><code>FIO_ARY_NAME(concat)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">concat</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">dest</span><span class="p">,</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">src</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Adds all the items in the <code>src</code> Array to the end of the <code>dest</code> Array.</p> |
| |
| <p>The <code>src</code> Array remain untouched.</p> |
| |
| <h4 id="fio_ary_name-set"><code>FIO_ARY_NAME(set)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">set</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="n">index</span><span class="p">,</span> |
| <span class="n">FIO_ARY_TYPE</span> <span class="n">data</span><span class="p">,</span> <span class="n">FIO_ARY_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Sets <code>index</code> to the value in <code>data</code>.</p> |
| |
| <p>If <code>index</code> is negative, it will be counted from the end of the Array (-1 == |
| last element).</p> |
| |
| <p>If <code>old</code> isn't NULL, the existing data will be copied to the location pointed |
| to by <code>old</code> before the copy in the Array is destroyed.</p> |
| |
| <h4 id="fio_ary_name-get"><code>FIO_ARY_NAME(get)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="n">FIO_ARY_TYPE</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">get</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="n">index</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the value located at <code>index</code> (no copying is peformed).</p> |
| |
| <p>If <code>index</code> is negative, it will be counted from the end of the Array (-1 == |
| last element).</p> |
| |
| <h4 id="fio_ary_name-find"><code>FIO_ARY_NAME(find)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">intptr_t</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">find</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="n">FIO_ARY_TYPE</span> <span class="n">data</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the index of the object or -1 if the object wasn't found.</p> |
| |
| <h4 id="fio_ary_name-remove"><code>FIO_ARY_NAME(remove)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">remove</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="kt">intptr_t</span> <span class="n">index</span><span class="p">,</span> |
| <span class="n">FIO_ARY_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes an object from the array, <strong>moving</strong> all the other objects to prevent |
| "holes" in the data.</p> |
| |
| <p>If <code>old</code> is set, the data is copied to the location pointed to by <code>old</code> |
| before the data in the array is destroyed.</p> |
| |
| <p>Returns 0 on success and -1 on error.</p> |
| |
| <h4 id="fio_ary_name-remove2"><code>FIO_ARY_NAME(remove2)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">remove2</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="n">FIO_ARY_TYPE</span> <span class="n">data</span><span class="p">,</span> |
| <span class="n">FIO_ARY_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes an object from the array, if it exists, MOVING all the other objects |
| to prevent "holes" in the data.</p> |
| |
| <p>Returns -1 if the object wasn't found or 0 if the object was successfully |
| removed.</p> |
| |
| <h4 id="fio_ary_name-to_a"><code>FIO_ARY_NAME(to_a)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="n">FIO_ARY_TYPE</span> <span class="o">*</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">to_a</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns a pointer to the C array containing the objects.</p> |
| |
| <h4 id="fio_ary_name-push"><code>FIO_ARY_NAME(push)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">push</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="n">FIO_ARY_TYPE</span> <span class="n">data</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Pushes an object to the end of the Array. Returns -1 on error.</p> |
| |
| <h4 id="fio_ary_name-pop"><code>FIO_ARY_NAME(pop)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">pop</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="n">FIO_ARY_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes an object from the end of the Array.</p> |
| |
| <p>If <code>old</code> is set, the data is copied to the location pointed to by <code>old</code> |
| before the data in the array is destroyed.</p> |
| |
| <p>Returns -1 on error (Array is empty) and 0 on success.</p> |
| |
| <h4 id="fio_ary_name-unshift"><code>FIO_ARY_NAME(unshift)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">unshift</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="n">FIO_ARY_TYPE</span> <span class="n">data</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Unshifts an object to the beginning of the Array. Returns -1 on error.</p> |
| |
| <p>This could be expensive, causing <code>memmove</code>.</p> |
| |
| <h4 id="fio_ary_name-shift"><code>FIO_ARY_NAME(shift)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">shift</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="n">FIO_ARY_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes an object from the beginning of the Array.</p> |
| |
| <p>If <code>old</code> is set, the data is copied to the location pointed to by <code>old</code> |
| before the data in the array is destroyed.</p> |
| |
| <p>Returns -1 on error (Array is empty) and 0 on success.</p> |
| |
| <h4 id="fio_ary_name-each"><code>FIO_ARY_NAME(each)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">each</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">start_at</span><span class="p">,</span> |
| <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">task</span><span class="p">)(</span><span class="n">FIO_ARY_TYPE</span> <span class="n">pt</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">),</span> |
| <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Iteration using a callback for each entry in the array.</p> |
| |
| <p>The callback task function must accept an the entry data as well as an opaque |
| user pointer.</p> |
| |
| <p>If the callback returns -1, the loop is broken. Any other value is ignored.</p> |
| |
| <p>Returns the relative "stop" position, i.e., the number of items processed + |
| the starting point.</p> |
| |
| <h4 id="fio_ary_name-compact"><code>FIO_ARY_NAME(compact)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_FUNC</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">compact</span><span class="p">)(</span><span class="n">FIO_ARY_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">ary</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes any FIO_ARY_TYPE_INVALID object from an Array (NULL pointers by |
| default), keeping all other data in the array.</p> |
| |
| <p>This action is O(n) where n in the length of the array. |
| It could get expensive.</p> |
| |
| <h4 id="fio_ary_for-ary-pos"><code>FIO_ARY_FOR(ary, pos)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_ARY_FOR(ary, pos) |
| </span></code></pre></div> |
| <p>Iterates through the list using a <code>for</code> loop.</p> |
| |
| <p>Access the object with the pointer <code>pos</code>. The <code>pos</code> variable can be named |
| however you please.</p> |
| |
| <p>Avoid editing the array during a FOR loop, although I hope it's possible, I |
| wouldn't count on it.</p> |
| |
| <h2 id="hash-maps-sets">Hash Maps / Sets</h2> |
| |
| <p>facil.io includes a simple ordered Hash Map / Set implementation, with a minimal API.</p> |
| |
| <p><strong>Note</strong>: <a href="fiobj_hash">The API for the <code>FIOBJ</code> Hash Map is located here</a>. This is the documentation for the core library Hash Map / Set.</p> |
| |
| <p>A Set is basically a Hash Map where the keys are also the values, it's often used for caching objects while a Hash Map is used to find one object using another.</p> |
| |
| <p>A Hash Map is basically a set where the objects in the Set are key-value couplets and only the keys are tested when searching the Set.</p> |
| |
| <p>The Set's object type and behavior is controlled by the FIO_SET_OBJ_* marcos.</p> |
| |
| <p>To create a Set or a Hash Map, the macro FIO_SET_NAME must be defined. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_NAME fio_str_info_set |
| #define FIO_SET_OBJ_TYPE char * |
| #define FIO_SET_OBJ_COMPARE(k1, k2) (!strcmp((k1), (k2))) |
| #include <fio.h> |
| </span><span class="c1">// ...</span> |
| <span class="n">fio_str_info_set_s</span> <span class="n">my_set</span> <span class="o">=</span> <span class="n">FIO_SET_INIT</span><span class="p">;</span> <span class="c1">// note type name matches FIO_SET_NAME</span> |
| <span class="kt">uint64_t</span> <span class="n">hash</span> <span class="o">=</span> <span class="n">fio_siphash</span><span class="p">(</span><span class="s">"foo"</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> |
| <span class="n">fio_str_info_set_insert</span><span class="p">(</span><span class="o">&</span><span class="n">my_set</span><span class="p">,</span> <span class="n">hash</span><span class="p">,</span> <span class="s">"foo"</span><span class="p">);</span> <span class="c1">// note function name</span> |
| </code></pre></div> |
| <p>This can be performed a number of times, defining a different Set / Hash Map each time.</p> |
| |
| <h3 id="security-concerns">Security Concerns</h3> |
| |
| <p>Since the facio.io hash map implementation allows any hash function to be used, there are a number of important safety considerations developers should be aware of.</p> |
| |
| <p>Hash Maps and Sets could be attacked using "hash flooding" attacks.</p> |
| |
| <p>The weaker the hashing function, the more likely it is to achieve a hash flooding attack.</p> |
| |
| <p>To avoid these attacks, there are three requirements:</p> |
| |
| <ol> |
| <li><p>The hashing function, used to produce the digest (hash value) <strong>should</strong> allow resistance to hash flooding attacks. This means:</p> |
| |
| <ol> |
| <li>The function should require a "seed" / "secret".</li> |
| <li>Malicious data can't be authored to circumvent the "secret".</li> |
| </ol></li> |
| <li><p>The implementation uses the secret to randomize digest values.</p></li> |
| </ol> |
| |
| <p>A bad secret will be a function pointer or a value set during startup.</p> |
| |
| <p>A good secret will be hash table specific, so different hash tables have different random secrets. For example, hashing the table's memory address with a good hash function would be a good secret (assuming the address remains the same while the table is in use).</p> |
| |
| <ol> |
| <li><p>The hash map implementation <strong>must</strong> use as many bits from the hashed value, or rotate the bits that are in use.</p> |
| |
| <p>In general, hash maps / sets are either prime number based (use more bits from the hash value but take longer for lookups) or modulus 2 based (faster lookup times).</p> |
| |
| <p>Modulus 2 based hash map implementations are very common, but they could be exposed to lower bit collision attacks, where a partial collision is enough to attack the hash table.</p> |
| |
| <p>This risk should be mitigated by utilizing as many bits from the digest as possible.</p> |
| |
| <p>For example, facil.io is modulus 2 based, but it uses different bits every time it grows, protecting against lower bit collision attacks. </p></li> |
| <li><p>The implementation <strong>must</strong> react to attacks that circumvent the hash functions.</p></li> |
| </ol> |
| |
| <p>A good hash function should be considered the first line of defense for a hash map implementation, but it should <strong>not</strong> be the main line of defense.</p> |
| |
| <p>A hash map implementation should, in addition to mitigating partial and full collisions using cuckoo steps / round robin, bit mangling, etc', recognize (full) collision attacks and prevent hash table growth when too many full collisions occur.</p> |
| |
| <p>For example, facil.io hash maps and sets will recognize an attack when 96 full collisions are detected (defined as <code>FIO_SET_MAX_MAP_FULL_COLLISIONS</code> in <code>fio.h</code>). After this point, new colliding data will overwrite old colliding data.</p> |
| |
| <h3 id="hash-map-set-memory-allocation">Hash Map / Set Memory allocation</h3> |
| |
| <p>The Hash Map's memory is managed by facil.io's allocation / deallocation routines (<code>fio_malloc</code>, etc').</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <p>A definition of <code>FIO_FORCE_MALLOC_TMP</code> doesn't persist, it will be cleared away once <code>fio.h</code> was included.</p> |
| |
| <p>A definition of <code>FIO_FORCE_MALLOC</code> will persist for all the types defined by <code>fio.h</code> until undefined but might be defined during compilation and shouldn't be manually unset.</p> |
| |
| <p>For example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_FORCE_MALLOC_TMP 1 |
| #define FIO_SET_NAME fio_str_info_set |
| #define FIO_SET_OBJ_TYPE char * |
| #define FIO_SET_OBJ_COMPARE(k1, k2) (!strcmp((k1), (k2))) |
| #include <fio.h> // created the fio_str_info_set_s and functions |
| #ifdef FIO_FORCE_MALLOC_TMP |
| #error "FIO_FORCE_MALLOC_TMP is removed after it's used." |
| #undef |
| </span></code></pre></div> |
| <p>More flexibility (such as using a third memory allocation scheme) can be achieved using the <code>FIO_SET_MALLOC</code> type macros, as detailed below.</p> |
| |
| <h3 id="defining-the-set-hash-map">Defining the Set / Hash Map</h3> |
| |
| <p>The Set's object type and behavior is controlled by the FIO_SET_OBJ_* marcos: <code>FIO_SET_OBJ_TYPE</code>, <code>FIO_SET_OBJ_COMPARE</code>, <code>FIO_SET_OBJ_COPY</code>, <code>FIO_SET_OBJ_DESTROY</code>. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_INCLUDE_STR |
| #include <fio.h> // adds the fio_str_s types and functions |
| </span> |
| <span class="cp">#define FIO_SET_NAME fio_str_set |
| #define FIO_SET_OBJ_TYPE fio_str_s * |
| #define FIO_SET_OBJ_COMPARE(s1, s2) fio_str_iseq((s1), (s2)) |
| #define FIO_SET_OBJ_COPY(dest, src) (dest) = fio_str_new_copy2((src)) |
| #define FIO_SET_OBJ_DESTROY(str) fio_str_free2((str)) |
| #include <fio.h> // creates the fio_str_set_s Set and functions |
| </span> |
| <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">fio_str_s</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">FIO_STR_INIT_STATIC</span><span class="p">(</span><span class="s">"foo"</span><span class="p">);</span> |
| <span class="c1">// Initialize a Set for String caching</span> |
| <span class="n">fio_str_set_s</span> <span class="n">my_set</span> <span class="o">=</span> <span class="n">FIO_SET_INIT</span><span class="p">;</span> |
| <span class="c1">// Insert object to Set (will make copy)</span> |
| <span class="n">fio_str_s</span> <span class="o">*</span><span class="n">cpy</span> <span class="o">=</span> <span class="n">fio_str_set_insert</span><span class="p">(</span><span class="o">&</span><span class="n">my_set</span><span class="p">,</span> <span class="n">fio_str_hash</span><span class="p">(</span><span class="o">&</span><span class="n">tmp</span><span class="p">),</span> <span class="o">&</span><span class="n">tmp</span><span class="p">);</span> |
| <span class="n">printf</span><span class="p">(</span><span class="s">"Original data %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">tmp</span><span class="p">);</span> |
| <span class="n">printf</span><span class="p">(</span><span class="s">"Stored data %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">cpy</span><span class="p">);</span> |
| <span class="n">printf</span><span class="p">(</span><span class="s">"Stored data content: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">fio_str_data</span><span class="p">(</span><span class="n">cpy</span><span class="p">));</span> |
| <span class="c1">// Free set (will free copy).</span> |
| <span class="n">fio_str_set_free</span><span class="p">(</span><span class="o">&</span><span class="n">my_set</span><span class="p">);</span> |
| <span class="p">}</span> |
| |
| </code></pre></div> |
| <p>To create a Hash Map, rather than a pure Set, the macro FIO_SET_KET_TYPE must |
| be defined. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_KEY_TYPE char * |
| </span></code></pre></div> |
| <p>This allows the FIO_SET_KEY_* macros to be defined as well. For example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_NAME fio_str_hash |
| #define FIO_SET_KEY_TYPE char * |
| #define FIO_SET_KEY_COMPARE(k1, k2) (!strcmp((k1), (k2))) |
| #define FIO_SET_OBJ_TYPE char * |
| #include <fio.h> |
| </span></code></pre></div> |
| <h4 id="fio_set_obj_type"><code>FIO_SET_OBJ_TYPE</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="c1">// default:</span> |
| <span class="cp">#define FIO_SET_OBJ_TYPE void * |
| </span></code></pre></div> |
| <p>Set's a Set or a Hash Map's object type. Defaults to <code>void *</code>.</p> |
| |
| <h4 id="fio_set_obj_compare"><code>FIO_SET_OBJ_COMPARE</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="c1">// default:</span> |
| <span class="cp">#define FIO_SET_OBJ_COMPARE(o1, o2) (1) |
| </span></code></pre></div> |
| <p>Compares two Set objects. This is only relevant to pure Sets (not Hash Maps). Defaults to doing nothing (always true).</p> |
| |
| <h4 id="fio_set_obj_copy"><code>FIO_SET_OBJ_COPY</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="c1">// default:</span> |
| <span class="cp">#define FIO_SET_OBJ_COPY(dest, obj) ((dest) = (obj)) |
| </span></code></pre></div> |
| <p>Copies an object's data from an external object to the internal storage. This allows String and other dynamic data to be copied and retained for the lifetime of the object.</p> |
| |
| <h4 id="fio_set_obj_destroy"><code>FIO_SET_OBJ_DESTROY</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="c1">// default:</span> |
| <span class="cp">#define FIO_SET_OBJ_DESTROY(obj) ((void)0) |
| </span></code></pre></div> |
| <p>Frees any allocated memory / resources used by the object data. By default this does nothing.</p> |
| |
| <h4 id="fio_set_key_type"><code>FIO_SET_KEY_TYPE</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#undef FIO_SET_KEY_TYPE |
| </span></code></pre></div> |
| <p>By defining a key type, the Set will be converted to a Hash Map and it's API will be slightly altered to reflect this change.</p> |
| |
| <p>By default, no key type is defined.</p> |
| |
| <h4 id="fio_set_key_compare"><code>FIO_SET_KEY_COMPARE</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_KEY_COMPARE(key1, key2) ((key1) == (key2)) |
| </span></code></pre></div> |
| <p>Compares two Hash Map keys.</p> |
| |
| <p>This is only relevant if the <code>FIO_SET_KEY_TYPE</code> was defined.</p> |
| |
| <h4 id="fio_set_key_copy"><code>FIO_SET_KEY_COPY</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_KEY_COPY(dest, key) ((dest) = (key)) |
| </span></code></pre></div> |
| <p>Copies the key's data from an external key to the internal storage. This allows String and other dynamic data to be copied and retained for the lifetime of the key-value pair.</p> |
| |
| <p>This is only relevant if the <code>FIO_SET_KEY_TYPE</code> was defined.</p> |
| |
| <h4 id="fio_set_key_destroy"><code>FIO_SET_KEY_DESTROY</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_KEY_DESTROY(key) ((void)0) |
| </span></code></pre></div> |
| <p>Frees any allocated memory / resources used by the key data. By default this does nothing.</p> |
| |
| <p>This is only relevant if the <code>FIO_SET_KEY_TYPE</code> was defined.</p> |
| |
| <h4 id="fio_set_realloc"><code>FIO_SET_REALLOC</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_REALLOC(ptr, original_size, new_size, valid_data_length) \ |
| realloc((ptr), (new_size)) |
| </span></code></pre></div> |
| <p>Allows for custom memory allocation / deallocation routines.</p> |
| |
| <p>The default allocator is facil.io's <code>fio_realloc</code>.</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <h4 id="fio_set_calloc"><code>FIO_SET_CALLOC</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_CALLOC(size, count) calloc((size), (count)) |
| </span></code></pre></div> |
| <p>Allows for custom memory allocation / deallocation routines.</p> |
| |
| <p>The default allocator is facil.io's <code>fio_calloc</code>.</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <h4 id="fio_set_free"><code>FIO_SET_FREE</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_FREE(ptr, size) free((ptr)) |
| </span></code></pre></div> |
| <p>Allows for custom memory allocation / deallocation routines.</p> |
| |
| <p>The default deallocator is facil.io's <code>fio_free</code>.</p> |
| |
| <p>To use the system's memory allocation / deallocation define <code>FIO_FORCE_MALLOC_TMP</code> as <code>1</code> before including <code>fio.h</code>.</p> |
| |
| <h3 id="naming-the-set-hash-map">Naming the Set / Hash Map</h3> |
| |
| <p>Because the type and function names are dictated by the <code>FIO_SET_NAME</code>, it's impossible to name the functions and types that will be created.</p> |
| |
| <p>For the purpose of this documentation, the <code>FIO_SET_NAME(name)</code> will mark a type / function name so that it's equal to <code>FIO_SET_NAME + "_" + name</code>.</p> |
| |
| <p>i.e., if <code>FIO_SET_NAME == foo</code> than <code>FIO_SET_NAME(s) == foo_s</code>.</p> |
| |
| <h3 id="set-hash-map-initialization">Set / Hash Map Initialization</h3> |
| |
| <h4 id="fio_set_name-s"><code>FIO_SET_NAME(s)</code></h4> |
| |
| <p>The Set's / Hash Map's type name. It's content should be considered opaque.</p> |
| |
| <h4 id="fio_set_init"><code>FIO_SET_INIT</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_INIT { .capa = 0 } |
| </span></code></pre></div> |
| <p>Initializes the Set or the Hash Map.</p> |
| |
| <h4 id="fio_set_name-free"><code>FIO_SET_NAME(free)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">free</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Frees all the objects in the Hash Map / Set and deallocates any internal resources.</p> |
| |
| <h3 id="hash-map-find-insert">Hash Map Find / Insert</h3> |
| |
| <p>These functions are defined if the Set defined is a Hash Map (<code>FIO_SET_KEY_TYPE</code> was defined).</p> |
| |
| <h4 id="fio_set_name-find-hash-map"><code>FIO_SET_NAME(find)</code> (Hash Map)</h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">FIO_SET_OBJ_TYPE</span> |
| <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">find</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">,</span> <span class="k">const</span> <span class="n">FIO_SET_HASH_TYPE</span> <span class="n">hash_value</span><span class="p">,</span> |
| <span class="n">FIO_SET_KEY_TYPE</span> <span class="n">key</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Locates an object in the Hash Map, if it exists.</p> |
| |
| <p><strong>Note</strong>: This is the function's Hash Map variant. See <code>FIO_SET_KEY_TYPE</code>.</p> |
| |
| <h4 id="fio_set_name-insert-hash-map"><code>FIO_SET_NAME(insert)</code> (Hash Map)</h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">insert</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">,</span> |
| <span class="k">const</span> <span class="n">FIO_SET_HASH_TYPE</span> <span class="n">hash_value</span><span class="p">,</span> |
| <span class="n">FIO_SET_KEY_TYPE</span> <span class="n">key</span><span class="p">,</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="n">obj</span><span class="p">,</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Inserts an object to the Hash Map, rehashing if required, returning the new object's location using a pointer.</p> |
| |
| <p>If an object already exists in the Hash Map, it will be destroyed.</p> |
| |
| <p>If <code>old</code> isn't NULL, the existing object (if any) will be copied to the location pointed to by <code>old</code> before it is destroyed.</p> |
| |
| <p><strong>Note</strong>: This is the function's Hash Map variant. See <code>FIO_SET_KEY_TYPE</code>.</p> |
| |
| <h4 id="fio_set_name-remove-hash-map"><code>FIO_SET_NAME(remove)</code> (Hash Map)</h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">remove</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">,</span> |
| <span class="k">const</span> <span class="n">FIO_SET_HASH_TYPE</span> <span class="n">hash_value</span><span class="p">,</span> |
| <span class="n">FIO_SET_KEY_TYPE</span> <span class="n">key</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes an object from the Set, rehashing if required.</p> |
| |
| <p>Returns 0 on success and -1 if the object wasn't found.</p> |
| |
| <p>If <code>old</code> isn't <code>NULL</code>, than the existing object (if any) would be copied to the location pointed to by <code>old</code>.</p> |
| |
| <p><strong>Note</strong>: This is the function's Hash Map variant. See <code>FIO_SET_KEY_TYPE</code>.</p> |
| |
| <h3 id="set-find-insert">Set Find / Insert</h3> |
| |
| <p>These functions are defined if the Set is a pure Set (not a Hash Map).</p> |
| |
| <h4 id="fio_set_name-find-set"><code>FIO_SET_NAME(find)</code> (Set)</h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">FIO_SET_OBJ_TYPE</span> |
| <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">find</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">,</span> <span class="k">const</span> <span class="n">FIO_SET_HASH_TYPE</span> <span class="n">hash_value</span><span class="p">,</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="n">obj</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Locates an object in the Set, if it exists.</p> |
| |
| <p><strong>Note</strong>: This is the function's pure Set variant (no <code>FIO_SET_KEY_TYPE</code>).</p> |
| |
| <h4 id="fio_set_name-insert-set"><code>FIO_SET_NAME(insert)</code> (Set)</h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">FIO_SET_OBJ_TYPE</span> |
| <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">insert</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">,</span> <span class="k">const</span> <span class="n">FIO_SET_HASH_TYPE</span> <span class="n">hash_value</span><span class="p">,</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="n">obj</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Inserts an object to the Set only if it's missing, rehashing if required, returning the new (or old) object's pointer.</p> |
| |
| <p>If the object already exists in the set, than the new object will be destroyed and the old object will be returned.</p> |
| |
| <p><strong>Note</strong>: This is the function's pure Set variant (no <code>FIO_SET_KEY_TYPE</code>).</p> |
| |
| <h4 id="fio_set_name-overwrite-set"><code>FIO_SET_NAME(overwrite)</code> (Set)</h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">FIO_SET_OBJ_TYPE</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">overwrite</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">,</span> |
| <span class="k">const</span> <span class="n">FIO_SET_HASH_TYPE</span> <span class="n">hash_value</span><span class="p">,</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="n">obj</span><span class="p">,</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Inserts an object to the Set only overwriting any existing data, rehashing if required.</p> |
| |
| <p>If <code>old</code> is set, the old object (if any) will be copied to the location pointed to by <code>old</code>.</p> |
| |
| <p><strong>Note</strong>: This function doesn't exist when <code>FIO_SET_KEY_TYPE</code> is defined.</p> |
| |
| <h4 id="fio_set_name-remove-set"><code>FIO_SET_NAME(remove)</code> (Set)</h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">remove</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">,</span> |
| <span class="k">const</span> <span class="n">FIO_SET_HASH_TYPE</span> <span class="n">hash_value</span><span class="p">,</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="n">obj</span><span class="p">,</span> |
| <span class="n">FIO_SET_OBJ_TYPE</span> <span class="o">*</span><span class="n">old</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Removes an object from the Set, rehashing if required.</p> |
| |
| <p>Returns 0 on success and -1 if the object wasn't found.</p> |
| |
| <p>If <code>old</code> is set, the old object (if any) will be copied to the location pointed to by <code>old</code>.</p> |
| |
| <p><strong>Note</strong>: This is the function's pure Set variant (no <code>FIO_SET_KEY_TYPE</code>).</p> |
| |
| <h3 id="set-hash-map-data">Set / Hash Map Data</h3> |
| |
| <h4 id="fio_set_name-last"><code>FIO_SET_NAME(last)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="n">FIO_SET_TYPE</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">last</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Allows a peak at the Set's last element.</p> |
| |
| <p>Remember that objects might be destroyed if the Set is altered (<code>FIO_SET_OBJ_DESTROY</code> / <code>FIO_SET_KEY_DESTROY</code>).</p> |
| |
| <h4 id="fio_set_name-pop"><code>FIO_SET_NAME(pop)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">pop</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Allows the Hash to be momentarily used as a stack, destroying the last object added (<code>FIO_SET_OBJ_DESTROY</code> / <code>FIO_SET_KEY_DESTROY</code>).</p> |
| |
| <h4 id="fio_set_name-count"><code>FIO_SET_NAME(count)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">count</span><span class="p">)(</span><span class="k">const</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the number of object currently in the Set.</p> |
| |
| <h4 id="fio_set_name-capa"><code>FIO_SET_NAME(capa)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">capa</span><span class="p">)(</span><span class="k">const</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns a temporary theoretical Set capacity.</p> |
| |
| <p>This could be used for testing performance and memory consumption.</p> |
| |
| <h4 id="fio_set_name-capa_require"><code>FIO_SET_NAME(capa_require)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">capa_require</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">,</span> |
| <span class="kt">size_t</span> <span class="n">min_capa</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Requires that a Set contains the minimal requested theoretical capacity.</p> |
| |
| <p>Returns the actual (temporary) theoretical capacity.</p> |
| |
| <h4 id="fio_set_name-is_fragmented"><code>FIO_SET_NAME(is_fragmented)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">is_fragmented</span><span class="p">)(</span><span class="k">const</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns non-zero if the Set is fragmented (more than 50% holes).</p> |
| |
| <h4 id="fio_set_name-compact"><code>FIO_SET_NAME(compact)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">size_t</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">compact</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Attempts to minimize memory usage by removing empty spaces caused by deleted items and rehashing the Set.</p> |
| |
| <p>Returns the updated Set capacity.</p> |
| |
| <h4 id="fio_set_name-rehash"><code>FIO_SET_NAME(rehash)</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">rehash</span><span class="p">)(</span><span class="n">FIO_SET_NAME</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">*</span> <span class="n">set</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Forces a rehashing of the Set.</p> |
| |
| <h4 id="fio_set_for_loop"><code>FIO_SET_FOR_LOOP</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_SET_FOR_LOOP(set, pos) // ... |
| </span></code></pre></div> |
| <p>A macro for a <code>for</code> loop that iterates over all the Set's objects (in order).</p> |
| |
| <p><code>set</code> is a pointer to the Set variable and <code>pos</code> is a temporary variable name to be created for iteration.</p> |
| |
| <p><code>pos->hash</code> is the hashing value.</p> |
| |
| <p>For Hash Maps, <code>pos->obj</code> is a key / value couplet, requiring a selection of <code>pos->obj.key</code> / <code>pos->obj.obj</code>.</p> |
| |
| <p>For Pure Sets. the <code>pos->obj</code> is the actual object data.</p> |
| |
| <p><strong>Important</strong>: Since the Set might have "holes" (objects that were removed), it is important to skip any <code>pos->hash == 0</code> or the equivalent of <code>FIO_SET_HASH_COMPARE(pos->hash, FIO_SET_HASH_INVALID)</code>.</p> |
| |
| <h2 id="general-helpers">General Helpers</h2> |
| |
| <p>Network applications require many common tasks, such as Atomic operations, locks, string to number conversions etc'</p> |
| |
| <p>Many of the helper functions used by the facil.io core library are exposed for client use.</p> |
| |
| <h3 id="atomic-operations">Atomic operations</h3> |
| |
| <h4 id="fio_atomic_xchange"><code>fio_atomic_xchange</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_atomic_xchange(p_obj, value) </span><span class="cm">/* compiler specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>An atomic exchange operation, sets a new value and returns the previous one.</p> |
| |
| <p><code>p_obj</code> must be a pointer to the object (not the object itself).</p> |
| |
| <p><code>value</code> is the new value to be set.</p> |
| |
| <h4 id="fio_atomic_add"><code>fio_atomic_add</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_atomic_add(p_obj, value) </span><span class="cm">/* compiler specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>An atomic addition operation.</p> |
| |
| <p>Returns the new value.</p> |
| |
| <p><code>p_obj</code> must be a pointer to the object (not the object itself).</p> |
| |
| <p><code>value</code> is the new value to be set.</p> |
| |
| <h4 id="fio_atomic_sub"><code>fio_atomic_sub</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_atomic_sub(p_obj, value) </span><span class="cm">/* compiler specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>An atomic subtraction operation.</p> |
| |
| <p>Returns the new value.</p> |
| |
| <p><code>p_obj</code> must be a pointer to the object (not the object itself).</p> |
| |
| <p><code>value</code> is the new value to be set.</p> |
| |
| <h3 id="atomic-locks">Atomic locks</h3> |
| |
| <p>Atomic locks the <code>fio_lock_i</code> type.</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">typedef</span> <span class="kt">uint8_t</span> <span class="k">volatile</span> <span class="n">fio_lock_i</span><span class="p">;</span> |
| <span class="cp">#define FIO_LOCK_INIT 0 |
| </span></code></pre></div> |
| <h4 id="fio_trylock"><code>fio_trylock</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_trylock</span><span class="p">(</span><span class="n">fio_lock_i</span> <span class="o">*</span><span class="n">lock</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns 0 if the lock was acquired and non-zero on failure.</p> |
| |
| <h4 id="fio_lock"><code>fio_lock</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="n">fio_lock</span><span class="p">(</span><span class="n">fio_lock_i</span> <span class="o">*</span><span class="n">lock</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Busy waits for the lock - CAREFUL, <code>fio_trylock</code> should be preferred.</p> |
| |
| <h4 id="fio_is_locked"><code>fio_is_locked</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_is_locked</span><span class="p">(</span><span class="n">fio_lock_i</span> <span class="o">*</span><span class="n">lock</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns the current lock's state (non 0 == Busy).</p> |
| |
| <h4 id="fio_unlock"><code>fio_unlock</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">int</span> <span class="n">fio_unlock</span><span class="p">(</span><span class="n">fio_lock_i</span> <span class="o">*</span><span class="n">lock</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Releases a lock. Returns non-zero if the lock was previously locked.</p> |
| |
| <p><strong>Note</strong>: Releasing an un-acquired will break the lock and could cause it's protection to fail. Make sure to only release the lock if it was previously acquired by the same "owner".</p> |
| |
| <h4 id="fio_reschedule_thread"><code>fio_reschedule_thread</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="n">fio_reschedule_thread</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Reschedules a thread (used as part of the <code>fio_lock</code> busy wait logic).</p> |
| |
| <p>Implemented using <code>nanosleep</code>, which seems to be the most effective and efficient thread rescheduler.</p> |
| |
| <h4 id="fio_throttle_thread"><code>fio_throttle_thread</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">void</span> <span class="n">fio_throttle_thread</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">nano_sec</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A blocking throttle using <code>nanosleep</code>.</p> |
| |
| <h3 id="byte-ordering-helpers-network-vs-local">Byte Ordering Helpers (Network vs. Local)</h3> |
| |
| <p>Different byte ordering schemes often effect network applications, especially when sending binary data.</p> |
| |
| <p>The 16 bit number might be represented as <code>0xaf00</code> on one machine and as <code>0x00af</code> on another.</p> |
| |
| <p>These helpers help concert between network byte ordering (Big Endian) to a local byte ordering scheme.</p> |
| |
| <p>These helpers also help extract numerical content from a binary string.</p> |
| |
| <h4 id="fio_lton16"><code>fio_lton16</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_lton16(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Local byte order to Network byte order, 16 bit integer.</p> |
| |
| <h4 id="fio_lton32"><code>fio_lton32</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_lton32(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Local byte order to Network byte order, 32 bit integer.</p> |
| |
| <h4 id="fio_lton64"><code>fio_lton64</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_lton64(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Local byte order to Network byte order, 62 bit integer.</p> |
| |
| <h4 id="fio_str2u16"><code>fio_str2u16</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_str2u16(c) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Reads a 16 bit number from an unaligned network ordered byte stream.</p> |
| |
| <p>Using this function makes it easy to avoid unaligned memory access issues.</p> |
| |
| <h4 id="fio_str2u32"><code>fio_str2u32</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_str2u32(c) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Reads a 32 bit number from an unaligned network ordered byte stream.</p> |
| |
| <p>Using this function makes it easy to avoid unaligned memory access issues.</p> |
| |
| <h4 id="fio_str2u64"><code>fio_str2u64</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_str2u64(c) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Reads a 64 bit number from an unaligned network ordered byte stream.</p> |
| |
| <p>Using this function makes it easy to avoid unaligned memory access issues.</p> |
| |
| <h4 id="fio_u2str16"><code>fio_u2str16</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_u2str16(buffer, i) </span><span class="cm">/* simple byte value assignment using network order */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Writes a local 16 bit number to an unaligned buffer in network order.</p> |
| |
| <p>No error checks or buffer tests are performed - make sure the buffer has at least 2 bytes available.</p> |
| |
| <h4 id="fio_u2str32"><code>fio_u2str32</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_u2str32(buffer, i) </span><span class="cm">/* simple byte value assignment using network order */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Writes a local 32 bit number to an unaligned buffer in network order.</p> |
| |
| <p>No error checks or buffer tests are performed - make sure the buffer has at least 4 bytes available.</p> |
| |
| <h4 id="fio_u2str64"><code>fio_u2str64</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_u2str64(buffer, i) </span><span class="cm">/* simple byte value assignment using network order */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Writes a local 64 bit number to an unaligned buffer in network order.</p> |
| |
| <p>No error checks or buffer tests are performed - make sure the buffer has at least 8 bytes available.</p> |
| |
| <h4 id="fio_ntol16"><code>fio_ntol16</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_ntol16(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Network byte order to Local byte order, 16 bit integer.</p> |
| |
| <h4 id="fio_ntol32"><code>fio_ntol32</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_ntol32(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Network byte order to Local byte order, 32 bit integer.</p> |
| |
| <h4 id="fio_ntol64"><code>fio_ntol64</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_ntol64(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Network byte order to Local byte order, 62 bit integer.</p> |
| |
| <h4 id="fio_bswap16"><code>fio_bswap16</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_bswap16(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Swaps the byte order in a 16 bit integer.</p> |
| |
| <h4 id="fio_bswap32"><code>fio_bswap32</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_bswap32(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Swaps the byte order in a 32 bit integer.</p> |
| |
| <h4 id="fio_bswap64"><code>fio_bswap64</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_bswap64(i) </span><span class="cm">/* system specific */</span><span class="cp"> |
| </span></code></pre></div> |
| <p>Swaps the byte order in a 64 bit integer.</p> |
| |
| <h3 id="strings-to-numbers">Strings to Numbers</h3> |
| |
| <h4 id="fio_atol"><code>fio_atol</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int64_t</span> <span class="n">fio_atol</span><span class="p">(</span><span class="kt">char</span> <span class="o">**</span><span class="n">pstr</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Converts between String data to a signed <code>int64_t</code>.</p> |
| |
| <p>Numbers are assumed to be in base 10.</p> |
| |
| <p>Octal (<code>0###</code>), Hex (<code>0x##</code>/<code>x##</code>) and binary (<code>0b##</code>/ <code>b##</code>) are recognized as well. For binary Most Significant Bit must come first.</p> |
| |
| <p>The most significant difference between this function and <code>strtol</code> (aside of API design and speed), is the added support for binary representations.</p> |
| |
| <h4 id="fio_atof"><code>fio_atof</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">double</span> <span class="n">fio_atof</span><span class="p">(</span><span class="kt">char</span> <span class="o">**</span><span class="n">pstr</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A helper function that converts between String data to a signed double.</p> |
| |
| <p>Implemented using the standard <code>strtold</code> library function.</p> |
| |
| <h3 id="numbers-to-strings">Numbers to Strings</h3> |
| |
| <h4 id="fio_ltoa"><code>fio_ltoa</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">size_t</span> <span class="n">fio_ltoa</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">num</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">base</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A helper function that writes a signed int64_t to a string.</p> |
| |
| <p>No overflow guard is provided, make sure there's at least 68 bytes available (for base 2).</p> |
| |
| <p>Offers special support for base 2 (binary), base 8 (octal), base 10 and base 16 (hex). An unsupported base will silently default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the beginning of the string).</p> |
| |
| <p>Returns the number of bytes actually written (excluding the NUL terminator).</p> |
| |
| <h4 id="fio_ftoa"><code>fio_ftoa</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">size_t</span> <span class="n">fio_ftoa</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="kt">double</span> <span class="n">num</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">base</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A helper function that converts between a double to a string.</p> |
| |
| <p>No overflow guard is provided, make sure there's at least 130 bytes |
| available (for base 2).</p> |
| |
| <p>Supports base 2, base 10 and base 16. An unsupported base will silently |
| default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the |
| beginning of the string).</p> |
| |
| <p>Returns the number of bytes actually written (excluding the NUL |
| terminator).</p> |
| |
| <h3 id="random-data-generation">Random data Generation</h3> |
| |
| <h4 id="fio_rand64"><code>fio_rand64</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">uint64_t</span> <span class="n">fio_rand64</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Returns 64 psedo-random bits. Probably not cryptographically safe.</p> |
| |
| <h4 id="fio_rand_bytes"><code>fio_rand_bytes</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_rand_bytes</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Writes <code>length</code> bytes of psedo-random bits to the target buffer. Probably not cryptographically safe.</p> |
| |
| <h3 id="base64">Base64</h3> |
| |
| <h4 id="fio_base64_encode"><code>fio_base64_encode</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_base64_encode</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>This will encode a byte array (data) of a specified length and place the encoded data into the target byte buffer (target). The target buffer MUST have enough room for the expected data.</p> |
| |
| <p>Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if the raw data's length isn't devisable by 3.</p> |
| |
| <p>Always assume the target buffer should have room enough for (len*4/3 + 4) bytes.</p> |
| |
| <p>Returns the number of bytes actually written to the target buffer (including the Base64 required padding and excluding a NULL terminator).</p> |
| |
| <p>A NULL terminator char is NOT written to the target buffer.</p> |
| |
| <h4 id="fio_base64url_encode"><code>fio_base64url_encode</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_base64url_encode</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Same as <a href="#fio_base64_encode"><code>fio_base64_encode</code></a>, but using Base64URL encoding.</p> |
| |
| <h4 id="fio_base64_decode"><code>fio_base64_decode</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_base64_decode</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">encoded</span><span class="p">,</span> <span class="kt">int</span> <span class="n">base64_len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>This will decode a Base64 encoded string of a specified length (len) and place the decoded data into the target byte buffer (target).</p> |
| |
| <p>The target buffer MUST have enough room for 2 bytes in addition to the expected data (NUL byte + padding test).</p> |
| |
| <p>A NUL byte will be appended to the target buffer. The function will return the number of bytes written to the target buffer (excluding the NUL byte).</p> |
| |
| <p>If the target buffer is NUL, the encoded string will be destructively edited and the decoded data will be placed in the original string's buffer.</p> |
| |
| <p>Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if the raw data's length isn't devisable by 3. Hence, the target buffer should be, at least, <code>base64_len/4*3 + 3</code> long.</p> |
| |
| <p>Returns the number of bytes actually written to the target buffer (excluding the NUL terminator byte).</p> |
| |
| <p><strong>Note</strong>:</p> |
| |
| <p>The decoder is variation agnostic (will decode Base64, Base64 URL and Base64 XML variations) and will attempt it's best to ignore invalid data, (in order to support the MIME Base64 variation in RFC 2045).</p> |
| |
| <p>This comes at the cost of error checking, so the encoding isn't validated and invalid input might produce surprising results.</p> |
| |
| <h3 id="siphash">SipHash</h3> |
| |
| <h4 id="fio_siphash24"><code>fio_siphash24</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">uint64_t</span> <span class="n">fio_siphash24</span><span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A SipHash variation (2-4).</p> |
| |
| <h4 id="fio_siphash13"><code>fio_siphash13</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">uint64_t</span> <span class="n">fio_siphash13</span><span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A SipHash 1-3 variation.</p> |
| |
| <h4 id="fio_siphash"><code>fio_siphash</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define fio_siphash(data, length) fio_siphash13((data), (length)) |
| </span></code></pre></div> |
| <p>The Hashing function used by dynamic facil.io objects.</p> |
| |
| <p>Currently implemented using SipHash 1-3.</p> |
| |
| <h3 id="sha-1">SHA-1</h3> |
| |
| <p>SHA-1 example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_sha1_s</span> <span class="n">sha1</span><span class="p">;</span> |
| <span class="n">fio_sha1_init</span><span class="p">(</span><span class="o">&</span><span class="n">sha1</span><span class="p">);</span> |
| <span class="n">fio_sha1_write</span><span class="p">(</span><span class="o">&</span><span class="n">sha1</span><span class="p">,</span> |
| <span class="s">"The quick brown fox jumps over the lazy dog"</span><span class="p">,</span> <span class="mi">43</span><span class="p">);</span> |
| <span class="kt">char</span> <span class="o">*</span><span class="n">hashed_result</span> <span class="o">=</span> <span class="n">fio_sha1_result</span><span class="p">(</span><span class="o">&</span><span class="n">sha1</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_sha1_init"><code>fio_sha1_init</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_sha1_s</span> <span class="n">fio_sha1_init</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Initializes or resets the <code>fio_sha1_s</code> object. This must be performed before hashing data using SHA-1.</p> |
| |
| <p>The SHA-1 container type (<code>fio_sha1_s</code>) is defines as follows:</p> |
| |
| <p>The <code>fio_sha1_s</code> structure's content should be ignored.</p> |
| |
| <h4 id="fio_sha1"><code>fio_sha1</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">char</span> <span class="o">*</span><span class="n">fio_sha1</span><span class="p">(</span><span class="n">fio_sha1_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">)</span> |
| </code></pre></div> |
| <p>A SHA1 helper function that performs initialization, writing and finalizing.</p> |
| |
| <p>SHA-1 hashing container - </p> |
| |
| <p>The <code>sha1_s</code> type will contain all the sha1 data required to perform the |
| hashing, managing it's encoding. If it's stack allocated, no freeing will be |
| required.</p> |
| |
| <h4 id="fio_sha1_write"><code>fio_sha1_write</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_sha1_write</span><span class="p">(</span><span class="n">fio_sha1_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Writes data to the sha1 buffer.</p> |
| |
| <h4 id="fio_sha1_result"><code>fio_sha1_result</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">char</span> <span class="o">*</span><span class="n">fio_sha1_result</span><span class="p">(</span><span class="n">fio_sha1_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Finalizes the SHA1 hash, returning the Hashed data.</p> |
| |
| <p><code>fio_sha1_result</code> can be called for the same object multiple times, but the finalization will only be performed the first time this function is called.</p> |
| |
| <h3 id="sha-2">SHA-2</h3> |
| |
| <p>SHA-2 example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_sha2_s</span> <span class="n">sha2</span><span class="p">;</span> |
| <span class="n">fio_sha2_init</span><span class="p">(</span><span class="o">&</span><span class="n">sha2</span><span class="p">,</span> <span class="n">SHA_512</span><span class="p">);</span> |
| <span class="n">fio_sha2_write</span><span class="p">(</span><span class="o">&</span><span class="n">sha2</span><span class="p">,</span> |
| <span class="s">"The quick brown fox jumps over the lazy dog"</span><span class="p">,</span> <span class="mi">43</span><span class="p">);</span> |
| <span class="kt">char</span> <span class="o">*</span><span class="n">hashed_result</span> <span class="o">=</span> <span class="n">fio_sha2_result</span><span class="p">(</span><span class="o">&</span><span class="n">sha2</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_sha2_init"><code>fio_sha2_init</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">fio_sha2_s</span> <span class="n">fio_sha2_init</span><span class="p">(</span><span class="n">fio_sha2_variant_e</span> <span class="n">variant</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Initializes / resets the SHA-2 object.</p> |
| |
| <p>SHA-2 is actually a family of functions with different variants. When initializing the SHA-2 container, a variant must be chosen. The following are valid variants:</p> |
| |
| <ul> |
| <li><p><code>SHA_512</code></p></li> |
| <li><p><code>SHA_384</code></p></li> |
| <li><p><code>SHA_512_224</code></p></li> |
| <li><p><code>SHA_512_256</code></p></li> |
| <li><p><code>SHA_256</code></p></li> |
| <li><p><code>SHA_224</code></p></li> |
| </ul> |
| |
| <p>The <code>fio_sha2_s</code> structure's content should be ignored.</p> |
| |
| <h4 id="fio_sha2_write"><code>fio_sha2_write</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_sha2_write</span><span class="p">(</span><span class="n">fio_sha2_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Writes data to the SHA-2 buffer.</p> |
| |
| <h4 id="fio_sha2_result"><code>fio_sha2_result</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">char</span> <span class="o">*</span><span class="n">fio_sha2_result</span><span class="p">(</span><span class="n">fio_sha2_s</span> <span class="o">*</span><span class="n">s</span><span class="p">);</span> |
| </code></pre></div> |
| <p>Finalizes the SHA-2 hash, returning the Hashed data.</p> |
| |
| <p><code>sha2_result</code> can be called for the same object multiple times, but the finalization will only be performed the first time this function is called.</p> |
| |
| <h4 id="fio_sha2_512"><code>fio_sha2_512</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">char</span> <span class="o">*</span><span class="n">fio_sha2_512</span><span class="p">(</span><span class="n">fio_sha2_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> |
| <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A SHA-2 helper function that performs initialization, writing and finalizing.</p> |
| |
| <p>Uses the SHA2 512 variant.</p> |
| |
| <h4 id="fio_sha2_256"><code>fio_sha2_256</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">char</span> <span class="o">*</span><span class="n">fio_sha2_256</span><span class="p">(</span><span class="n">fio_sha2_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> |
| <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A SHA-2 helper function that performs initialization, writing and finalizing.</p> |
| |
| <p>Uses the SHA2 256 variant.</p> |
| |
| <h4 id="fio_sha2_256"><code>fio_sha2_256</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kr">inline</span> <span class="kt">char</span> <span class="o">*</span><span class="n">fio_sha2_384</span><span class="p">(</span><span class="n">fio_sha2_s</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> |
| <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span> |
| </code></pre></div> |
| <p>A SHA-2 helper function that performs initialization, writing and finalizing.</p> |
| |
| <p>Uses the SHA2 384 variant.</p> |
| |
| <h2 id="version-and-compilation-related-macros">Version and Compilation Related Macros</h2> |
| |
| <p>The following macros effect facil.io's compilation and can be used to validate the API version exposed by the library.</p> |
| |
| <h3 id="version-macros">Version Macros</h3> |
| |
| <p>The version macros relate the version for both facil.io's core library and it's bundled extensions.</p> |
| |
| <h4 id="fio_version_major"><code>FIO_VERSION_MAJOR</code></h4> |
| |
| <p>The major version macro is currently zero (0), since the facil.io library's API should still be considered unstable.</p> |
| |
| <p>In the future, API breaking changes will cause this number to change.</p> |
| |
| <h4 id="fio_version_minor"><code>FIO_VERSION_MINOR</code></h4> |
| |
| <p>The minor version normally represents new feature or substantial changes that don't effect existing API.</p> |
| |
| <p>However, as long as facil.io's major version is zero (0), API breaking changes will cause the minor version (rather than the major version) to change.</p> |
| |
| <h4 id="fio_version_patch"><code>FIO_VERSION_PATCH</code></h4> |
| |
| <p>The patch version is usually indicative to bug fixes.</p> |
| |
| <p>However, as long as facil.io's major version is zero (0), new feature or substantial changes will cause the patch version to change.</p> |
| |
| <h4 id="fio_version_beta"><code>FIO_VERSION_BETA</code></h4> |
| |
| <p>A number representing a pre-release beta version.</p> |
| |
| <p>This indicates the API might change without notice and effects the <code>FIO_VERSION_STRING</code>.</p> |
| |
| <h4 id="fio_version_string"><code>FIO_VERSION_STRING</code></h4> |
| |
| <p>This macro translates to facil.io's literal string. It can be used, for example, like this:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">printf</span><span class="p">(</span><span class="s">"Running facil.io version"</span> <span class="n">FIO_VERSION_STRING</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">);</span> |
| </code></pre></div> |
| <h3 id="logging-macros">Logging Macros</h3> |
| |
| <p>facil.io provides a number of possible logging levels and macros for easy logging to <code>stderr</code>.</p> |
| |
| <h4 id="fio_log_level"><code>FIO_LOG_LEVEL</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="k">extern</span> <span class="kt">size_t</span> <span class="n">FIO_LOG_LEVEL</span><span class="p">;</span> |
| </code></pre></div> |
| <p>This variable sets / gets the logging level. Supported values include:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cm">/** Logging level of zero (no logging). */</span> |
| <span class="cp">#define FIO_LOG_LEVEL_NONE 0 |
| </span><span class="cm">/** Log fatal errors. */</span> |
| <span class="cp">#define FIO_LOG_LEVEL_FATAL 1 |
| </span><span class="cm">/** Log errors and fatal errors. */</span> |
| <span class="cp">#define FIO_LOG_LEVEL_ERROR 2 |
| </span><span class="cm">/** Log warnings, errors and fatal errors. */</span> |
| <span class="cp">#define FIO_LOG_LEVEL_WARNING 3 |
| </span><span class="cm">/** Log every message (info, warnings, errors and fatal errors). */</span> |
| <span class="cp">#define FIO_LOG_LEVEL_INFO 4 |
| </span><span class="cm">/** Log everything, including debug messages. */</span> |
| <span class="cp">#define FIO_LOG_LEVEL_DEBUG 5 |
| </span></code></pre></div> |
| <h4 id="fio_log_fatal"><code>FIO_LOG_FATAL</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LOG_FATAL(...) |
| </span></code></pre></div> |
| <p>Logs a fatal error. Doesn't exit the program (this should be performed after the logging).</p> |
| |
| <p>Logging macros accept <code>printf</code> type arguments. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_LOG_FATAL</span><span class="p">(</span><span class="s">"The meaning of life: %d"</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_log_error"><code>FIO_LOG_ERROR</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LOG_ERROR(...) |
| </span></code></pre></div> |
| <p>Logs an error.</p> |
| |
| <p>Logging macros accept <code>printf</code> type arguments. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_LOG_ERROR</span><span class="p">(</span><span class="s">"The meaning of life: %d"</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_log_warning"><code>FIO_LOG_WARNING</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LOG_WARNING(...) |
| </span></code></pre></div> |
| <p>Logs a warning message.</p> |
| |
| <p>Logging macros accept <code>printf</code> type arguments. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_LOG_WARNING</span><span class="p">(</span><span class="s">"The meaning of life: %d"</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_log_info"><code>FIO_LOG_INFO</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LOG_INFO(...) |
| </span></code></pre></div> |
| <p>Logs an information level message.</p> |
| |
| <p>Logging macros accept <code>printf</code> type arguments. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_LOG_INFO</span><span class="p">(</span><span class="s">"The meaning of life: %d"</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_log_debug"><code>FIO_LOG_DEBUG</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LOG_DEBUG(...) |
| </span></code></pre></div> |
| <p>Logs a debug message.</p> |
| |
| <p>Logging macros accept <code>printf</code> type arguments. i.e.:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="n">FIO_LOG_DEBUG</span><span class="p">(</span><span class="s">"The meaning of life: %d"</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span> |
| </code></pre></div> |
| <h4 id="fio_log_length_limit"><code>FIO_LOG_LENGTH_LIMIT</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#define FIO_LOG_LENGTH_LIMIT 2048 |
| </span></code></pre></div> |
| <p>(since 0.7.0.beta3)</p> |
| |
| <p>Since logging uses stack memory rather than dynamic allocation, it's memory usage must be limited to avoid exploding the stack. The following sets the maximum stack memory used when logging events.</p> |
| |
| <p>Log messages that exceed this length will result in the message <em>ERROR: log line output too long (can't write)</em>.</p> |
| |
| <h3 id="compilation-macros">Compilation Macros</h3> |
| |
| <p>The facil.io core library has some hard coded values that can be adjusted by defining the following macros during compile time.</p> |
| |
| <h4 id="fio_max_sock_capacity"><code>FIO_MAX_SOCK_CAPACITY</code></h4> |
| |
| <p>This macro define the maximum hard coded number of connections per worker process.</p> |
| |
| <p>To be more accurate, this number represents the highest <code>fd</code> value allowed by library functions.</p> |
| |
| <p>If the soft coded OS limit is higher than this number, than this limit will be enforced instead.</p> |
| |
| <h4 id="fio_engine_poll"><code>FIO_ENGINE_POLL</code></h4> |
| |
| <p>If set, facil.io will prefer the <code>poll</code> system call over <code>epoll</code> or <code>kqueue</code>.</p> |
| |
| <p>It should be noted that for most use-cases, <code>epoll</code> and <code>kqueue</code> will perform better.</p> |
| |
| <h4 id="fio_cpu_cores_limit"><code>FIO_CPU_CORES_LIMIT</code></h4> |
| |
| <p>The facil.io startup procedure allows for auto-CPU core detection.</p> |
| |
| <p>Sometimes it would make sense to limit this auto-detection to a lower number, such as on systems with more than 32 cores.</p> |
| |
| <p>This is only relevant to automated values, when running facil.io with zero threads and processes, which invokes a large matrix of workers and threads (see <a href="#facil_start">facil_start</a>).</p> |
| |
| <p>This does NOT effect manually set (non-zero) worker/thread values.</p> |
| |
| <h4 id="fio_defer_throttle_progressive"><code>FIO_DEFER_THROTTLE_PROGRESSIVE</code></h4> |
| |
| <p>The progressive throttling model makes concurrency and parallelism more likely.</p> |
| |
| <p>Otherwise threads are assumed to be intended for "fallback" in case of slow user code, where a single thread should be active most of the time and other threads are activated only when that single thread is slow to perform. </p> |
| |
| <p>By default, <code>FIO_DEFER_THROTTLE_PROGRESSIVE</code> is true (1).</p> |
| |
| <h4 id="fio_print_state"><code>FIO_PRINT_STATE</code></h4> |
| |
| <p>When this macro is true (1), facil.io will enable the <code>FIO_LOG_STATE(msg, ...)</code> macro to print some default information level messages to stderr (startup / shutdown messages, etc').</p> |
| |
| <p>By default this macro is set to true.</p> |
| |
| <h4 id="fio_poll_max_events"><code>FIO_POLL_MAX_EVENTS</code></h4> |
| |
| <p>This macro sets the maximum number of IO events facil.io will pre-schedule at the beginning of each cycle, when using <code>epoll</code> or <code>kqueue</code> (not when using <code>poll</code>).</p> |
| |
| <p>Since this requires stack pre-allocated memory, this number shouldn't be set too high. Reasonable values range from 8 to 160.</p> |
| |
| <p>The default value is currently 64.</p> |
| |
| <h4 id="fio_use_urgent_queue"><code>FIO_USE_URGENT_QUEUE</code></h4> |
| |
| <p>This macro can be used to disable the priority queue given to outbound IO.</p> |
| |
| <h4 id="fio_pubsub_support"><code>FIO_PUBSUB_SUPPORT</code></h4> |
| |
| <p>If true (1), compiles the facil.io pub/sub API .</p> |
| |
| <h2 id="weak-functions">Weak functions</h2> |
| |
| <p>Weak functions are functions that can be over-ridden during the compilation / linking stage.</p> |
| |
| <p>This provides control over some operations such as thread creation and process forking, which could be important when integrating facil.io into a VM engine such as Ruby or JavaScript.</p> |
| |
| <h3 id="forking">Forking</h3> |
| |
| <h4 id="fio_fork"><code>fio_fork</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_fork</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> |
| </code></pre></div> |
| <p>OVERRIDE THIS to replace the default <code>fork</code> implementation.</p> |
| |
| <p>Should behaves like the system's <code>fork</code>.</p> |
| |
| <p>Current implementation simply calls <a href="http://man7.org/linux/man-pages/man2/fork.2.html"><code>fork</code></a>.</p> |
| |
| <h3 id="thread-creation">Thread Creation</h3> |
| |
| <h4 id="fio_thread_new"><code>fio_thread_new</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="o">*</span><span class="n">fio_thread_new</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">thread_func</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">),</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">);</span> |
| </code></pre></div> |
| <p>OVERRIDE THIS to replace the default <code>pthread</code> implementation.</p> |
| |
| <p>Accepts a pointer to a function and a single argument that should be executed |
| within a new thread.</p> |
| |
| <p>The function should allocate memory for the thread object and return a |
| pointer to the allocated memory that identifies the thread.</p> |
| |
| <p>On error NULL should be returned.</p> |
| |
| <p>The default implementation returns a <code>pthread_t *</code>.</p> |
| |
| <h4 id="fio_thread_free"><code>fio_thread_free</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">void</span> <span class="n">fio_thread_free</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">p_thr</span><span class="p">);</span> |
| </code></pre></div> |
| <p>OVERRIDE THIS to replace the default <code>pthread</code> implementation.</p> |
| |
| <p>Frees the memory associated with a thread identifier (allows the thread to |
| run it's course, just the identifier is freed).</p> |
| |
| <h4 id="fio_thread_join"><code>fio_thread_join</code></h4> |
| <div class="highlight"><pre class="highlight c"><code><span class="kt">int</span> <span class="n">fio_thread_join</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">p_thr</span><span class="p">);</span> |
| </code></pre></div> |
| <p>OVERRIDE THIS to replace the default <code>pthread</code> implementation.</p> |
| |
| <p>Accepts a pointer returned from <code>fio_thread_new</code> (should also free any |
| allocated memory) and joins the associated thread.</p> |
| |
| <p>Return value is ignored.</p> |
| </div><a href="/" id="sign"></a><div class="hidden" id="notice"><a class="notice_close" onclick="hide_notice()">X</a><div id="notice_text"></div></div><script>function change_themes() { |
| if(localStorage.getItem("theme") == 'dark') { |
| localStorage.setItem("theme", "light"); |
| } else { |
| localStorage.setItem("theme", "dark"); |
| } |
| $('body')[0].className = localStorage.getItem("theme"); |
| set_theme_link(); |
| $('#show_nav').attr('checked', false); |
| return false; |
| }; |
| function sidebar_name() { return window.location.pathname.slice(0, window.location.pathname.lastIndexOf("/")); } |
| function on_sidebar_link(e) { |
| sessionStorage.setItem("sidebar.expect", sidebar_name()); |
| sessionStorage.setItem("sidebar.pos", document.getElementById("side_bar").scrollTop); |
| } |
| function load_sidebar_pos() { |
| var e = document.getElementById("side_bar"); |
| if(!e) { |
| console.warn("No sidebar detected"); |
| return; |
| } |
| var expect = sidebar_name(); |
| if(sessionStorage.getItem("sidebar.expect") == expect) { |
| e.scrollTo(0, parseInt(sessionStorage.getItem("sidebar.pos"))); |
| } else { |
| sessionStorage.setItem("sidebar.expect", false); |
| sessionStorage.setItem("sidebar.pos", 0); |
| } |
| if(e) { |
| // add link callbacks |
| var links = document.links; |
| var count = links.length; |
| for (var i = 0; i < count; i++) { |
| var href = links[i].href; |
| if(href.startsWith(document.location.origin)) { |
| href = href.slice(document.location.origin.length); |
| } |
| if(href.startsWith(expect)) { |
| /* add link event */ |
| links[i].addEventListener("click", on_sidebar_link); |
| } |
| } |
| } |
| |
| }; |
| load_sidebar_pos(); |
| function set_theme_link() { |
| $("#theme").html( ( (localStorage.getItem("theme") == 'dark') ? "Day" : "Night") + " Theme" ); |
| } |
| $('body')[0].className = (localStorage.getItem("theme") == 'dark') ? "dark" : "light"; |
| set_theme_link(); |
| function show_notice() { document.getElementById("notice").classList.remove('hidden'); }; |
| function hide_notice() { document.getElementById("notice").classList.add('hidden'); }; |
| $('#toc').on("touchstart", function (e) { return true; } ); |
| $('#toc').on("hover", function (e) { return true; } ); |
| // hljs.initHighlighting(); |
| // Google Analytics |
| // if(location.hostname != "localhost") { |
| // (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ |
| // (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), |
| // m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) |
| // })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); |
| |
| // ga('create', 'UA-69931401-1', 'auto'); |
| // ga('send', 'pageview'); |
| // }</script></body></html> |