{"id":20704329,"url":"https://github.com/osch/lua-mtmsg","last_synced_at":"2025-04-23T01:26:08.013Z","repository":{"id":43800959,"uuid":"145289830","full_name":"osch/lua-mtmsg","owner":"osch","description":"Low-level multi-threading message buffers for the Lua scripting language (see: https://github.com/osch/lua-mtmsg#mtmsg)","archived":false,"fork":false,"pushed_at":"2023-11-09T23:51:45.000Z","size":204,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-29T20:51:07.301Z","etag":null,"topics":["lua","lua-binding","lua-library","multithreading"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/osch.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":"2018-08-19T09:31:25.000Z","updated_at":"2023-09-18T06:27:51.000Z","dependencies_parsed_at":"2022-09-01T03:22:39.212Z","dependency_job_id":null,"html_url":"https://github.com/osch/lua-mtmsg","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osch%2Flua-mtmsg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osch%2Flua-mtmsg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osch%2Flua-mtmsg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osch%2Flua-mtmsg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/osch","download_url":"https://codeload.github.com/osch/lua-mtmsg/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250350802,"owners_count":21416197,"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":["lua","lua-binding","lua-library","multithreading"],"created_at":"2024-11-17T01:11:57.629Z","updated_at":"2025-04-23T01:26:07.997Z","avatar_url":"https://github.com/osch.png","language":"C","readme":"# mtmsg \n[![Licence](http://img.shields.io/badge/Licence-MIT-brightgreen.svg)](LICENSE)\n[![build status](https://github.com/osch/lua-mtmsg/workflows/test/badge.svg)](https://github.com/osch/lua-mtmsg/actions/workflows/test.yml)\n[![Build status](https://ci.appveyor.com/api/projects/status/r4gwhqv2jvv2jirn?svg=true)](https://ci.appveyor.com/project/osch/lua-mtmsg)\n[![Install](https://img.shields.io/badge/Install-LuaRocks-brightgreen.svg)](https://luarocks.org/modules/osch/mtmsg)\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\nLow-level multi-threading message buffers for the [Lua] scripting language.\n\nThis package provides in-memory message buffers for inter-thread communication. \nThe implementation is independent from the underlying threading library\n(e.g. [Lanes] or [llthreads2]).\n\nThis package is also available via LuaRocks, see https://luarocks.org/modules/osch/mtmsg.\n\n[Lua]:           https://www.lua.org\n[Lanes]:         https://luarocks.org/modules/benoitgermain/lanes\n[llthreads2]:    https://luarocks.org/modules/moteus/lua-llthreads2\n[carray]:        https://github.com/osch/lua-carray\n\nSee below for full [reference documentation](#documentation) .\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n#### Requirements\n\n   * Tested operating systems: Linux, Windows, MacOS\n   * Other Unix variants: could work, but untested, required are:\n      * gcc atomic builtins or C11 `stdatomic.h`\n      * `pthread.h` or C11 `threads.h`\n   * Tested Lua versions: 5.1, 5.2, 5.3, 5.4, luajit 2.0 \u0026 2.1\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n## Examples\n\nSimple example, passes message buffer by integer id to another thread \n([llthreads2] is used as multi-threading implementation in this example):\n\n```lua\nlocal llthreads = require(\"llthreads2.ex\")\nlocal mtmsg     = require(\"mtmsg\")\nlocal buffer    = mtmsg.newbuffer()\nlocal thread    = llthreads.new(function(bufferId)\n                                    local mtmsg  = require(\"mtmsg\")\n                                    local buffer = mtmsg.buffer(bufferId)\n                                    return buffer:nextmsg()\n                                end,\n                                buffer:id())\nthread:start()\nbuffer:addmsg(\"Hello\", \"world!\")\nprint(thread:join())\n```\n\nMultiple buffers can be connected to one listener:\n\n```lua\nlocal mtmsg = require(\"mtmsg\")\nlocal lst   = mtmsg.newlistener()\nlocal b1    = lst:newbuffer()\nlocal b2    = lst:newbuffer()\nb1:addmsg(\"m1\")\nb2:addmsg(\"m2\")\nb1:addmsg(\"m3\")\nb2:setmsg(\"m4\") -- overwrites m2 in b2\nb2:addmsg(\"m5\")\nassert(lst:nextmsg() == \"m1\")\nassert(lst:nextmsg() == \"m4\")\nassert(lst:nextmsg() == \"m3\")\nassert(lst:nextmsg() == \"m5\")\nassert(lst:nextmsg(0) == nil)\n```\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n## Documentation\n\n   * [Module Functions](#module-functions)\n       * mtmsg.newbuffer()\n       * mtmsg.buffer()\n       * mtmsg.newlistener()\n       * mtmsg.listener()\n       * mtmsg.abort()\n       * mtmsg.isabort()\n       * mtmsg.time()\n       * mtmsg.sleep()\n       * mtmsg.type()\n       * mtmsg.newwriter()\n       * mtmsg.newreader()\n   * [Buffer Methods](#buffer-methods)\n       * buffer:id()\n       * buffer:name()\n       * buffer:addmsg()\n       * buffer:setmsg()\n       * buffer:msgcnt()\n       * buffer:clear()\n       * buffer:nextmsg()\n       * buffer:notifier()\n       * buffer:nonblock()\n       * buffer:isnonblock()\n       * buffer:close()\n       * buffer:abort()\n       * buffer:isabort()\n   * [Listener Methods](#listener-methods)\n       * listener:id()\n       * listener:name()\n       * listener:newbuffer()\n       * listener:nextmsg()\n       * listener:nonblock()\n       * listener:isnonblock()\n       * listener:clear()\n       * listener:close()\n       * listener:abort()\n       * listener:isabort()\n   * [Writer Methods](#writer-methods)\n       * writer:add()\n       * writer:addmsg()\n       * writer:setmsg()\n       * writer:clear()\n   * [Reader Methods](#reader-methods)\n       * reader:next()\n       * reader:nextmsg()\n       * reader:clear()\n   * [Errors](#errors)\n       * mtmsg.error.ambiguous_name\n       * mtmsg.error.message_size\n       * mtmsg.error.no_buffers\n       * mtmsg.error.object_closed\n       * mtmsg.error.operation_aborted\n       * mtmsg.error.out_of_memory\n       * mtmsg.error.unknown_object\n       \n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n### Module Functions\n\n* **`mtmsg.newbuffer([name,][size[,grow]])`**\n\n  Creates a new buffer and returns a lua object for referencing the\n  created buffer.\n\n    * *name*  - optional string, the name of the new buffer,\n    * *size*  - optional integer, initial size in bytes for the buffer that\n                holds all messages for this buffer (defaults to *1024*).\n    * *grow*  - optional float, the factor how fast buffer memory grows\n                if more data has to be buffered. If *0*, the used\n                memory is fixed by the initially given size. If *\u003c=1* the \n                buffer grows only by the needed bytes (default value is *2*,\n                i.e. the size doubles if buffer memory needs to grow).\n  \n  The created buffer is garbage collected if the last object referencing this\n  buffer vanishes.\n  \n  The created buffer objects implement the [Notify C API], the [Receiver C API] \n  and the [Sender C API], i.e. native code can send notifications or send or \n  receive messages from any thread.\n  \n  [Notify C API]:   https://github.com/lua-capis/lua-notify-capi\n  [Receiver C API]: https://github.com/lua-capis/lua-receiver-capi\n  [Sender C API]:   https://github.com/lua-capis/lua-sender-capi\n  \n  Possible errors: *mtmsg.error.operation_aborted*\n                   \n\n* **`mtmsg.buffer(id|name)`**\n\n  Creates a lua object for referencing an existing buffer. The buffer must\n  be referenced by its *id* or *name*. Referencing the buffer by *id* is\n  much faster than referencing by *name* if the number of buffers \n  increases.\n\n    * *id* - integer, the unique buffer id that can be obtained by\n             *buffer:id()*.\n\n    * *name* - string, the optional name that was given when the\n               buffer was created with *mtmsg.newbuffer()* or with \n               *listener:newbuffer()*. To find a buffer by name \n               the name must be unique for the whole process.\n             \n  Possible errors: *mtmsg.error.ambiguous_name*,\n                   *mtmsg.error.unknown_object*,\n                   *mtmsg.error.operation_aborted*\n\n\n* **`mtmsg.newlistener([name])`**\n\n  Creates a new buffer listener and returns a lua object for referencing the\n  created listener.\n  \n    * *name* - optional string, the name of the new listener.\n\n  The created listener is garbage collected if the last reference object to this\n  listener vanishes.\n\n  Possible errors: *mtmsg.error.operation_aborted*,\n\n* **`mtmsg.listener(id|name)`**\n\n  Creates a lua object for referencing an existing listener. The listener must\n  be referenced by its *id* or *name*. Referencing the listener by *id* is\n  much faster than referencing by *name* if the number of listeners \n  increases.\n\n    * *id* - integer, the unique buffer id that can be obtained by\n           *listener:id()*.\n\n    * *name* - string, the optional name that was given when the\n               listener was created with *mtmsg.newlistener()*. To\n               find a listener by name the name must be unique for\n               the whole process.\n\n  Possible errors: *mtmsg.error.ambiguous_name*,\n                   *mtmsg.error.unknown_object*,\n                   *mtmsg.error.operation_aborted*\n\n\n* **`mtmsg.abort([flag])`**\n\n  Aborts operation on all buffers and listeners.\n  \n    * *flag* - optional boolean. If *true* or not given all buffers and\n               listeners are aborted, i.e. a *mtmsg.error.operation_aborted* is\n               raised. If *false*, abortion is canceled, i.e. all buffers and\n               listeners can be used again.\n\n* **`mtmsg.isabort()`**\n\n  Returns *true* if *mtmsg.abort()* or *mtmsg.abort(true)* was called.\n  \n* **`mtmsg.time()`**\n\n  Similiar to *os.time()*: Gives the time in seconds, but as float with higher\n  precision (at least milliseconds).\n  \n* **`mtmsg.sleep(timeout)`**\n  \n  Suspends the current thread for the specified time.\n\n  * *timeout* float, time in seconds.\n\n  Possible errors: *mtmsg.error.operation_aborted*\n  \n* **`mtmsg.type(arg)`**\n\n  Returns the type of *arg* as string. Same as *type(arg)* for builtin types.\n  For *userdata* objects it tries to determine the type from the *__name* field in \n  the metatable and checks if the metatable can be found in the lua registry for this key\n  as created by [luaL_newmetatable](https://www.lua.org/manual/5.3/manual.html#luaL_newmetatable).\n\n  Returns *\"userdata\"* for userdata where the *__name* field in the metatable is missing\n  or does not have a corresponding entry in the lua registry.\n  \n  Returns *\"mtmsg.buffer\"* or *\"mtmsg.listener\"* if the arg is one of the userdata types \n  provided by the mtmsg package.\n\n\n* **`mtmsg.newwriter([size[,grow]])`**\n\n  Creates a new writer. A writer can be used to build up messages incrementally by adding\n  new message elements using *writer:add()*. The message than can be added to a buffer\n  using *writer:addmsg()* in one atomic step.\n\n    * *size*  - optional integer, initial size in bytes for the memory that\n                holds all message elements for this writer (defaults to *1024*).\n    * *grow*  - optional float, the factor how fast memory grows if more\n                message elements have to be buffered. If *0*, the used\n                memory is fixed by the initially given size. If *\u003c=1* the \n                memory grows only by the needed bytes (default value is *2*,\n                i.e. the size doubles if memory needs to grow).\n  \n  The created writer canot be accessed from other threads and is garbage collected\n  like any normal Lua value.\n  \n\n* **`mtmsg.newreader([size[,grow]])`**\n\n  Creates a new reader. A reader can be used to parse messages incrementally by invoking\n  *reader:next()* to get the message elements. Invoking *reader:nextmsg()* gets the next\n  message of a buffer or listener into the reader in one atomic step.\n\n\n    * *size*  - optional integer, initial size in bytes for the memory that\n                holds all message elements for this reader (defaults to *1024*).\n    * *grow*  - optional float, the factor how fast memory grows if more\n                message elements have to be buffered. If *0*, the used\n                memory is fixed by the initially given size. If *\u003c=1* the \n                memory grows only by the needed bytes (default value is *2*,\n                i.e. the size doubles if memory needs to grow).\n  \n  The created reader canot be accessed from other threads and is garbage collected\n  like any normal Lua value.\n  \n\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n### Buffer Methods\n\n* **`buffer:id()`**\n  \n  Returns the buffer's id as integer. This id is unique for the whole process.\n\n* **`buffer:name()`**\n\n  Returns the buffer's name that was given to *mtmsg.newbuffer()* or to\n  *listener:newbuffer()*.\n  \n* **`buffer:addmsg(...)`**\n\n  Adds the arguments together as one message to the buffer. Arguments can be\n  simple data types (string, number, boolean, nil, light user data, C function)\n  or [carray] objects.\n  \n  Returns *true* if the message could be added to the buffer. \n  \n  Returns *false* if *buffer:isnonblock() == true* and the buffer is\n  concurrently accessed from a parallel thread. \n  \n  Returns *false* if the buffer was created with a grow factor *0* and the\n  current buffer messages together with the new message would exceed the\n  buffer's fixed size.\n  \n  Possible errors: *mtmsg.error.message_size*,\n                   *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n\n* **`buffer:setmsg(...)`**\n\n  Sets the arguments together as one message into the buffer. All other messages\n  in this buffer are discarded. Arguments can be simple data types \n  (string, number, boolean, light user data, C function) or [carray] objects.\n  \n  Returns *true* if the message could be set into the buffer.\n  \n  Returns *false* if *buffer:isnonblock() == true* and the buffer is\n  concurrently accessed from another thread. \n  \n  Possible errors: *mtmsg.error.message_size*,\n                   *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n\n\n* **`buffer:msgcnt()`**\n\n  Returns the number of messages in the buffer.\n\n* **`buffer:clear()`**\n\n  Removes all messages from the buffer.\n\n  Returns *true* if the buffer could be cleared.\n  \n  Returns *false* if *buffer:isnonblock() == true* and the buffer is\n  concurrently accessed from another thread. \n  \n\n  Possible errors: *mtmsg.error.object_closed*\n\n\n* **`buffer:nextmsg([timeout][, carray]*)`**\n\n  Returns all the arguments that were given as one message by invoking the method\n  *buffer:addmsg()* or *buffer:setmsg()*. The returned message is removed\n  from the underlying buffer.\n  \n  * *timeout* optional float, maximal time in seconds for waiting for the next \n    message. The method returns without result if timeout is reached.\n  \n  * *carray* optional one or more [carray] objects. These objects are reused \n             if the message contains an array of the corresponding data type \n             of the given *carray*. Unused *carray* objects are reset to length 0\n             after this call.\n  \n  If timeout is not given or *nil* and *buffer:isnonblock() == false* then this \n  methods waits without timeout limit forever until a next message becomes available.\n\n  If timeout is not given or *nil* and *buffer:isnonblock() == true* then this method\n  returns immediately without result if no next message is available or if the\n  buffer is concurrently accessed from another thread.\n\n  Possible errors: *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n\n\n* **`buffer:notifier(ntf[,type[,threshold]])`**\n\n  Connects a notifier object to the underlying buffer.\n  \n  * *ntf*       notifier object or *nil*. If *nil* is given, an existing notifier \n                object of the specified type is disconnected from the underlying buffer.\n                \n  * *type*      optional string, value \"\u003c\" for a notifier that is notified if a message \n                is removed from the buffer and \"\u003e\" for a notifier that is notified if\n                a message is added to the buffer. Default value is \"\u003e\".\n                \n  * *threshold* optional integer. For notifier type \"\u003c\" the notifier is notified\n                if the current number of messages is below the threshold after a\n                message is removed from the buffer. For notifier type \"\u003e\" the notifier\n                is notifierd if the current number of message is above the threshold\n                after a message is added to the buffer. If nil or not given\n                the threshold is not considered. i.e. the corresponding notifier\n                is always called if a message is removed or added.\n  \n  A buffer can only have one connected notifier object per notifier type \"\u003c\" or \"\u003e\".\n  It is an error to call this method in case the buffer already has a connected \n  notifier object of the same type.\n  \n  The given notifier object must implement the [Notify C API], \n  see [src/notify_capi.h](./src/notify_capi.h), i.e. the given object must\n  have an an associated meta table entry *_capi_notify* delivered by\n  the C API function *notify_get_capi()* and the associated \n  C API function *toNotifier()* must return a valid pointer for the given \n  notifier object *ntf*.\n  \n  [Notify C API]: https://github.com/lua-capis/lua-notify-capi\n  \n  A buffer itself does also implement the Notify C API, i.e. a buffer can be\n  also set as notifier for another buffer, see [lua-mtmsg/example06.lua](./examples/example06.lua).\n  \n  More Examples:\n  * [lua-mtstates/example06.lua](https://github.com/osch/lua-mtstates/blob/master/examples/example06.lua)\n  * [lua-lpugl/example10.lua](https://github.com/osch/lua-lpugl/blob/master/example/example10.lua)\n  * [lua-nocurses/example03.lua](https://github.com/osch/lua-nocurses/blob/master/examples/example03.lua)\n\n  Possible errors: *mtmsg.error.object_closed*,\n                   *mtmsg.error.has_notifier*\n\n* **`buffer:nonblock([flag])`**\n\n  if *flag* is not given or *true* the buffer referencing object will operate\n  in *nonblock mode*. This does not affect the underlying buffer, i.e. several\n  buffer referencing objects could operate in different modes accessing the same \n  buffer.\n  \n  *Nonblock mode* affects the methods *buffer:nextmsg()*, *buffer:addmsg()*\n  and *buffer:setmsg()*: all these methods return immediately with negative \n  result if the underlying buffer is concurrently accessed from another thread.\n  \n  *Nonblock mode* can be useful for realtime processing, when it is more importent\n  to continue processing and a blocking operation could be postponed or be skipped.\n\n  Possible errors: *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n\n* **`buffer:isnonblock()`**\n\n  Returns *true* if *buffer:nonblock()* or *buffer:nonblock(true)* was invoked.\n\n* **`buffer:close()`**\n\n  Closes the underlying buffer and frees the memory. Every operation from any\n  referencing object raises a *mtmsg.error.object_closed*. A closed buffer\n  cannot be reactivated.\n\n* **`buffer:abort([flag])`**\n\n  Aborts operation on the underlying buffer.\n  \n    * *flag* - optional boolean. If *true* or not given the buffer is aborted, \n               i.e. a *mtmsg.error.operation_aborted* is raised. \n               If *false*, abortion is canceled, i.e. the buffer can be used \n               again.\n\n* **`buffer:isabort()`**\n\n  Returns *true* if *buffer:abort()* or *buffer:abort(true)* was called.\n\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n### Listener Methods\n\n* **`listener:id()`**\n  \n  Returns the listener's id as integer. This id is unique for the whole process.\n\n* **`listener:name()`**\n\n  Returns the listener's name that was given to *mtmsg.newlistener()*.\n\n\n* **`listener:newbuffer([name,][size[,grow]])`**\n\n  Creates a new buffer that is connected to the listener and returns a lua object \n  for referencing the created buffer.\n  \n  The arguments are the same as for the module function *mtmsg.newbuffer*.\n\n  The created buffer is garbage collected if the last object referencing this\n  buffer vanishes. The buffer is **not** referenced by the connected listener.\n  \n  If the buffer is garbage collected, the remaining messages in this buffer are \n  still delivered to the listener, i.e. these messages are not discarded.\n\n  Possible errors: *mtmsg.error.operation_aborted*\n\n\n* **`listener:nextmsg([timeout][, carray]*)`**\n\n  Returns all the arguments that were given as one message by invoking the method\n  *buffer:addmsg()* or *buffer:setmsg()* to one of the buffers that are\n  connected to this listener.  The returned message is removed\n  from the underlying buffer.\n  \n  * *timeout* optional float, maximal time in seconds for waiting for the next \n    message. The method returns without result if timeout is reached.\n\n  * *carray* optional one or more [carray] objects. These objects are reused \n             if the message contains an array of the corresponding data type \n             of the given *carray*. Unused *carray* objects are reset to length 0\n             after this call.\n  \n  If timeout is not given or *nil* and *listener:isnonblock() == false* then this \n  methods waits without timeout limit forever until a next message becomes available.\n\n  If timeout is not given or *nil* and *listener:isnonblock() == true* then this methods\n  returns immediately without result if no next message is available or if the\n  listener is concurrently accessed from another thread.\n\n  Possible errors: *mtmsg.error.no_buffers*,\n                   *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n    \n\n* **`listener:nonblock([flag])`**\n\n  if *flag* is not given or *true* the listener referencing object will operate\n  in *nonblock mode*. This does not affect the underlying listener, i.e. several\n  listener referencing objects could operate in different modes accessing the same \n  listener.\n  \n  *Nonblock mode* affects the method *listener:nextmsg()*: this method returns\n  immediately with negative result if the underlying listener (or one of its\n  buffers) is concurrently accessed from another thread.\n  \n  *Nonblock mode* can be useful for realtime processing, when it is more importent\n  to continue processing and a blocking operation could be postponed or be skipped.\n\n  Possible errors: *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n\n* **`listener:isnonblock()`**\n\n  Returns *true* if *listener:nonblock()* or *listener:nonblock(true)* was invoked.\n\n* **`listener:clear()`**\n\n  Removes all messages from all connected buffers.\n\n  Returns *true* if all buffers could be cleared.\n  \n  Returns *false* if *listener:isnonblock() == true* and the listener or one of the \n  buffers is concurrently accessed from another thread. \n  \n  Possible errors: *mtmsg.error.object_closed*\n\n\n* **`listener:close()`**\n\n  Closes the listener and all connected buffers and frees the memory. Every \n  operation from any referencing object raises a *mtmsg.error.object_closed*. \n  A closed listener cannot be reactivated.\n\n\n* **`listener:abort([flag])`**\n\n  Aborts operation on the underlying listener and all connected buffers.\n  \n    * *flag* - optional boolean. If *true* or not given the listener and connected buffers \n               are aborted, i.e. a *mtmsg.error.operation_aborted* is raised. \n               If *false*, abortion is canceled, i.e. the listener and \n               all connected buffers can be used again.\n\n\n* **`listener:isabort()`**\n\n  Returns *true* if *listener:abort()* or *listener:abort(true)* was called.\n\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n### Writer Methods\n\nA writer can be used to build up messages incrementally by adding\nnew message elements using *writer:add()*. \n\nThe message than can be added to a buffer using *writer:addmsg()* in one atomic step.\n\nFor example, this code\n```lua\n    writer:add(\"foo1\"); writer:add(\"foo2\", \"foo3\"); writer:addmsg(buffer)\n```\nis equivalent to\n```lua\n    buffer:addmsg(\"foo1\", \"foo2\", \"foo3\")\n```\n\n* **`writer:add(...)`**\n\n  Adds the arguments as message elements into the writer. Arguments can be\n  simple data types (string, number, boolean, nil, light user data, C function)\n  or [carray] objects.\n  \n  Possible errors: *mtmsg.error.message_size*\n\n* **`writer:addmsg(buffer)`**\n\n  Adds the writer's message elements together as one message to the buffer. \n  \n  Returns *true* if the message could be added to the buffer. In this case,\n  the message elements are removed from the writer, i.e. the writer can\n  be re-used to build a new message.\n  \n  Returns *false* if *buffer:isnonblock() == true* and the buffer is\n  concurrently accessed from a parallel thread. \n  \n  Returns *false* if the buffer was created with a grow factor *0* and the\n  current buffer messages together with the new message would exceed the\n  buffer's fixed size.\n  \n  Possible errors: *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n\n* **`writer:setmsg(buffer)`**\n\n  Sets the writer's message elements together as one message into the buffer. \n  All other messages in the given buffer are discarded.\n  \n  Returns *true* if the message could be added to the buffer. \n  \n  Returns *false* if *buffer:isnonblock() == true* and the buffer is\n  concurrently accessed from a parallel thread. \n  \n  Returns *false* if the buffer was created with a grow factor *0* and the\n  current buffer messages together with the new message would exceed the\n  buffer's fixed size.\n  \n  Possible errors: *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n\n* **`writer:clear()`**\n  \n  Removes all message elements from the writer.\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n### Reader Methods\n\nA reader can be used to parse messages incrementally by invoking *reader:next()* to get the message \nelements. \n\nInvoking *reader:nextmsg()* gets the next message of a buffer or listener into the reader in one \natomic step.\n\nFor example, this code\n```lua\n    reader:nextmsg(buffer); local a = reader:next(); local b, c = reader:next(2)\n```\nis equivalent to\n```lua\n    local a, b, c = buffer:nextmsg()\n```\n\n* **`reader:next([count][, carray]*)`**\n\n  Returns next message elements from the reader. Returns nothing if no more message elements \n  are available. The returned elements are removed from the reader's internal list of message\n  elements.\n\n  * *count* - optional integer, the maximaum number of message elements to be returned\n              (defaults to 1).\n\n  * *carray* optional one or more [carray] objects. These objects are reused \n             if the message contains an array of the corresponding data type \n             of the given *carray*. Unused *carray* objects are reset to length 0\n             after this call.\n\n* **`reader:nextmsg(buffer|listener, [timeout])`**\n\n  Gets the next message of a buffer or listener into the reader in one atomic step. The\n  message is removed from the given buffer or listener. If the reader contained older\n  message elements from a previous message these are discarded before all messages elements \n  from the new message are added to the reader, i.e. after this call the reader contains \n  only message elements from the new message.\n\n  * *timeout* optional float, maximal time in seconds for waiting for the next \n    message. The method returns *false* if timeout is reached and no message\n    was reveived.\n\n  Returns *true* if a message could be obtained from the given buffer or listener. In\n  this case the message is removed from the given buffer or listener.\n\n  If no timeout is given and *isnonblock() == false* for the given buffer or listener then \n  this methods waits without timeout limit until a next message becomes available.\n\n  If no timeout is given and *isnonblock() == true* for the given buffer or listener then this \n  methods returns immediately *false*  if no next message is available or if the given buffer \n  or listener is concurrently accessed from another thread.\n\n  Possible errors: *mtmsg.error.no_buffers*,\n                   *mtmsg.error.object_closed*,\n                   *mtmsg.error.operation_aborted*\n\n* **`reader:clear()`**\n  \n  Removes all message elements from the reader.\n\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n\n### Errors\n\n* All errors raised by this module are string values. Special error strings are\n  available in the table `mtmsg.error`, example:\n\n  ```lua\n  local mtmsg = require(\"mtmsg\")\n  assert(mtmsg.error.object_closed == \"mtmsg.error.object_closed\")\n  ```\n  \n  These can be used for error evaluation purposes, example:\n  \n  ```lua\n  local mtmsg = require(\"mtmsg\")\n  local listener = mtmsg.newlistener()\n  local _, err = pcall(function() listener:nextmsg() end)\n  assert(err:match(mtmsg.error.no_buffers))\n  ```\n\n* **`mtmsg.error.ambiguous_name`**\n\n  More than one buffer or listener was found for the given name to \n  *mtmsg.buffer()* or *mtmsg.listener()*. \n  To find a buffer by name, the buffer name must be unique among all buffers\n  of the whole process. To find a listener by name, the listener name must \n  be unique among all listeners of the whole process \n\n\n* **`mtmsg.error.message_size`**\n  \n  The size of one message exceeds the limit that was given in *mtmsg.newbuffer()*, \n  *listener:newbuffer()*, *mtmsg.newwriter()* or *mtmsg.newreader()* and a grow\n  factor *0* was specified to prevent the internal memory buffer growing.\n  \n* **`mtmsg.error.no_buffers`**\n\n  *listener:nextmsg()* was called and no buffer is connected to the listener.\n  Buffers are subject to garbage collection and therefore a reference to a created\n  buffer is needed to keep it alive. If a listener's buffer becomes garbage\n  collected, it is disconnected from the listener.\n\n* **`mtmsg.error.has_notifier`**\n\n  The method *buffer:notifier()* is called with a notifier object but the underlying\n  buffer already has notifier object.\n\n* **`mtmsg.error.object_closed`**\n\n  An operation is performed on a closed buffer or listener, i.e. the method\n  *buffer:close()* or *listener:close()* has been called.\n\n* **`mtmsg.error.operation_aborted`**\n\n  An operation should be performed on an object with *object:isabort() == true*\n  or *mtmsg.abort()* has been called to abort all operations.\n\n* **`mtmsg.error.out_of_memory`**\n\n  Buffer memory cannot be allocated.\n\n* **`mtmsg.error.unknown_object`**\n\n  A reference to an existing buffer (via *mtmsg.buffer()*) or listener (via\n  *mtmsg.listener()*) cannot be created because the object cannot be found by\n  the given id or name. \n  \n  All mtmsg objects are subject to garbage collection and therefore a reference to a \n  created object is needed to keep it alive, i.e. if you want to pass an object\n  to another thread via name or id, a reference to this object should be kept in the\n  thread that created the object, until the receiving thread signaled that a reference\n  to the object has been constructed in the receiving thread, example:\n  \n  ```lua\n  local llthreads = require(\"llthreads2.ex\")\n  local mtmsg     = require(\"mtmsg\")\n  local threadIn  = mtmsg.newbuffer()\n  local lst       = mtmsg.newlistener()\n  local threadOut = lst:newbuffer()\n  local thread    = llthreads.new(function(inId, outId)\n                                      local mtmsg     = require(\"mtmsg\")\n                                      local threadIn  = mtmsg.buffer(inId)\n                                      local threadOut = mtmsg.buffer(outId)\n                                      threadOut:addmsg(\"started\")\n                                      assert(threadIn:nextmsg() == \"exit\")\n                                      threadOut:addmsg(\"finished\")\n                                  end,\n                                  threadIn:id(),\n                                  threadOut:id())\n  -- threadOut = nil -- not now!\n  -- collectgarbage()\n  thread:start()\n  assert(lst:nextmsg() == \"started\")\n  threadOut = nil -- now it's safe\n  collectgarbage()\n  threadIn:addmsg(\"exit\")\n  assert(lst:nextmsg() == \"finished\")\n  assert(thread:join())\n  collectgarbage()\n  local _, err = pcall(function() lst:nextmsg() end)\n  assert(err:match(mtmsg.error.no_buffers))\n  ```\n\nEnd of document.\n\n\u003c!-- ---------------------------------------------------------------------------------------- --\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosch%2Flua-mtmsg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fosch%2Flua-mtmsg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosch%2Flua-mtmsg/lists"}