{"id":13420485,"url":"https://github.com/baruch/libwire","last_synced_at":"2025-03-15T06:33:17.016Z","repository":{"id":14826041,"uuid":"17548774","full_name":"baruch/libwire","owner":"baruch","description":"User space threading (aka coroutines) library for C resembling GoLang and goroutines","archived":false,"fork":false,"pushed_at":"2018-10-03T06:36:05.000Z","size":367,"stargazers_count":165,"open_issues_count":1,"forks_count":18,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-07-31T22:55:23.591Z","etag":null,"topics":["c","coroutines","event-driven","green-threads","library"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/baruch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-08T19:07:14.000Z","updated_at":"2023-08-12T12:18:49.000Z","dependencies_parsed_at":"2022-09-21T11:52:37.768Z","dependency_job_id":null,"html_url":"https://github.com/baruch/libwire","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baruch%2Flibwire","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baruch%2Flibwire/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baruch%2Flibwire/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baruch%2Flibwire/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/baruch","download_url":"https://codeload.github.com/baruch/libwire/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243695465,"owners_count":20332622,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","coroutines","event-driven","green-threads","library"],"created_at":"2024-07-30T22:01:34.631Z","updated_at":"2025-03-15T06:33:16.685Z","avatar_url":"https://github.com/baruch.png","language":"C","funding_links":[],"categories":["TODO scan for Android support in followings"],"sub_categories":[],"readme":"libwire    {#mainpage}\n========\n\n[![Build Status](https://travis-ci.org/baruch/libwire.png?branch=master)](https://travis-ci.org/baruch/libwire)\n\nlibwire is a user-space threading library that is intended to provide in C some semblance\nof the GoLang environment. Namely, lightweight user-space cooperative threading\nand communication channels between them. Unlike Go this is squarely intended at\nhigh performance system-level programming that cares enough about memory\nallocations, zero-copy wherever possible and the least amount of overhead even\nat the expense of safety and ease of programming.\n\nA guiding light for this library is to not allocate memory by itself if at all possible\nand to let the user completely manage the memory and the allocation. A memory pool is\nprovided for when that is needed but even that memory can be provided by the user as a\nstatic array instead of mallocing each part.\n\nThe library is built in layers to make it more understandable and to make each\npart reviewable to ensure correctness. It should be possible to rip and replace\nsome of the parts in order to support OS compatibility.\n\nLayering\n========\n\nlibcoro\n-------\n\nThe underlying layer used to implement the entire library is libcoro which is\nused to switch between the wires. libcoro is very very simplistic and only\nknows how to create the context switch area and to switch between two different\ncontexts. It is portable and can work on almost any environment.\n\nwire\n----\n\nThe first libwire layer is that of the user-space threads themselves. It deals\nwith settings things up easily and with suspend/resume. It is a fairly thin\nlayer on top of the coroutine switching layer of libcoro.\n\n    void wire_thread_init(wire_thread_t *wire);\n    void wire_thread_run(void);\n    wire_t *wire_init(wire_t *wire, const char *name, void (*entry_point)(void *), void *arg, void *stack, unsigned stack_size);\n    void wire_yield(void);\n    void wire_suspend(void);\n    void wire_resume(wire_t *wire);\n\nwire_stack\n----------\n\nThe wire_stack provides a simple way to allocate safe stacks of page size\nmultiples with a page of guard space around them. This helps catching stack\noverflow bugs easily. It also provides a sigsegv handler to catch and report\nsuch failures in a simple to understand way to quickly home on the problematic\nwire.\n\n    void *wire_stack_alloc(unsigned stack_size);\n    #define WIRE_STACK_ALLOC(size) wire_stack_alloc(size), size\n    void wire_stack_fault_detector_install(void);\n\nwire_pool\n---------\n\nA wire_pool is used to easily provide a pool of wires that can be used for some\ntask. These wires will release their wire state to the pool upon completion and\nmake it easier to have a pool of workers. The wires are released in LIFO order\nto try and have the memory as hot in the cache as possible.\n\n    int wire_pool_init(wire_pool_t *pool, wire_pool_entry_t *entries, unsigned size, unsigned stack_size);\n    wire_t *wire_pool_alloc(wire_pool_t *pool, const char *name, void (*entry_point)(void*), void *arg);\n    wire_t *wire_pool_alloc_block(wire_pool_t *pool, const char *name, void (*entry_point)(void*), void *arg);\n\nwire_wait\n---------\n\nThe next layer (wire_wait) is that of cleanly suspending and resuming upon a\nwakeup call from another wire. This is intended as a simple way to wait for\nmultiple sources such as waiting on a socket with a timeout, in such a case you\nwant to wait for the first of socket readable or timeout expired wakeups. The\nwakeups do not carry any data beyond the wakeup itself.\n\n    void wire_wait_init(wire_wait_t *w);\n    void wire_wait_resume(wire_wait_t *w);\n    void wire_wait_reset(wire_wait_t *w);\n    void wire_wait_stop(wire_wait_t *w);\n    void wire_wait_single(wire_wait_t *w);\n\n    void wire_wait_list_init(wire_wait_list_t *wl);\n    void wire_wait_chain(wire_wait_list_t *wl, wire_wait_t *w);\n    void wire_wait_unchain(wire_wait_t *w);\n    wire_wait_t *wire_list_wait(wire_wait_list_t *wl);\n\nwire_channel\n------------\n\nA channel is a construct on top wire_wait which is used to send data between\nwires. The data is only a void pointer so it can hold anything in it and the\nsender will block until the data is received and processed by the receiver.\nThis provides both data passing and synchronization.\n\n    void wire_channel_init(wire_channel_t *c);\n    void wire_channel_send(wire_channel_t *c, void *msg);\n    int wire_channel_recv_block(wire_channel_t *c, void **msg);\n    int wire_channel_recv_nonblock(wire_channel_t *c, void **msg);\n    void wire_channel_recv_wait(wire_channel_t *c, wire_channel_receiver_t *receiver, wire_wait_t *wait);\n\nwire_fd\n-------\n\nwire_fd is using epoll to make a wire wait for a file descriptor to become\nreadable or writable. It also provides basic timers by using timerfd. This part\nis Linux specific but can be ported by using the appropriate feature of the\nhost OS (BSD kqueue and such).\n\n    void wire_fd_init(void);\n    void wire_fd_mode_init(wire_fd_state_t *state, int fd);\n    int wire_fd_mode_read(wire_fd_state_t *fd_state);\n    int wire_fd_mode_write(wire_fd_state_t *fd_state);\n    int wire_fd_mode_none(wire_fd_state_t *fd_state);\n    void wire_fd_wait(wire_fd_state_t *fd_state);\n    void wire_fd_wait_list_chain(wire_wait_list_t *wl, wire_fd_state_t *fd_state);\n    int wire_fd_wait_msec(int msecs);\n\nwire_io\n-------\n\nwire_io provides a way to make non-async blocking system calls into an async\noperation by delegating it to a thread that will perform it and block and then\nreturn the reply through a socket back to the thread running the wires. This\nuses pthread mutexes and conditions and may block but hopefully contention on\nthe locks will be minimal.\n\n    void wire_io_init(int num_threads);\n    int wio_open(const char *pathname, int flags, mode_t mode);\n    int wio_close(int fd);\n    ssize_t wio_pread(int fd, void *buf, size_t count, off_t offset);\n    ssize_t wio_pwrite(int fd, const void *buf, size_t count, off_t offset);\n    int wio_fstat(int fd, struct stat *buf);\n    int wio_ftruncate(int fd, off_t length);\n    int wio_fallocate(int fd, int mode, off_t offset, off_t len);\n    int wio_fsync(int fd);\n\nwire_io also implements many of the blocking library calls as overridden\nfunctions that will call the wio\\_ function when in the wire and call the\noriginal libc function when in the thread so that libraries and external code\ndoes not need to be modified to work in the wire. That pertains to statically\nlinked code to the executable, a shared library may need its own special\nhandling and this use is still untested for external shared libraries.\n\nwire_lock\n---------\n\nwire_lock provides a way to lock a shared resource between the wires. This is\nrarely needed but one such example is multiple senders over a TCP socket where\neach can block but mostly won't. The lock is very low cost if no blocking\nhappens (only a few integer operations) and will suspend the wire and be\ncompletely fair if blocking is needed.\n\n    void wire_lock_init(wire_lock_t *l);\n    void wire_lock_take(wire_lock_t *l);\n    void wire_lock_release(wire_lock_t *l);\n    void wire_lock_wait_clear(wire_lock_t *l);\n\nThere is no smart scheduling done, the scheduling is completely FIFO based and\nis handled by the core wire layer. Also, only a single thread is assumed to run\nthe wires even though there is a vestige or two of a multi-thread assumption as\nwell, this can later be added by using Thread Local Storage to reduce the need\nto pass the wire_thread construct around.\n\nDependencies\n============\n\nIt is currently supported on modern Linux only and essentially expects\nfeatures that were only available as of late 2.6.x where x \u003e= 30\nThis stems mostly from the user of epoll, timerfd and signalfd.\nThis can be replaced probably with libev but will mandate some change to the\nAPI.\n\nThe coroutine core uses libcoro to provide support for multiple architectures.\n\nLicense\n=======\n\nlibwire itself is licensed under the MIT license (see the LICENSE file),\nlibcoro is licensed under the GNU GPL v2 or later (used on non x86-64, non-linux arches)\nhttp_parser is licensed under the nginx license (see src/http_parser.c)\n\nAuthor\n======\n\nBaruch Even \u003cbaruch@ev-en.org\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaruch%2Flibwire","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaruch%2Flibwire","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaruch%2Flibwire/lists"}