{"id":20400089,"url":"https://github.com/codebrainz/grinder","last_synced_at":"2025-04-12T13:50:56.672Z","repository":{"id":36929081,"uuid":"41236317","full_name":"codebrainz/grinder","owner":"codebrainz","description":"Simple C++ event loop library","archived":false,"fork":false,"pushed_at":"2015-08-24T05:18:47.000Z","size":140,"stargazers_count":55,"open_issues_count":0,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-26T08:23:31.208Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/codebrainz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"License.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-23T04:57:52.000Z","updated_at":"2025-02-12T06:13:56.000Z","dependencies_parsed_at":"2022-09-09T12:10:31.112Z","dependency_job_id":null,"html_url":"https://github.com/codebrainz/grinder","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/codebrainz%2Fgrinder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codebrainz%2Fgrinder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codebrainz%2Fgrinder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codebrainz%2Fgrinder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codebrainz","download_url":"https://codeload.github.com/codebrainz/grinder/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248575647,"owners_count":21127225,"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":[],"created_at":"2024-11-15T04:38:21.453Z","updated_at":"2025-04-12T13:50:56.650Z","avatar_url":"https://github.com/codebrainz.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"Grinder README\n==============\n\nGrinder is a simple C++ library providing an \"asynchronous\" event\nloop.\n\nTo use Grinder in your project, just copy the .cpp and .h files you\nneed into your project. The files use standard C++11 as well as some\nPOSIX-ish APIs. The `Grinder/Linux` directory contains wrappers around\nsome useful Linux-specific APIs like timerfd and signalfd.\n\nThe main.cpp file contains some test/demo code.\n\nConcepts\n--------\n\nThe main component is the `EventLoop` which controls the processing of\nevents. It is the heart of the system.\n\n`EventSource` subclasses provide a mechanism for detecting when events\nare ready. The `EventLoop` uses the `EventSource` interface to figure\nout when the events are ready as well as dispatching events. All of\nthe `___Source` classes as well as the classes in the `Grinder/Linux`\ndirectory provide implementations of the `EventSource` interface.\n\nThe `EventSource` interface is composed of the following pure virtual \nfunctions:\n\n- `bool prepare(int\u0026 max_timeout)`\n  This function is called before the event loop polls any file descriptors.\n  If your event source knows it's ready now, implementations can return\n  `true` and skip polling. The `max_timeout` argument is an output\n  parameter that can limit how long the `poll()` timeout is. The value\n  is in milliseconds and may be lowered by other event sources.\n- `bool check()`\n  This function is called after the file descriptors have been polled.\n  The `check()` function won't be called if the `prepare()` function\n  returned `true` for a particular event loop iteration. Examples of\n  using this function are to check if specific `FileEvents` have occured\n  or whether a timer has elapsed. Return `true` to have the event handler\n  dispatched or false to not dispatch.\n- `bool dispatch(EventHandler\u0026 handler)`\n  This function is called when either the `prepare()` or `check()`\n  functions have returned `true` indicating that an event has occurred.\n  The `handler` argument provides a reference to the function to be\n  called. Implementations of this function might choose to read a file\n  descriptor or setup some event source-specific state which might be\n  useful to event handlers. When this function returns `false`, the\n  event source dispatching will be removed from the event loop and\n  deleted. If it returns `true`, events will continue to be checked and\n  dispatched.\n\nThere are 3 basic event source types, represented by the base classes \n`FileSource`, `IdleSource`, and `TimeoutSource`. Most event sources \nwill want to subclass one of these rather than subclassing the \n`EventSource` directly.\n\nThe typedef for `EventHandler` provides a function type that should be \nused when setting the callback for event sources. You can use a \nfunctor, function pointer or anonymous (lambda) function for the event \nhandler. If the handler returns `false`, the event source which called \nthe handler will be removed from the event loop. If it returns `true`, \nthe event source will continue to be checked and dispatched.\n\nEvent Sources\n-------------\n\n### FileSource\n\nFile sources have a file descriptor as well as a set of events to be\nwatched for on the file descriptor. The `EventLoop` uses the `poll()`\nfunction or similar to check whether any of the file descriptors are\nready. Most event sources will want to subclass this class.\n\n### IdleSource\n\nIdle sources are a special kind of event source which will only be\ndispatched when there's nothing else for the event loop to do (ie. no\ntimers have expired and no file descriptors are ready). Usually you\nwon't use this class directly but rather add idle event sources to\nthe event loop using `EventLoop::add_idle()` passing it a function\nto be called when the event loop is idle.\n\n### TimeoutSource\n\nTimeout sources show an example of a class which is directly inherited\nfrom `EventSource` as they have no backing file descriptor. Timeouts\nare not particularly accurate but provide a convenient mechanism to\ncall a function at roughly some time in the future. Ususally you won't\nuse `TimeoutSource` class directly but rather add timeout event sources\nto the event loop using `EventLoop::add_timeout()`.\n\nAn alternative to `TimeoutSource` for Linux is the `TimerFD` class. It\ninherits from `FileSource` as it uses the Linux-specific `timerfd` API.\nThis should in theory provide better accuracy, but the class is only\ndesigned to handle timers accurate to whole milliseconds.\n\n### SignalSource\n\nSignal sources are designed to wrangle Unix signals into the event\nloop.\n\nIt's important that only one `SignalSource` instance be added to an\nevent loop. Since the `SignalSource` installs global signal handlers,\nand optionally modifies the global process signal mask, adding more\nthan one `SignalSource` to event loops will cause bad things to happen.\n\nThe recommended usage is to create a single `SignalSource` when setting\nup the `EventLoop` initially, and adding it to the loop, leaving it to\nbe freed when the loop cleans up. Keep a pointer the `EventSource` if\nyou want to add or remove signals to be watched using the\n`SignalSource::add()` and `SignalSource::remove()` member functions.\nAny other usage is likely to cause problems.\n\nThere are two concrete implementations of the `SignalSource`,\n`GenericSignalSource` and the Linux-specific `SignalFD`.\n\n`GenericSignalSource` installs a global signal handler which writes to \none end of a pipe, while the event source, being derived from \n`FileSource` (via `SignalSource`), watches the other end of the pipe in \nthe event loop. The signal handler writes the signal number as a 32-bit \nunsigned integer and the `GenericSignalSource` reads the signal number, \nsets the `SignalSource::signo` member variable and then dispatches the \nevent to the handler.\n\nAn alternative to `GenericSignalSource` for Linux is the `SignalFD` \nclass which provides a wrapper around the Linux-specific `signalfd` \nAPI. It derives from `FileSource` (via `SignalSource`) and watches a \nfile descriptor that the kernel will send signal information to.\n\nBuilding and Embedding\n======================\n\nCurrently the library is meant to be integrated into other projects\ndirectly. There is a `Makefile` included in the root source directory\nwhich is just meant for testing the build. It doesn't support fancy\nstuff like out-of-tree builds or installing the library. The `Makefile`\nproduces a `libgrinder.so` file and `GrinderTest` program in the root\ndirectory.\n\nThere's also a `Grinder.pro` file in the root source directory which is\njust enough to compile the code (into a single demo program) using\nQtCreator/qmake. This is only meant for use when working on `Grinder`\ncode in the QtCreator IDE, not for a real build system.\n\n### Using it with your Project\n\nThis is the current recommended method of using Grinder in your project:\n\n1. Copy the entire `Grinder` sub-directory into your project's tree.\n2. Copy the `License.txt` and optionally the `README.md` files into\n   that same directory.\n3. If not using the Linux-specific classes, you can delete the\n   `Grinder/Linux` directory.\n4. Add the .cpp files to be compiled by your build system/C++ compiler.\n  - For GCC-like compilers, you should use the `-std=c++11` flag to\n    enable the C++11 support which Grinder requires.\n  - Add the directory containing the `Grinder` directory to the compiler's\n    include search path. This is so your code can use Grinder headers\n    like `#include \u003cGrinder/TheHeader.h\u003e`.\n5. In the code that uses Grinder, it is recommended to include the\n   main `Grinder` header like `#include \u003cGrinder/Grinder\u003e`. That header\n   includes all of the other headers, including platform-specific ones\n   if supported.\n\nIt is up to the project whether to build an actual library. With some\nbuild-systems it's convenient to build \"helper\" libraries and in other\ncases you might want a proper shared library if several programs you\ncontrol use Grinder. The optimal method for a single application is to\nlink the compiled Grinder object files directly into the main binary.\n\nPortability\n===========\n\nWhile Grinder is meant to be cross-platform, at least initially such\nsupport is not widely tested. Primary development happens on Linux as\nwell as minor testing on OSX.\n\nNo testing on Windows has been performed but it is a goal to add both\ngeneric and platform-specific support for Windows. The `EventLoop`,\n`EventSource`, `IdleSource`, and `TimeoutSource` should be fine on\nWindows out of the box. `SignalSource` and `FileSource`, which use file\ndescriptors rather than Win32 `HANDLE`s are most likely to require\nporting effort. Supporting sockets on Windows should be relatively\npainless as it has a file-descriptor like API on Windows.\n\nClass Hierarchy\n===============\n\nBelow is a little diagram to show the class inheritance in Grinder.\n\n    EventLoop\n    EventSource\n        IdleSource\n        TimeoutSource\n        FileSource\n            SignalSource\n              GenericSignalSource\n              SignalFD\n            TimerFD\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodebrainz%2Fgrinder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodebrainz%2Fgrinder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodebrainz%2Fgrinder/lists"}