blob: 8743b82a1edb25ee0a3000e1352351af18503dca [file] [log] [blame] [raw]
<!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><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>
</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-&gt;on_data</code></a>
</li>
<li>
<a href="#fio_protocol_s-on_ready"><code>fio_protocol_s-&gt;on_ready</code></a>
</li>
<li>
<a href="#fio_protocol_s-on_shutdown"><code>fio_protocol_s-&gt;on_shutdown</code></a>
</li>
<li>
<a href="#fio_protocol_s-on_close"><code>fio_protocol_s-&gt;on_close</code></a>
</li>
<li>
<a href="#fio_protocol_s-ping"><code>fio_protocol_s-&gt;ping</code></a>
</li>
<li>
<a href="#fio_protocol_s-rsv"><code>fio_protocol_s-&gt;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="#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_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>
</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="#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&#39;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&#39;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&#39;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 &quot;recycled&quot; by the OS.</p>
<p>The structure looks like this:</p>
<pre><code class='highlight'><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>
<h4 id="fio_protocol_s-on_data"><code>fio_protocol_s-&gt;on_data</code></h4>
<pre><code class='highlight'><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>
<p>Called when a data is available.</p>
<p>The function is called under the protocol&#39;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-&gt;on_ready</code></h4>
<pre><code class='highlight'><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>
<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-&gt;on_shutdown</code></h4>
<pre><code class='highlight'><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>
<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-&gt;on_close</code></h4>
<pre><code class='highlight'><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>
<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-&gt;ping</code></h4>
<pre><code class='highlight'><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>
<p>Called when a connection&#39;s timeout was reached.</p>
<p>This callback is called outside of the protocol&#39;s normal locks to support pinging in cases where the <code>on_data</code> callback is running in the background (which shouldn&#39;t happen, but we know it sometimes does).</p>
<h4 id="fio_protocol_s-rsv"><code>fio_protocol_s-&gt;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 &quot;hijacking&quot; the socket from <code>facil.io</code>).</p>
<h4 id="fio_attach"><code>fio_attach</code></h4>
<pre><code class='highlight'><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>
<p>Attaches (or updates) a protocol object to a connection&#39;s uuid.</p>
<p>The new protocol object can be NULL, which will detach (&quot;hijack&quot;) the socket.</p>
<p>The old protocol&#39;s <code>on_close</code> (if any) will be scheduled.</p>
<p>On error, the new protocol&#39;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&#39;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>
<pre><code class='highlight'><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>
<p>Attaches (or updates) a protocol object to a file descriptor (fd).</p>
<p>The new protocol object can be NULL, which will detach (&quot;hijack&quot;) 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&#39;s <code>on_close</code> (if any) will be scheduled.</p>
<p>On error, the new protocol&#39;s <code>on_close</code> callback will be called immediately.</p>
<h4 id="fio_capa"><code>fio_capa</code></h4>
<pre><code class='highlight'><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>
<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&#39;t tested or known by facil.io.</p>
<p>The value of 0 indicates either that the facil.io library wasn&#39;t initialized
yet or that it&#39;s resources were already released.</p>
<h4 id="fio_timeout_set"><code>fio_timeout_set</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Gets a timeout for a specific connection. Returns 0 if none.</p>
<h4 id="fio_touch"><code>fio_touch</code></h4>
<pre><code class='highlight'><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>
<p>&quot;Touches&quot; a socket connection, resetting it&#39;s timeout counter.</p>
<h4 id="fio_force_event"><code>fio_force_event</code></h4>
<pre><code class='highlight'><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>
<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&#39;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>
<pre><code class='highlight'><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>
<p>Temporarily prevents <code>on_data</code> events from firing.</p>
<p>Note: the function will work as expected when called within the protocol&#39;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&#39;s protocol and call <a href="#fio_attach"><code>fio_attach</code></a> to attach a protocol to the connection&#39;s uuid.</p>
<p>The protocol&#39;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>
<pre><code class='highlight'><span class="cp">#include &lt;fio.h&gt;
</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">&gt;</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">&amp;&amp;</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">&amp;&amp;</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>
<h4 id="fio_listen"><code>fio_listen</code></h4>
<pre><code class='highlight'><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>
<p>The <code>fio_listen</code> function is shadowed by the <code>fio_listen</code> MACRO, which allows the function to accept &quot;named arguments&quot;, as shown above in the example code:</p>
<pre><code class='highlight'> <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>
<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&#39;s uuid and a void pointer (the optional <code>udata</code> pointer one passed to <code>fio_listen</code>)</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">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>
</code></pre></li>
<li><p><code>port</code>:</p>
<p>The network service / port. A NULL or &quot;0&quot; port indicates a Unix socket should be used.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">port</span><span class="p">;</span>
</code></pre></li>
<li><p><code>address</code>:</p>
<p>The socket binding address. Defaults to the recommended NULL (recommended for TCP/IP).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">address</span><span class="p">;</span>
</code></pre></li>
<li><p><code>udata</code>:</p>
<p>Opaque user data. This will be passed along to the <code>on_open</code> callback.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre></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>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_start</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>
</code></pre></li>
<li><p><code>on_finish</code>:</p>
<p>A callback to be called for every process once the listening socket is closed.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_finish</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>
</code></pre></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>
<pre><code class='highlight'><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>
<p>The <code>fio_connect</code> function is shadowed by the <code>fio_connect</code> MACRO, which allows the function to accept &quot;named arguments&quot;, 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 &quot;0&quot; port indicates a Unix socket connection should be attempted.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">port</span><span class="p">;</span>
</code></pre></li>
<li><p><code>address</code>:</p>
<p>The remote (or Unix socket) address. Defaults to the recommended NULL (recommended for TCP/IP).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">address</span><span class="p">;</span>
</code></pre></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&#39;s uuid and a void pointer (the optional <code>udata</code> pointer one passed to <code>fio_connect</code>)</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_connect</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>
</code></pre></li>
<li><p><code>on_connect</code>:</p>
<p>This callback will be called when a socket fails to connect. It&#39;s often a good place for cleanup.</p>
<p>The callback should accept the attempted connection&#39;s uuid (might be -1) and a void pointer (the optional <code>udata</code> pointer one passed to <code>fio_connect</code>)</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_connect</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>
</code></pre></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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre></li>
<li><p><code>timeout</code>:</p>
<p>A non-system timeout after which connection is assumed to have failed.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">uint8_t</span> <span class="n">timeout</span><span class="p">;</span>
</code></pre></li>
</ul>
<h3 id="manual-protocol-locking">Manual Protocol Locking</h3>
<h4 id="fio_protocol_try_lock"><code>fio_protocol_try_lock</code></h4>
<pre><code class='highlight'><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>
<p>This function allows out-of-task access to a connection&#39;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&#39;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&#39;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>
<pre><code class='highlight'><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>
<p>Don&#39;t unlock what you didn&#39;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 &quot;hot restart&quot; is enabled (using the USR1 signal).</p>
<h4 id="fio_start"><code>fio_start</code></h4>
<pre><code class='highlight'><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>
<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 &quot;named arguments&quot;, i.e.:</p>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">int16_t</span> <span class="n">threads</span><span class="p">;</span>
</code></pre></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&#39;s cluster mode, where a crashed worker will be automatically re-spawned and &quot;hot restart&quot; is enabled (using the USR1 signal).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">int16_t</span> <span class="n">workers</span><span class="p">;</span>
</code></pre></li>
</ul>
<p>Negative thread / worker values indicate a fraction of the number of CPU cores. i.e., -2 will normally indicate &quot;half&quot; (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&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;t running or is winding down (during shutdown).</p>
<h4 id="fio_is_worker"><code>fio_is_worker</code></h4>
<pre><code class='highlight'><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>
<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&#39;t automatically re-spawn after critical errors.</p>
<h4 id="fio_parent_pid"><code>fio_parent_pid</code></h4>
<pre><code class='highlight'><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>
<p>Returns facil.io&#39;s parent (root) process pid.</p>
<h4 id="fio_reap_children"><code>fio_reap_children</code></h4>
<pre><code class='highlight'><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>
<p>Initializes zombie reaping for the process. Call before <code>fio_start</code> to enable
global zombie reaping.</p>
<h4 id="fio_last_tick"><code>fio_last_tick</code></h4>
<pre><code class='highlight'><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>
<p>Returns the last time facil.io reviewed any pending IO events.</p>
<h4 id="fio_engine"><code>fio_engine</code></h4>
<pre><code class='highlight'><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>
<p>Returns a C string detailing the IO engine selected during compilation.</p>
<p>Valid values are &quot;kqueue&quot;, &quot;epoll&quot; and &quot;poll&quot;.</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>
<pre><code class='highlight'><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>
<p>Creates a TCP/IP or Unix socket and returns it&#39;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 &quot;localhost&quot; or &quot;127.0.0.1&quot; 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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;t flagged to be closed.</p>
<h4 id="fio_close"><code>fio_close</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Returns the information available about the socket&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>&#39;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&#39;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>
<pre><code class='highlight'><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>
<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 &quot;moved&quot; 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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">union</span> <span class="p">{</span>
<span class="cm">/** The in-memory data to be sent. */</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="cm">/** The data to be sent, if this is a file. */</span>
<span class="k">const</span> <span class="kt">intptr_t</span> <span class="n">fd</span><span class="p">;</span>
<span class="p">}</span> <span class="n">data</span><span class="p">;</span>
</code></pre></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&#39;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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">union</span> <span class="p">{</span>
<span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">dealloc</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">void</span> <span class="p">(</span><span class="o">*</span><span class="n">close</span><span class="p">)(</span><span class="kt">intptr_t</span> <span class="n">fd</span><span class="p">);</span>
<span class="p">}</span> <span class="n">after</span><span class="p">;</span>
</code></pre></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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">uintptr_t</span> <span class="n">length</span><span class="p">;</span>
</code></pre></li>
<li><p><code>offset</code>:</p>
<p>Starting point offset from the buffer or file descriptor&#39;s beginning.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">uintptr_t</span> <span class="n">offset</span><span class="p">;</span>
</code></pre></li>
<li><p><code>urgent</code>:</p>
<p>The data will be sent as soon as possible, moving forward in the connection&#39;s queue as much as possible without fragmenting other <code>fio_write2</code> calls.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">unsigned</span> <span class="n">urgent</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
</code></pre></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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">unsigned</span> <span class="n">is_fd</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
</code></pre></li>
</ul>
<p>On error, -1 will be returned. Otherwise returns 0.</p>
<h4 id="fio_write"><code>fio_write</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<h4 id="fio_sendfile"><code>fio_sendfile</code></h4>
<pre><code class='highlight'><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>
<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&#39;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>
<pre><code class='highlight'><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>
<h4 id="fio_pending"><code>fio_pending</code></h4>
<pre><code class='highlight'><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>
<p>Returns the number of <code>fio_write</code> calls that are waiting in the connection&#39;s queue and haven&#39;t been processed.</p>
<h4 id="fio_flush"><code>fio_flush</code></h4>
<pre><code class='highlight'><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>
<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&#39;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&#39;s lock is busy.</p>
<h4 id="fio_flush_strong"><code>fio_flush_strong</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_flush_strong(uuid) \
do { \
errno = 0; \
} while (fio_flush(uuid) &gt; 0 || errno == EWOULDBLOCK)
</span></code></pre>
<p>Blocks until all the data was flushed from the buffer.</p>
<h4 id="fio_flush_all"><code>fio_flush_all</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#define fio_uuid2fd(uuid) ((int)((uintptr_t)uuid &gt;&gt; 8))
</span></code></pre>
<p>Convert between a facil.io connection&#39;s identifier (uuid) and system&#39;s fd.</p>
<h4 id="fio_fd2uuid"><code>fio_fd2uuid</code></h4>
<pre><code class='highlight'><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>
<p><code>fio_fd2uuid</code> takes an existing file decriptor <code>fd</code> and returns it&#39;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&#39;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&#39;s lifetime rather than it&#39;s Protocol&#39;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>
<pre><code class='highlight'><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>
<p>Links an object to a connection&#39;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>
<pre><code class='highlight'><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>
<p>Un-links an object from the connection&#39;s lifetime, so it&#39;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&#39;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>
<pre><code class='highlight'><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>
<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&#39;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&#39;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&#39;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&#39;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>
<pre><code class='highlight'><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>
<p>Sets a connection&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;s state (starting up, cleaning up, etc&#39;).</p></li>
</ul>
<h3 id="the-task-queue-functions">The Task Queue Functions</h3>
<h4 id="fio_defer"><code>fio_defer</code></h4>
<pre><code class='highlight'><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>
<p>Defers a task&#39;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>
<pre><code class='highlight'><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>
<p>Performs all deferred tasks.</p>
<h4 id="fio_defer_has_queue"><code>fio_defer_has_queue</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">enum</span> <span class="n">fio_protocol_lock_e</span> <span class="n">type</span><span class="p">;</span>
</code></pre></li>
<li><p><code>task</code>:</p>
<p>The task (function) to be performed. The tasks accepts the connection&#39;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>
<pre><code class='highlight'><span class="c1">// Callback example:</span>
<span class="kt">void</span> <span class="n">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_protocol_s</span> <span class="o">*</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></li>
<li><p><code>fallback</code>:</p>
<p>A fallback task (function) to be performed in cases where the <code>uuid</code> isn&#39;t valid by the time the task should be executed. The fallback task accepts the connection&#39;s <code>uuid</code> and the opaque <code>udata</code> pointer passed to <code>fio_defer_io_task</code>.</p>
<pre><code class='highlight'><span class="c1">// Callback example:</span>
<span class="kt">void</span> <span class="n">fallback</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>
</code></pre></li>
<li><p><code>udata</code>:</p>
<p>An opaque pointer that&#39;s passed along to the task.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre></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&#39;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&#39;)</h3>
<p>facil.io allows callbacks to be called when certain events occur (such as before and after forking etc&#39;).</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&#39;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&#39;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>
<pre><code class='highlight'><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>
<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&#39;s context.</p>
<h4 id="fio_state_callback_remove"><code>fio_state_callback_remove</code></h4>
<pre><code class='highlight'><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>
<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&#39;s context.</p>
<h4 id="fio_state_callback_force"><code>fio_state_callback_force</code></h4>
<pre><code class='highlight'><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>
<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&#39;s context.</p>
<p>During an event, changes to the callback list are ignored (callbacks can&#39;t remove other callbacks for the same event).</p>
<h4 id="fio_state_callback_clear"><code>fio_state_callback_clear</code></h4>
<pre><code class='highlight'><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>
<p>Clears all the existing callbacks for the event (doesn&#39;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>
<pre><code class='highlight'><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>
<p>This function subscribes to either a numerical &quot;filter&quot; 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 &quot;named arguments&quot;, as shown in the following example:</p>
<pre><code class='highlight'><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>
<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&#39;s numerical value will be forwarded to the subscription&#39;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&#39;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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">int32_t</span> <span class="n">filter</span><span class="p">;</span>
</code></pre></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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">;</span>
</code></pre></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>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">int</span> <span class="n">foo_bar_match_fn</span><span class="p">(</span><span class="n">fio_str_info_s</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">);</span>
<span class="c1">// type:</span>
<span class="k">typedef</span> <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">fio_match_fn</span><span class="p">)(</span><span class="n">fio_str_info_s</span> <span class="n">pattern</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_match_fn</span> <span class="n">match</span><span class="p">;</span>
<span class="k">extern</span> <span class="n">fio_match_fn</span> <span class="n">FIO_MATCH_GLOB</span><span class="p">;</span>
</code></pre></li>
<li><p><code>on_message</code>:</p>
<p>The callback will be called for each message forwarded to the subscription.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_message</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></li>
<li><p><code>on_unsubscribe</code>:</p>
<p>The callback will be called once the subscription is canceled, allowing it&#39;s resources to be freed.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">on_unsubscribe</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></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>
<pre><code class='highlight'><span class="c1">// type:</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></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>
<pre><code class='highlight'><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>
<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&#39;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>
<pre><code class='highlight'><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>
<p>This helper returns a temporary String with the subscription&#39;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>
<pre><code class='highlight'><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>
<p>Defers the subscription&#39;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>
<pre><code class='highlight'><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>
<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&#39;t be called after the function returns.</p>
<h3 id="publishing-messages">Publishing messages</h3>
<h4 id="fio_publish"><code>fio_publish</code></h4>
<pre><code class='highlight'><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>
<p>This function publishes a message to either a numerical &quot;filter&quot; 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 &quot;named arguments&quot;, as shown in the following example:</p>
<pre><code class='highlight'><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>
<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&#39;s numerical value will be forwarded to the subscription&#39;s callback.</p>
<p>Subscriptions can either require a match by filter or match by channel. This will match the subscription by filter.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">int32_t</span> <span class="n">filter</span><span class="p">;</span>
</code></pre></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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">;</span>
</code></pre></li>
<li><p><code>message</code>:</p>
<p>The message data to be sent.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">message</span><span class="p">;</span>
</code></pre></li>
<li><p><code>is_json</code>:</p>
<p>A flag indicating if the message is JSON data or binary/text.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">uint8_t</span> <span class="n">is_json</span><span class="p">;</span>
</code></pre></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>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_pubsub_engine_s</span> <span class="k">const</span> <span class="o">*</span><span class="n">engine</span><span class="p">;</span>
<span class="c1">// default engine:</span>
<span class="k">extern</span> <span class="n">fio_pubsub_engine_s</span> <span class="o">*</span><span class="n">FIO_PUBSUB_DEFAULT</span><span class="p">;</span>
</code></pre></li>
</ul>
<h3 id="pub-sub-message-middleware-meta-data">Pub/Sub Message MiddleWare Meta-Data</h3>
<p>It&#39;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&#39;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>
<pre><code class='highlight'><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>
<p>Finds the message&#39;s meta-data by the meta-data&#39;s type ID. Returns the data or NULL.</p>
<h4 id="fio_message_metadata_callback_set"><code>fio_message_metadata_callback_set</code></h4>
<pre><code class='highlight'><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>
<p>The callback should return a <code>fio_msg_metadata_s</code> object. The object looks like this:</p>
<pre><code class='highlight'><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>
<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 &quot;engines&quot; (<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&#39;t part of the core library.</p>
<p>The default engine can be set using the <code>FIO_PUBSUB_DEFAULT</code> global variable. It&#39;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&#39;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>
<pre><code class='highlight'><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>
<h4 id="fio_pubsub_attach"><code>fio_pubsub_attach</code></h4>
<pre><code class='highlight'><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>
<p>Attaches an engine, so it&#39;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>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">subscribe</span><span class="p">(</span><span class="k">const</span> <span class="n">fio_pubsub_engine_s</span> <span class="o">*</span><span class="n">eng</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_match_fn</span> <span class="n">match</span><span class="p">);</span>
</code></pre></li>
<li><p><code>unsubscribe</code> - Should unsubscribe channel. Failures are ignored.</p>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">unsubscribe</span><span class="p">(</span><span class="k">const</span> <span class="n">fio_pubsub_engine_s</span> <span class="o">*</span><span class="n">eng</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_match_fn</span> <span class="n">match</span><span class="p">);</span>
</code></pre></li>
<li><p><code>publish</code> - Should publish a message through the engine. Failures are ignored.</p>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">publish</span><span class="p">(</span><span class="k">const</span> <span class="n">fio_pubsub_engine_s</span> <span class="o">*</span><span class="n">eng</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">uint8_t</span> <span class="n">is_json</span><span class="p">);</span>
</code></pre></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>
<pre><code class='highlight'><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>
<p>Detaches an engine, so it could be safely destroyed.</p>
<h4 id="fio_pubsub_reattach"><code>fio_pubsub_reattach</code></h4>
<pre><code class='highlight'><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>
<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&#39;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>
<pre><code class='highlight'><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>
<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&#39;s a small per-process overhead for the allocator&#39;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&#39;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&#39;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 &quot;free&quot; 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 &quot;slices&quot; 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 &quot;free list&quot; 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&#39;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&#39;s allocator.It&#39;s also possible to prevent facil.io&#39;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&#39;s API</h3>
<p>The functions were designed to be a drop in replacement to the system&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Frees memory that was allocated using this library.</p>
<h4 id="fio_realloc"><code>fio_realloc</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#include &lt;fio.h&gt; // No linked list helpers
#define FIO_INCLUDE_LINKED_LIST
#include &lt;fio.h&gt; // Linked list helpers become available
</span></code></pre>
<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&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#define FIO_LS_INIT(name) \
{ .next = &amp;(name), .prev = &amp;(name) }
</span></code></pre>
<p>Initializes the list container. i.e.:</p>
<pre><code class='highlight'><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>
<h4 id="fio_ls_push"><code>fio_ls_push</code></h4>
<pre><code class='highlight'><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>
<p>Adds an object to the list&#39;s head.</p>
<p>Returns a pointer to the object&#39;s position (can be used in <code>fio_ls_remove</code>).</p>
<h4 id="fio_ls_unshift"><code>fio_ls_unshift</code></h4>
<pre><code class='highlight'><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>
<p>Adds an object to the list&#39;s tail.</p>
<p>Returns a pointer to the object&#39;s position (can be used in <code>fio_ls_remove</code>).</p>
<h4 id="fio_ls_pop"><code>fio_ls_pop</code></h4>
<pre><code class='highlight'><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>
<p>Removes an object from the list&#39;s head.</p>
<h4 id="fio_ls_shift"><code>fio_ls_shift</code></h4>
<pre><code class='highlight'><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>
<p>Removes an object from the list&#39;s tail.</p>
<h4 id="fio_ls_remove"><code>fio_ls_remove</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Tests if the list is empty.</p>
<h4 id="fio_ls_any"><code>fio_ls_any</code></h4>
<pre><code class='highlight'><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>
<p>Tests if the list is NOT empty (contains any nodes).</p>
<h4 id="fio_ls_for"><code>FIO_LS_FOR</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_LS_FOR(list, pos)
</span></code></pre>
<p>Iterates through the list using a <code>for</code> loop.</p>
<p>Access the data with <code>pos-&gt;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Adds a node to the list&#39;s head.</p>
<h4 id="fio_ls_embd_unshift"><code>fio_ls_embd_unshift</code></h4>
<pre><code class='highlight'><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>
<p>Adds a node to the list&#39;s tail.</p>
<h4 id="fio_ls_embd_pop"><code>fio_ls_embd_pop</code></h4>
<pre><code class='highlight'><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>
<p>Removes a node from the list&#39;s head.</p>
<h4 id="fio_ls_embd_shift"><code>fio_ls_embd_shift</code></h4>
<pre><code class='highlight'><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>
<p>Removes a node from the list&#39;s tail.</p>
<h4 id="fio_ls_embd_remove"><code>fio_ls_embd_remove</code></h4>
<pre><code class='highlight'><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>
<p>Removes a node from the containing node.</p>
<h4 id="fio_ls_embd_is_empty"><code>fio_ls_embd_is_empty</code></h4>
<pre><code class='highlight'><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>
<p>Tests if the list is empty.</p>
<h4 id="fio_ls_embd_any"><code>fio_ls_embd_any</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#define FIO_LS_EMBD_FOR(list, node)
</span></code></pre>
<p>Iterates through the list using a <code>for</code> loop.</p>
<p>Access the data with <code>pos-&gt;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>
<pre><code class='highlight'><span class="cp">#define FIO_LS_EMBD_OBJ(type, member, plist) \
((type *)((uintptr_t)(plist) - (uintptr_t)(&amp;(((type *)0)-&gt;member))))
</span></code></pre>
<p>Takes a list pointer <code>plist</code> (node) and returns a pointer to it&#39;s container.</p>
<p>This uses pointer offset calculations and can be used to calculate any structure&#39;s pointer (not just list containers) as an offset from a pointer of one of it&#39;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>
<pre><code class='highlight'><span class="cp">#include &lt;fio.h&gt; // No string helpers
#define FIO_INCLUDE_STR
#include &lt;fio.h&gt; // String helpers become available
</span></code></pre>
<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&#39;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&#39;s allocation / deallocation routines (<code>fio_malloc</code>, etc&#39;).</p>
<p>To use the system&#39;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&#39;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&#39;t be manually unset.</p>
<p>For example:</p>
<pre><code class='highlight'><span class="cp">#define FIO_INCLUDE_STR 1
#define FIO_FORCE_MALLOC_TMP 1
#include &lt;fio.h&gt;
#ifdef FIO_FORCE_MALLOC_TMP
#error "FIO_FORCE_MALLOC_TMP is removed after it's used."
#undef
</span></code></pre>
<h4 id="fio_str_init"><code>FIO_STR_INIT</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_STR_INIT ((fio_str_s){.data = NULL, .small = 1})
</span></code></pre>
<p>This value should be used for initialization. For example:</p>
<pre><code class='highlight'><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>
<p>Remember to cleanup:</p>
<pre><code class='highlight'><span class="c1">// on the stack</span>
<span class="n">fio_str_free</span><span class="p">(</span><span class="o">&amp;</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>
<h4 id="fio_str_init_existing"><code>FIO_STR_INIT_EXISTING</code></h4>
<pre><code class='highlight'><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>
<p>This macro allows the container to be initialized with existing data, as long as it&#39;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>
<pre><code class='highlight'><span class="cp">#define FIO_STR_INIT_STATIC(buffer) \
((fio_str_s){.data = (buffer), .len = strlen((buffer)), .dealloc = NULL})
</span></code></pre>
<p>This macro allows the container to be initialized with existing static data, that shouldn&#39;t be freed.</p>
<h4 id="fio_str_init_static2"><code>FIO_STR_INIT_STATIC2</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_STR_INIT_STATIC2(buffer, length) \
((fio_str_s){.data = (buffer), .len = (length), .dealloc = NULL})
</span></code></pre>
<p>This macro allows the container to be initialized with existing static data, that shouldn&#39;t be freed.</p>
<h4 id="fio_str_new2"><code>fio_str_new2</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;s data and it&#39;s container.</p>
<h4 id="fio_str_dup"><code>fio_str_dup</code></h4>
<pre><code class='highlight'><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>
<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&#39; 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>
<pre><code class='highlight'><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>
<p>Frees the String&#39;s resources and reinitializes the container.</p>
<p>Note: if the container isn&#39;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>
<pre><code class='highlight'><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>
<p>Frees the String&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Returns a C string with the existing data, clearing the <code>fio_str_s</code> object&#39;s String.</p>
<p>Note: the String data is removed from the container, but the container isn&#39;t freed.</p>
<p>Returns NULL if there&#39;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&#39;)</h3>
<p>Many of the String state functions return a <code>fio_str_info_s</code> structure with information about the String:</p>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Returns the String&#39;s complete state (capacity, length and pointer). </p>
<h4 id="fio_str_len"><code>fio_str_len</code></h4>
<pre><code class='highlight'><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>
<p>Returns the String&#39;s length in bytes.</p>
<h4 id="fio_str_data"><code>fio_str_data</code></h4>
<pre><code class='highlight'><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>
<p>Returns a pointer (<code>char *</code>) to the String&#39;s content.</p>
<h4 id="fio_str_bytes"><code>fio_str_bytes</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_str_bytes(s) ((uint8_t *)fio_str_data((s)))
</span></code></pre>
<p>Returns a byte pointer (<code>uint8_t *</code>) to the String&#39;s unsigned content.</p>
<h4 id="fio_str_capa"><code>fio_str_capa</code></h4>
<pre><code class='highlight'><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>
<p>Returns the String&#39;s existing capacity (total used &amp; available memory).</p>
<h4 id="fio_str_resize"><code>fio_str_resize</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#define fio_str_clear(s) fio_str_resize((s), 0)
</span></code></pre>
<p>Clears the string (retaining the existing capacity).</p>
<h4 id="fio_str_hash"><code>fio_str_hash</code></h4>
<pre><code class='highlight'><span class="kr">inline</span> <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>
<p>Returns the string&#39;s SipHash value (Uses SipHash 1-3).</p>
<h3 id="string-api-memory-management">String API - Memory management</h3>
<h4 id="fio_str_compact"><code>fio_str_compact</code></h4>
<pre><code class='highlight'><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>
<p>Performs a best attempt at minimizing memory consumption.</p>
<p>Actual effects depend on the underlying memory allocator and it&#39;s implementation. Not all allocators will free any memory.</p>
<h4 id="fio_str_capa_assert"><code>fio_str_capa_assert</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Returns the String&#39;s length in UTF-8 characters.</p>
<h4 id="fio_str_utf8_select"><code>fio_str_utf8_select</code></h4>
<pre><code class='highlight'><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>
<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&#39;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&#39;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>
<pre><code class='highlight'><span class="cp">#define FIO_STR_UTF8_CODE_POINT(ptr, end, i32) // ...
</span></code></pre>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#define fio_str_join(dest, src) fio_str_concat((dest), (src))
</span></code></pre>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Opens the file <code>filename</code> and pastes it&#39;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&#39;t be located, opened or read, or if <code>start_at</code> is beyond
the EOF position, NULL is returned in the state&#39;s <code>data</code> field.</p>
<p>Works on POSIX only.</p>
<h4 id="fio_str_freeze"><code>fio_str_freeze</code></h4>
<pre><code class='highlight'><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>
<p>Prevents further manipulations to the String&#39;s content.</p>
<h4 id="fio_str_iseq"><code>fio_str_iseq</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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 &lt;fio.h&gt;
</span></code></pre>
<p>It&#39;s possible to create a number of Set or Array types by re-including the <code>fio.h</code> header. i.e.:</p>
<pre><code class='highlight'><span class="cp">#define FIO_INCLUDE_STR
#include &lt;fio.h&gt; // 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 &lt;fio.h&gt; // 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 &lt;fio.h&gt; // creates the fio_str_ary_s Array and functions
</span></code></pre>
<h3 id="array-memory-allocation">Array Memory allocation</h3>
<p>The Array&#39;s memory is managed by facil.io&#39;s allocation / deallocation routines (<code>fio_malloc</code>, etc&#39;).</p>
<p>To use the system&#39;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&#39;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&#39;t be manually unset.</p>
<p>For example:</p>
<pre><code class='highlight'><span class="cp">#define FIO_FORCE_MALLOC_TMP 1
#define FIO_ARY_NAME fio_int_ary
#define FIO_ARY_TYPE int
#include &lt;fio.h&gt; // 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>
<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&#39;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>
<pre><code class='highlight'><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 &lt;fio.h&gt;
</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">&lt;</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">&amp;</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>
<h4 id="fio_ary_type"><code>FIO_ARY_TYPE</code></h4>
<pre><code class='highlight'><span class="cp">#if !defined(FIO_ARY_TYPE)
#define FIO_ARY_TYPE void *
#endif
</span></code></pre>
<p>The default Array object type is <code>void *</code> */</p>
<h4 id="fio_ary_invalid"><code>FIO_ARY_INVALID</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#if !defined(FIO_ARY_COMPARE)
#define FIO_ARY_COMPARE(o1, o2) ((o1) == (o2))
#endif
</span></code></pre>
<p>The default object comparison assumes a simple type.</p>
<h4 id="fio_ary_copy"><code>FIO_ARY_COPY</code></h4>
<pre><code class='highlight'><span class="cp">#ifndef FIO_ARY_COPY
#define FIO_ARY_COPY(dest, obj) ((dest) = (obj))
#endif
</span></code></pre>
<p>The default object copy is a simple assignment.</p>
<h4 id="fio_ary_destroy"><code>FIO_ARY_DESTROY</code></h4>
<pre><code class='highlight'><span class="cp">#ifndef FIO_ARY_DESTROY
#define FIO_ARY_DESTROY(obj) ((void)0)
#endif
</span></code></pre>
<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>
<pre><code class='highlight'><span class="cp">#ifndef FIO_ARY_MALLOC
#define FIO_ARY_MALLOC(size) fio_malloc((size))
#endif
</span></code></pre>
<p>The default Array allocator is set to <code>fio_malloc</code>.</p>
<p>It&#39;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&#39;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>
<pre><code class='highlight'><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>
<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&#39;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>
<pre><code class='highlight'><span class="cp">#ifndef FIO_ARY_DEALLOC
#define FIO_ARY_DEALLOC(ptr, size) fio_free((ptr))
#endif
</span></code></pre>
<p>The default Array deallocator is set to <code>fio_free</code>.</p>
<p>To use the system&#39;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&#39;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&#39;s equal to <code>FIO_ARY_NAME + &quot;_&quot; + 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>
<pre><code class='highlight'><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>
<p>The Array container type. It is advised that the container be considered opaque and that the functions provided are used to access it&#39;s data (instead of direct data access).</p>
<h4 id="fio_ary_init"><code>FIO_ARY_INIT</code></h4>
<pre><code class='highlight'><span class="cp">#ifndef FIO_ARY_INIT
#define FIO_ARY_INIT \
{ .capa = 0 }
#endif
</span></code></pre>
<p>Initializes the Array.</p>
<h4 id="fio_ary_name-free"><code>FIO_ARY_NAME(free)</code></h4>
<pre><code class='highlight'><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>
<p>Frees the array&#39;s internal data.</p>
<h4 id="fio_ary_name-count"><code>FIO_ARY_NAME(count)</code></h4>
<pre><code class='highlight'><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>
<p>Returns the number of elements in the Array.</p>
<h4 id="fio_ary_name-capa"><code>FIO_ARY_NAME(capa)</code></h4>
<pre><code class='highlight'><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>
<p>Returns the current, temporary, array capacity (it&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Returns the index of the object or -1 if the object wasn&#39;t found.</p>
<h4 id="fio_ary_name-remove"><code>FIO_ARY_NAME(remove)</code></h4>
<pre><code class='highlight'><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>
<p>Removes an object from the array, <strong>moving</strong> all the other objects to prevent
&quot;holes&quot; 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>
<pre><code class='highlight'><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>
<p>Removes an object from the array, if it exists, MOVING all the other objects
to prevent &quot;holes&quot; in the data.</p>
<p>Returns -1 if the object wasn&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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 &quot;stop&quot; 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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#define FIO_ARY_FOR(ary, pos)
</span></code></pre>
<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&#39;s possible, I
wouldn&#39;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&#39;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&#39;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>
<pre><code class='highlight'><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 &lt;fio.h&gt;
</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">&amp;</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>
<p>This can be performed a number of times, defining a different Set / Hash Map each time.</p>
<h3 id="hash-map-set-memory-allocation">Hash Map / Set Memory allocation</h3>
<p>The Hash Map&#39;s memory is managed by facil.io&#39;s allocation / deallocation routines (<code>fio_malloc</code>, etc&#39;).</p>
<p>To use the system&#39;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&#39;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&#39;t be manually unset.</p>
<p>For example:</p>
<pre><code class='highlight'><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 &lt;fio.h&gt; // 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>
<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&#39;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>
<pre><code class='highlight'><span class="cp">#define FIO_INCLUDE_STR
#include &lt;fio.h&gt; // 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 &lt;fio.h&gt; // 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">&amp;</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">&amp;</span><span class="n">tmp</span><span class="p">),</span> <span class="o">&amp;</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">&amp;</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">&amp;</span><span class="n">my_set</span><span class="p">);</span>
<span class="p">}</span>
</code></pre>
<p>To create a Hash Map, rather than a pure Set, the macro FIO_SET_KET_TYPE must
be defined. i.e.:</p>
<pre><code class='highlight'><span class="cp">#define FIO_SET_KEY_TYPE char *
</span></code></pre>
<p>This allows the FIO_SET_KEY_* macros to be defined as well. For example:</p>
<pre><code class='highlight'><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 &lt;fio.h&gt;
</span></code></pre>
<h4 id="fio_set_obj_type"><code>FIO_SET_OBJ_TYPE</code></h4>
<pre><code class='highlight'><span class="c1">// default:</span>
<span class="cp">#define FIO_SET_OBJ_TYPE void *
</span></code></pre>
<p>Set&#39;s a Set or a Hash Map&#39;s object type. Defaults to <code>void *</code>.</p>
<h4 id="fio_set_obj_compare"><code>FIO_SET_OBJ_COMPARE</code></h4>
<pre><code class='highlight'><span class="c1">// default:</span>
<span class="cp">#define FIO_SET_OBJ_COMPARE(o1, o2) (1)
</span></code></pre>
<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>
<pre><code class='highlight'><span class="c1">// default:</span>
<span class="cp">#define FIO_SET_OBJ_COPY(dest, obj) ((dest) = (obj))
</span></code></pre>
<p>Copies an object&#39;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>
<pre><code class='highlight'><span class="c1">// default:</span>
<span class="cp">#define FIO_SET_OBJ_DESTROY(obj) ((void)0)
</span></code></pre>
<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>
<pre><code class='highlight'><span class="cp">#undef FIO_SET_KEY_TYPE
</span></code></pre>
<p>By defining a key type, the Set will be converted to a Hash Map and it&#39;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>
<pre><code class='highlight'><span class="cp">#define FIO_SET_KEY_COMPARE(key1, key2) ((key1) == (key2))
</span></code></pre>
<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>
<pre><code class='highlight'><span class="cp">#define FIO_SET_KEY_COPY(dest, key) ((dest) = (key))
</span></code></pre>
<p>Copies the key&#39;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>
<pre><code class='highlight'><span class="cp">#define FIO_SET_KEY_DESTROY(key) ((void)0)
</span></code></pre>
<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>
<pre><code class='highlight'><span class="cp">#define FIO_SET_REALLOC(ptr, original_size, new_size, valid_data_length) \
realloc((ptr), (new_size))
</span></code></pre>
<p>Allows for custom memory allocation / deallocation routines.</p>
<p>The default allocator is facil.io&#39;s <code>fio_realloc</code>.</p>
<p>To use the system&#39;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>
<pre><code class='highlight'><span class="cp">#define FIO_SET_CALLOC(size, count) calloc((size), (count))
</span></code></pre>
<p>Allows for custom memory allocation / deallocation routines.</p>
<p>The default allocator is facil.io&#39;s <code>fio_calloc</code>.</p>
<p>To use the system&#39;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>
<pre><code class='highlight'><span class="cp">#define FIO_SET_FREE(ptr, size) free((ptr))
</span></code></pre>
<p>Allows for custom memory allocation / deallocation routines.</p>
<p>The default deallocator is facil.io&#39;s <code>fio_free</code>.</p>
<p>To use the system&#39;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&#39;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&#39;s equal to <code>FIO_SET_NAME + &quot;_&quot; + 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&#39;s / Hash Map&#39;s type name. It&#39;s content should be considered opaque.</p>
<h4 id="fio_set_init"><code>FIO_SET_INIT</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_SET_INIT { .capa = 0 }
</span></code></pre>
<p>Initializes the Set or the Hash Map.</p>
<h4 id="fio_set_name-free"><code>FIO_SET_NAME(free)</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Locates an object in the Hash Map, if it exists.</p>
<p><strong>Note</strong>: This is the function&#39;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>
<pre><code class='highlight'><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>
<p>Inserts an object to the Hash Map, rehashing if required, returning the new object&#39;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&#39;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&#39;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>
<pre><code class='highlight'><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>
<p>Removes an object from the Set, rehashing if required.</p>
<p>Returns 0 on success and -1 if the object wasn&#39;t found.</p>
<p>If <code>old</code> isn&#39;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&#39;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>
<pre><code class='highlight'><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>
<p>Locates an object in the Set, if it exists.</p>
<p><strong>Note</strong>: This is the function&#39;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>
<pre><code class='highlight'><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>
<p>Inserts an object to the Set only if it&#39;s missing, rehashing if required, returning the new (or old) object&#39;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&#39;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>
<pre><code class='highlight'><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>
<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&#39;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>
<pre><code class='highlight'><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>
<p>Removes an object from the Set, rehashing if required.</p>
<p>Returns 0 on success and -1 if the object wasn&#39;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&#39;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>
<pre><code class='highlight'><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>
<p>Allows a peak at the Set&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Returns the number of object currently in the Set.</p>
<h4 id="fio_set_name-capa"><code>FIO_SET_NAME(capa)</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Forces a rehashing of the Set.</p>
<h4 id="fio_set_for_loop"><code>FIO_SET_FOR_LOOP</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_SET_FOR_LOOP(set, pos) // ...
</span></code></pre>
<p>A macro for a <code>for</code> loop that iterates over all the Set&#39;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-&gt;hash</code> is the hashing value.</p>
<p>For Hash Maps, <code>pos-&gt;obj</code> is a key / value couplet, requiring a selection of <code>pos-&gt;obj.key</code> / <code>pos-&gt;obj.obj</code>.</p>
<p>For Pure Sets. the <code>pos-&gt;obj</code> is the actual object data.</p>
<p><strong>Important</strong>: Since the Set might have &quot;holes&quot; (objects that were removed), it is important to skip any <code>pos-&gt;hash == 0</code> or the equivalent of <code>FIO_SET_HASH_COMPARE(pos-&gt;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&#39;</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>
<pre><code class='highlight'><span class="cp">#define fio_atomic_xchange(p_obj, value) </span><span class="cm">/* compiler specific */</span><span class="cp">
</span></code></pre>
<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>
<pre><code class='highlight'><span class="cp">#define fio_atomic_add(p_obj, value) </span><span class="cm">/* compiler specific */</span><span class="cp">
</span></code></pre>
<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>
<pre><code class='highlight'><span class="cp">#define fio_atomic_sub(p_obj, value) </span><span class="cm">/* compiler specific */</span><span class="cp">
</span></code></pre>
<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>
<pre><code class='highlight'><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>
<h4 id="fio_trylock"><code>fio_trylock</code></h4>
<pre><code class='highlight'><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>
<p>Returns 0 if the lock was acquired and non-zero on failure.</p>
<h4 id="fio_lock"><code>fio_lock</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>Returns the current lock&#39;s state (non 0 == Busy).</p>
<h4 id="fio_unlock"><code>fio_unlock</code></h4>
<pre><code class='highlight'><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>
<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&#39;s protection to fail. Make sure to only release the lock if it was previously acquired by the same &quot;owner&quot;.</p>
<h4 id="fio_reschedule_thread"><code>fio_reschedule_thread</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#define fio_lton16(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<p>Local byte order to Network byte order, 16 bit integer.</p>
<h4 id="fio_lton32"><code>fio_lton32</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_lton32(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<p>Local byte order to Network byte order, 32 bit integer.</p>
<h4 id="fio_lton64"><code>fio_lton64</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_lton64(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<p>Local byte order to Network byte order, 62 bit integer.</p>
<h4 id="fio_str2u16"><code>fio_str2u16</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_str2u16(c) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<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>
<pre><code class='highlight'><span class="cp">#define fio_str2u32(c) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<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>
<pre><code class='highlight'><span class="cp">#define fio_str2u64(c) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="cp">#define fio_ntol16(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<p>Network byte order to Local byte order, 16 bit integer.</p>
<h4 id="fio_ntol32"><code>fio_ntol32</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_ntol32(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<p>Network byte order to Local byte order, 32 bit integer.</p>
<h4 id="fio_ntol64"><code>fio_ntol64</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_ntol64(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<p>Network byte order to Local byte order, 62 bit integer.</p>
<h4 id="fio_bswap16"><code>fio_bswap16</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_bswap16(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<p>Swaps the byte order in a 16 bit integer.</p>
<h4 id="fio_bswap32"><code>fio_bswap32</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_bswap32(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<p>Swaps the byte order in a 32 bit integer.</p>
<h4 id="fio_bswap64"><code>fio_bswap64</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_bswap64(i) </span><span class="cm">/* system specific */</span><span class="cp">
</span></code></pre>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<p>A helper function that writes a signed int64_t to a string.</p>
<p>No overflow guard is provided, make sure there&#39;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&#39;t added (i.e., no &quot;0x&quot; or &quot;0b&quot; 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>
<pre><code class='highlight'><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>
<p>A helper function that converts between a double to a string.</p>
<p>No overflow guard is provided, make sure there&#39;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&#39;t added (i.e., no &quot;0x&quot; or &quot;0b&quot; 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>
<pre><code class='highlight'><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>
<p>Returns 64 psedo-random bits. Probably not cryptographically safe.</p>
<h4 id="fio_rand_bytes"><code>fio_rand_bytes</code></h4>
<pre><code class='highlight'><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>
<p>Writes <code>length</code> bytes of psedo-random bits to the target buffer.</p>
<h3 id="base64">Base64</h3>
<h4 id="fio_base64_encode"><code>fio_base64_encode</code></h4>
<pre><code class='highlight'><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>
<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&#39;s length isn&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;s buffer.</p>
<p>Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if the raw data&#39;s length isn&#39;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&#39;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&#39;t validated and invalid input might produce surprising results.</p>
<h3 id="siphash">SipHash</h3>
<h4 id="fio_siphash24"><code>fio_siphash24</code></h4>
<pre><code class='highlight'><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>
<p>A SipHash variation (2-4).</p>
<h4 id="fio_siphash13"><code>fio_siphash13</code></h4>
<pre><code class='highlight'><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>
<p>A SipHash 1-3 variation.</p>
<h4 id="fio_siphash"><code>fio_siphash</code></h4>
<pre><code class='highlight'><span class="cp">#define fio_siphash(data, length) fio_siphash13((data), (length))
</span></code></pre>
<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>
<pre><code class='highlight'><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">&amp;</span><span class="n">sha1</span><span class="p">);</span>
<span class="n">fio_sha1_write</span><span class="p">(</span><span class="o">&amp;</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">&amp;</span><span class="n">sha1</span><span class="p">);</span>
</code></pre>
<h4 id="fio_sha1_init"><code>fio_sha1_init</code></h4>
<pre><code class='highlight'><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>
<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&#39;s content should be ignored.</p>
<h4 id="fio_sha1"><code>fio_sha1</code></h4>
<pre><code class='highlight'><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>
<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&#39;s encoding. If it&#39;s stack allocated, no freeing will be
required.</p>
<h4 id="fio_sha1_write"><code>fio_sha1_write</code></h4>
<pre><code class='highlight'><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>
<p>Writes data to the sha1 buffer.</p>
<h4 id="fio_sha1_result"><code>fio_sha1_result</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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">&amp;</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">&amp;</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">&amp;</span><span class="n">sha2</span><span class="p">);</span>
</code></pre>
<h4 id="fio_sha2_init"><code>fio_sha2_init</code></h4>
<pre><code class='highlight'><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>
<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&#39;s content should be ignored.</p>
<h4 id="fio_sha2_write"><code>fio_sha2_write</code></h4>
<pre><code class='highlight'><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>
<p>Writes data to the SHA-2 buffer.</p>
<h4 id="fio_sha2_result"><code>fio_sha2_result</code></h4>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;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&#39;s core library and it&#39;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&#39;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&#39;t effect existing API.</p>
<p>However, as long as facil.io&#39;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&#39;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&#39;s literal string. It can be used, for example, like this:</p>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><span class="k">extern</span> <span class="kt">size_t</span> <span class="n">FIO_LOG_LEVEL</span><span class="p">;</span>
</code></pre>
<p>This variable sets / gets the logging level. Supported values include:</p>
<pre><code class='highlight'><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>
<h4 id="fio_log_fatal"><code>FIO_LOG_FATAL</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_LOG_FATAL(...)
</span></code></pre>
<p>Logs a fatal error. Doesn&#39;t exit the program (this should be performed after the logging).</p>
<p>Logging macros accept <code>printf</code> type arguments. i.e.:</p>
<pre><code class='highlight'><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>
<h4 id="fio_log_error"><code>FIO_LOG_ERROR</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_LOG_ERROR(...)
</span></code></pre>
<p>Logs an error.</p>
<p>Logging macros accept <code>printf</code> type arguments. i.e.:</p>
<pre><code class='highlight'><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>
<h4 id="fio_log_warning"><code>FIO_LOG_WARNING</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_LOG_WARNING(...)
</span></code></pre>
<p>Logs a warning message.</p>
<p>Logging macros accept <code>printf</code> type arguments. i.e.:</p>
<pre><code class='highlight'><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>
<h4 id="fio_log_info"><code>FIO_LOG_INFO</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_LOG_INFO(...)
</span></code></pre>
<p>Logs an information level message.</p>
<p>Logging macros accept <code>printf</code> type arguments. i.e.:</p>
<pre><code class='highlight'><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>
<h4 id="fio_log_debug"><code>FIO_LOG_DEBUG</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_LOG_DEBUG(...)
</span></code></pre>
<p>Logs a debug message.</p>
<p>Logging macros accept <code>printf</code> type arguments. i.e.:</p>
<pre><code class='highlight'><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>
<h4 id="fio_log_length_limit"><code>FIO_LOG_LENGTH_LIMIT</code></h4>
<pre><code class='highlight'><span class="cp">#define FIO_LOG_LENGTH_LIMIT 2048
</span></code></pre>
<p>(since 0.7.0.beta3)</p>
<p>Since logging uses stack memory rather than dynamic allocation, it&#39;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&#39;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 &quot;fallback&quot; 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&#39;).</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&#39;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>
<pre><code class='highlight'><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>
<p>OVERRIDE THIS to replace the default <code>fork</code> implementation.</p>
<p>Should behaves like the system&#39;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>
<pre><code class='highlight'><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>
<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>
<pre><code class='highlight'><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>
<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&#39;s course, just the identifier is freed).</p>
<h4 id="fio_thread_join"><code>fio_thread_join</code></h4>
<pre><code class='highlight'><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>
<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>