Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Import to git

  • Loading branch information...
commit 812a3639d76dee090776c8eb99e291f3fc3cc9bb 0 parents
@drahosp drahosp authored
Showing with 4,966 additions and 0 deletions.
  1. +23 −0 CMakeLists.txt
  2. +19 −0 LICENSE
  3. +2 −0  Makefile
  4. +17 −0 NEWS
  5. +35 −0 README
  6. +130 −0 dist.cmake
  7. +16 −0 dist.info
  8. BIN  doc/concurrentlua.png
  9. +105 −0 doc/index.html
  10. +625 −0 doc/introduction.html
  11. +89 −0 doc/license.html
  12. +314 −0 doc/reference.html
  13. +71 −0 doc/stylesheet.css
  14. +10 −0 samples/example1.lua
  15. +37 −0 samples/example2.lua
  16. +38 −0 samples/example3.lua
  17. +22 −0 samples/example4a.lua
  18. +25 −0 samples/example4b.lua
  19. +33 −0 samples/example5a.lua
  20. +37 −0 samples/example5b.lua
  21. +5 −0 src/Makefile
  22. +42 −0 src/cldaemon/Makefile
  23. +80 −0 src/cldaemon/cldaemon.c
  24. +2 −0  src/cldaemon/cldaemon.def
  25. +24 −0 src/clpmd/Makefile
  26. +61 −0 src/clpmd/clpmd
  27. +42 −0 src/cltime/Makefile
  28. +88 −0 src/cltime/cltime.c
  29. +2 −0  src/cltime/cltime.def
  30. +36 −0 src/concurrent/Makefile
  31. +34 −0 src/concurrent/distributed/Makefile
  32. +19 −0 src/concurrent/distributed/cookie.lua
  33. +15 −0 src/concurrent/distributed/init.lua
  34. +149 −0 src/concurrent/distributed/link.lua
  35. +73 −0 src/concurrent/distributed/message.lua
  36. +118 −0 src/concurrent/distributed/monitor.lua
  37. +299 −0 src/concurrent/distributed/network.lua
  38. +72 −0 src/concurrent/distributed/node.lua
  39. +79 −0 src/concurrent/distributed/process.lua
  40. +310 −0 src/concurrent/distributed/register.lua
  41. +53 −0 src/concurrent/distributed/scheduler.lua
  42. +17 −0 src/concurrent/init.lua
  43. +104 −0 src/concurrent/link.lua
  44. +36 −0 src/concurrent/message.lua
  45. +75 −0 src/concurrent/monitor.lua
  46. +19 −0 src/concurrent/option.lua
  47. +109 −0 src/concurrent/process.lua
  48. +61 −0 src/concurrent/register.lua
  49. +69 −0 src/concurrent/root.lua
  50. +123 −0 src/concurrent/scheduler.lua
  51. +9 −0 test/concurrent.sh
  52. +27 −0 test/concurrent/link1.lua
  53. +40 −0 test/concurrent/link2.lua
  54. +24 −0 test/concurrent/message1.lua
  55. +27 −0 test/concurrent/monitor1.lua
  56. +41 −0 test/concurrent/monitor2.lua
  57. +28 −0 test/concurrent/process1.lua
  58. +36 −0 test/concurrent/process2.lua
  59. +43 −0 test/concurrent/register1.lua
  60. +57 −0 test/concurrent/register2.lua
  61. +30 −0 test/concurrent/trapexit1.lua
  62. +45 −0 test/concurrent/trapexit2.lua
  63. +20 −0 test/distributed/cookie1a.lua
  64. +21 −0 test/distributed/cookie1b.lua
  65. +21 −0 test/distributed/cookie2a.lua
  66. +21 −0 test/distributed/cookie2b.lua
  67. +20 −0 test/distributed/link1a.lua
  68. +20 −0 test/distributed/link1b.lua
  69. +17 −0 test/distributed/link2a.lua
  70. +20 −0 test/distributed/link2b.lua
  71. +20 −0 test/distributed/link2c.lua
  72. +20 −0 test/distributed/message1a.lua
  73. +14 −0 test/distributed/message1b.lua
  74. +19 −0 test/distributed/monitor1a.lua
  75. +21 −0 test/distributed/monitor1b.lua
  76. +16 −0 test/distributed/monitor2a.lua
  77. +22 −0 test/distributed/monitor2b.lua
  78. +22 −0 test/distributed/monitor2c.lua
  79. +22 −0 test/distributed/node1a.lua
  80. +21 −0 test/distributed/node1b.lua
  81. +19 −0 test/distributed/process1a.lua
  82. +20 −0 test/distributed/process1b.lua
  83. +27 −0 test/distributed/process2a.lua
  84. +9 −0 test/distributed/process2b.lua
  85. +26 −0 test/distributed/register1a.lua
  86. +21 −0 test/distributed/register1b.lua
  87. +23 −0 test/distributed/register2a.lua
  88. +22 −0 test/distributed/register2b.lua
  89. +22 −0 test/distributed/register2c.lua
  90. +20 −0 test/distributed/trapexit1a.lua
  91. +23 −0 test/distributed/trapexit1b.lua
  92. +17 −0 test/distributed/trapexit2a.lua
  93. +25 −0 test/distributed/trapexit2b.lua
  94. +24 −0 test/distributed/trapexit2c.lua
  95. +8 −0 test/distributed2a.sh
  96. +9 −0 test/distributed2b.sh
  97. +7 −0 test/distributed3a.sh
  98. +8 −0 test/distributed3b.sh
  99. +8 −0 test/distributed3c.sh
23 CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (C) 2007-2009 LuaDist.
+# Created by Peter Drahoš
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own license.
+
+PROJECT(concrrentlua C)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+INCLUDE(dist.cmake)
+
+# Build
+ADD_LUA_MODULE(cldaemon src/cldaemon/cldaemon.c ${CMAKE_CURRENT_SOURCE_DIR}/src/cldaemon/cldaemon.def)
+ADD_LUA_MODULE(cltime src/cltime/cltime.c ${CMAKE_CURRENT_SOURCE_DIR}/src/cldaemon/cldaemon.def)
+
+# Install all files and documentation
+INSTALL (TARGETS cldaemon cltime DESTINATION ${INSTALL_CMOD})
+INSTALL (PROGRAMS src/clpmd/clpmd DESTINATION ${INSTALL_BIN})
+INSTALL (DIRECTORY src/concurrent DESTINATION ${INSTALL_LMOD} PATTERN "Makefile" EXCLUDE)
+INSTALL (DIRECTORY samples/ DESTINATION ${INSTALL_EXAMPLE})
+INSTALL (DIRECTORY test/ DESTINATION ${INSTALL_TEST})
+INSTALL (DIRECTORY doc/ DESTINATION ${INSTALL_DOC})
+INSTALL (FILES README LICENSE NEWS DESTINATION ${INSTALL_DATA})
+
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2007-2009 Eleftherios Chatzimparmpas
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
2  Makefile
@@ -0,0 +1,2 @@
+all install uninstall clean:
+ cd src && $(MAKE) $@
17 NEWS
@@ -0,0 +1,17 @@
+Version 1.0.3 - 23 May 2009
+---------------------------
+- Bug fix; time calculation for the root process while sleeping was wrong.
+- Minor enhancements to the serializer in the handling of tables.
+
+Version 1.0.2 - 21 June 2008
+----------------------------
+- Minor enhancement to the serializer in the handling of strings.
+
+Version 1.0.1 - 24 March 2008
+-----------------------------
+- Bug fix; cltime.time() overflow in 32-bit architectures caused problems to
+ the scheduler.
+
+Version 1.0 - 31 December 2007
+------------------------------
+- Initial release.
35 README
@@ -0,0 +1,35 @@
+ConcurrentLua 1.0.3
+===================
+
+Requirements
+------------
+* The Lua Socket module (http://luasocket.luaforge.net)
+* The Lua Copas module (http://www.keplerproject.org/copas/)
+
+
+Installation
+------------
+The system can be compiled and installed using the make files:
+
+ make all
+ make install
+
+
+Usage
+-----
+See the doc/introduction.html and doc/reference.html files.
+
+
+Website
+-------
+http://concurrentlua.luaforge.net
+
+
+Author
+------
+Lefteris Chatzimparmpas <lefcha@hellug.gr>
+
+
+License
+-------
+See the LICENSE file.
130 dist.cmake
@@ -0,0 +1,130 @@
+# LuaDist CMake utility library.
+# Provides variables and utility functions common to LuaDist CMake builds.
+#
+# Copyright (C) 2007-2010 LuaDist.
+# by David Manura, Peter Drahos
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own license.
+
+# Few convinence settings
+SET (CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+SET (CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_MODULE_PATH})
+
+# Where to install module parts:
+set(INSTALL_BIN bin CACHE PATH "Where to install binaries to.")
+set(INSTALL_LIB lib CACHE PATH "Where to install libraries to.")
+set(INSTALL_INC include CACHE PATH "Where to install headers to.")
+set(INSTALL_ETC etc CACHE PATH "Where to store configuration files")
+set(INSTALL_LMOD share/lua/lmod CACHE PATH "Directory to install Lua modules.")
+set(INSTALL_CMOD share/lua/cmod CACHE PATH "Directory to install Lua binary modules.")
+set(INSTALL_DATA share/${PROJECT_NAME} CACHE PATH "Directory the package can store documentation, tests or other data in.")
+set(INSTALL_DOC ${INSTALL_DATA}/doc CACHE PATH "Recommended directory to install documentation into.")
+set(INSTALL_EXAMPLE ${INSTALL_DATA}/example CACHE PATH "Recommended directory to install examples into.")
+set(INSTALL_TEST ${INSTALL_DATA}/test CACHE PATH "Recommended directory to install tests into.")
+set(INSTALL_FOO ${INSTALL_DATA}/etc CACHE PATH "Where to install additional files")
+
+
+# In MSVC, prevent warnings that can occur when using standard libraries.
+if(MSVC)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif(MSVC)
+
+# Adds Lua shared library module target `_target`.
+# Additional sources to build the module are listed after `_target`.
+macro(add_lua_module _target)
+ find_package(Lua51 REQUIRED)
+ include_directories(${LUA_INCLUDE_DIR}) #2DO: somehow apply only to _target?
+
+ add_library(${_target} MODULE ${ARGN})
+ set_target_properties(${_target} PROPERTIES PREFIX "")
+ target_link_libraries(${_target} ${LUA_LIBRARY})
+
+ IF(WIN32)
+ set_target_properties(${_target} PROPERTIES LINK_FLAGS "-Wl,--enable-auto-import")
+ ENDIF()
+
+endmacro(add_lua_module)
+
+# Runs Lua script `_testfile` under CTest tester.
+# Optional argument `_testcurrentdir` is current working directory to run test under
+# (defaults to ${CMAKE_CURRENT_BINARY_DIR}).
+# Both paths, if relative, are relative to ${CMAKE_CURRENT_SOURCE_DIR}.
+# Under LuaDist, set test=true in config.lua to enable testing.
+macro(add_lua_test _testfile)
+ include(CTest)
+ if(BUILD_TESTING)
+ find_program(LUA NAMES lua lua.bat)
+ get_filename_component(TESTFILEABS ${_testfile} ABSOLUTE)
+ get_filename_component(TESTFILENAME ${_testfile} NAME)
+ get_filename_component(TESTFILEBASE ${_testfile} NAME_WE)
+
+ # Write wrapper script.
+ set(TESTWRAPPER ${CMAKE_CURRENT_BINARY_DIR}/${TESTFILENAME})
+ set(TESTWRAPPERSOURCE
+"package.path = '${CMAKE_CURRENT_BINARY_DIR}/?.lua\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;' .. package.path
+package.cpath = '${CMAKE_CURRENT_BINARY_DIR}/?.so\;${CMAKE_CURRENT_BINARY_DIR}/?.dll\;' .. package.cpath
+return dofile '${TESTFILEABS}'
+" )
+ if(${ARGC} GREATER 1)
+ set(_testcurrentdir ${ARGV1})
+ get_filename_component(TESTCURRENTDIRABS ${_testcurrentdir} ABSOLUTE)
+ set(TESTWRAPPERSOURCE
+"require 'lfs'
+lfs.chdir('${TESTCURRENTDIRABS}')
+${TESTWRAPPERSOURCE}")
+ endif()
+ FILE(WRITE ${TESTWRAPPER} ${TESTWRAPPERSOURCE})
+
+ add_test(${TESTFILEBASE} ${LUA} ${TESTWRAPPER})
+ endif(BUILD_TESTING)
+
+ # see also http://gdcm.svn.sourceforge.net/viewvc/gdcm/Sandbox/CMakeModules/UsePythonTest.cmake
+endmacro(add_lua_test)
+
+# Converts Lua source file `_source` to binary string embedded in C source
+# file `_target`. Optionally compiles Lua source to byte code (not available
+# under LuaJIT2, which doesn't have a bytecode loader). Additionally, Lua
+# versions of bin2c [1] and luac [2] may be passed respectively as additional
+# arguments.
+#
+# [1] http://lua-users.org/wiki/BinToCee
+# [2] http://lua-users.org/wiki/LuaCompilerInLua
+function(add_lua_bin2c _target _source)
+ find_program(LUA NAMES lua lua.bat)
+ execute_process(COMMAND ${LUA} -e "string.dump(function()end)" RESULT_VARIABLE _LUA_DUMP_RESULT ERROR_QUIET)
+ if (NOT ${_LUA_DUMP_RESULT})
+ SET(HAVE_LUA_DUMP true)
+ endif()
+ message("-- string.dump=${HAVE_LUA_DUMP}")
+
+ if (ARGV2)
+ get_filename_component(BIN2C ${ARGV2} ABSOLUTE)
+ set(BIN2C ${LUA} ${BIN2C})
+ else()
+ find_program(BIN2C NAMES bin2c bin2c.bat)
+ endif()
+ if (HAVE_LUA_DUMP)
+ if (ARGV3)
+ get_filename_component(LUAC ${ARGV3} ABSOLUTE)
+ set(LUAC ${LUA} ${LUAC})
+ else()
+ find_program(LUAC NAMES luac luac.bat)
+ endif()
+ endif (HAVE_LUA_DUMP)
+ message("-- bin2c=${BIN2C}")
+ message("-- luac=${LUAC}")
+
+ get_filename_component(SOURCEABS ${_source} ABSOLUTE)
+ if (HAVE_LUA_DUMP)
+ get_filename_component(SOURCEBASE ${_source} NAME_WE)
+ add_custom_command(
+ OUTPUT ${_target} DEPENDS ${_source}
+ COMMAND ${LUAC} -o ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo ${SOURCEABS}
+ COMMAND ${BIN2C} ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo ">${_target}" )
+ else()
+ add_custom_command(
+ OUTPUT ${_target} DEPENDS ${SOURCEABS}
+ COMMAND ${BIN2C} ${_source} ">${_target}" )
+ endif()
+endfunction(add_lua_bin2c)
16 dist.info
@@ -0,0 +1,16 @@
+--- This file is part of LuaDist project
+
+name = "concurrentlua"
+version = "1.0.3"
+
+desc = "Concurrency Oriented Programming in Lua"
+author = "Lefteris Chatzimparmpas"
+license = "MIT"
+url = "http://concurrentlua.luaforge.net/"
+maintainer = "Peter Drahoš"
+
+depends = {
+ "lua ~> 5.1",
+ "luasocket >= 2.0",
+ "copas >= 1.1"
+}
BIN  doc/concurrentlua.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
105 doc/index.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></meta>
+<meta name="keywords" content="concurrent lua"></meta>
+<meta name="description" content="ConcurrentLua. Concurrency Oriented
+ Programming in Lua."></meta>
+<title>ConcurrentLua</title>
+<link href="stylesheet.css" rel="stylesheet" type="text/css"></link>
+</head>
+
+<body>
+
+<div class="center">
+ <a class="link" href="http://luaforge.net/projects/concurrentlua/">
+ <img src="concurrentlua.png" alt="ConcurrentLua logo"></img>
+ </a>
+ <h1>ConcurrentLua</h1>
+ <p>Concurrency Oriented Programming in Lua</p>
+ <div class="navigation">
+ <a class="link" href="index.html">home</a> &middot;
+ <a class="link" href="index.html#download">download</a> &middot;
+ <a class="link" href="index.html#installation">installation</a> &middot;
+ <a class="link" href="introduction.html">introduction</a> &middot;
+ <a class="link" href="reference.html">reference</a>
+ </div>
+</div>
+
+<div class="box">
+
+ <h3><a>Overview</a></h3>
+
+ <p>ConcurrentLua is a system that implements Erlang-style concurrency for the
+ <a class="link" href="http://www.lua.org/">Lua programming language</a>. It is
+ a system that brings an alternative to what scripting languages offer for
+ concurrent and distributed programming.</p>
+
+ <p>Erlang is regarded as the reference language for concurrent and distributed
+ programming using the message-passing model. Erlang was designed with
+ concurrency oriented programming in mind and has built-in facilities to
+ support this model.</p>
+
+ <p>ConcurrentLua is based on the Lua model for concurrency, namely coroutines,
+ and extends this model by providing message-passing primitives. Distributed
+ programming is supported transparently with the same message-passing
+ primitives.</p>
+
+ <p>ConcurrentLua is implemented as a collection of Lua modules that can be
+ loaded by any Lua program. Most of the code is written in Lua itself, with
+ minor parts written in C.</p>
+
+ <p>The system was originally designed and implemented as part of my MSc Thesis
+ at the Royal Institute of Technology (KTH). At this point it can be considered
+ a working prototype, nevertheless it is a complete solution and it was
+ implemented so as to be further extended in the future, if found useful by the
+ community.</p>
+
+ <h3><a id="download">Download</a></h3>
+
+ <p>The current version is 1.0.3, released on 23 May 2009.</p>
+
+ <p>ConcurrentLua can be downloaded from its <a class="link"
+ href="http://luaforge.net/projects/concurrentlua/">LuaForge project
+ page</a>.</p>
+
+ <h3><a id="installation">Installation</a></h3>
+
+ <p>ConcurrentLua depends only on the <a class="link"
+ href="http://luasocket.luaforge.net/">LuaSocket</a> and <a class="link"
+ href="http://www.keplerproject.org/copas/">Copas</a> modules.</p>
+
+ <p>ConcurrentLua uses the new package system for Lua 5.1. </p>
+
+ <p>ConcurrentLua is supplied with a Makefile that can be used to build and
+ install it.</p>
+
+ <h3><a>Contact</a></h3>
+
+ <p>Lefteris Chatzimparmpas <a class="link"
+ href="mailto:lefcha@hellug.gr">&lt;lefcha@hellug.gr&gt;</a></p>
+
+ <h3><a>License</a></h3>
+
+ <p>This program is released under the same <a class="link" href=
+ "license.html">terms and conditions</a> as the Lua language, the MIT/X11
+ license.</p>
+
+</div>
+
+<div class="center">
+ <div class="navigation">
+ <a class="link" href="index.html">home</a> &middot;
+ <a class="link" href="index.html#download">download</a> &middot;
+ <a class="link" href="index.html#installation">installation</a> &middot;
+ <a class="link" href="introduction.html">introduction</a> &middot;
+ <a class="link" href="reference.html">reference</a>
+ </div>
+</div>
+
+</body>
+
+</html>
+
625 doc/introduction.html
@@ -0,0 +1,625 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></meta>
+<meta name="keywords" content="concurrent lua"></meta>
+<meta name="description" content="ConcurrentLua. Concurrency Oriented
+ Programming in Lua."></meta>
+<title>ConcurrentLua - Introduction</title>
+<link href="stylesheet.css" rel="stylesheet" type="text/css"></link>
+</head>
+
+<body>
+
+<div class="center">
+ <a class="link" href="http://luaforge.net/projects/concurrentlua/">
+ <img src="concurrentlua.png" alt="ConcurrentLua logo"></img>
+ </a>
+ <h1>ConcurrentLua</h1>
+ <p>Concurrency Oriented Programming in Lua</p>
+ <div class="navigation">
+ <a class="link" href="index.html">home</a> &middot;
+ <a class="link" href="index.html#download">download</a> &middot;
+ <a class="link" href="index.html#installation">installation</a> &middot;
+ <a class="link" href="introduction.html">introduction</a> &middot;
+ <a class="link" href="reference.html">reference</a>
+ </div>
+</div>
+
+<div class="box">
+
+ <h3>Introduction</h3>
+
+ <p>ConcurrentLua is an implementation of the share-nothing asynchronous
+ message-passing model that is employed in the Erlang programming language. It
+ is an adaptation of the Erlang concurrency primitives in such a way as to
+ integrate strongly to Lua.</p>
+
+ <p>One of the core elements of ConcurrentLua is the <em>process</em>. A
+ process is a light-weight VM thread, that plays the same role as do processes
+ in an operating system; they don't share memory but instead they communicate
+ through some kind of interprocess communication. These processes can be
+ created and destroyed on demand, and a simple round-robin scheduler passes
+ control to them.</p>
+
+ <p>Each process is associated with a <em>mailbox</em>, a message queue for the
+ temporary storage of messages that were sent to the process. A process can
+ check its mailbox for new messages at any time, and if there are any, they can
+ be read in the order of arrival.</p>
+
+ <p>Each process is identified by a unique numeric <em>process identifier</em>,
+ or else <em>PID</em>. In addition, aliases or process names can be used
+ instead of PIDs, in order to refer to processes. These aliases and their
+ references are stored in a central repository, the <em>registry</em>.
+ Processes can edit the registry, by adding or deleting entries.</p>
+
+ <p>Error handling mechanisms are also provided in the form of
+ <em>monitors</em> and <em>links</em>. With monitors processes can monitor the
+ other processes, and get notified if the monitored processes terminate
+ abnormally. With links processes are bound together, and when one of them
+ terminates abnormally the other one is signalled and terminates, too.</p>
+
+ <p>This system also supports distributed programming and all the properties
+ that have been described map naturally onto a distributed system. Distributed
+ processes communicate with the same primitives as local processes.</p>
+
+ <p>Distribution is based on a component that is called the <em>node</em>. A
+ node represents a system runtime inside of which processes are executing.
+ Nodes can be connected to each other and communicate, thus forming a
+ <em>virtual network</em>. Distributed processes use this network in order to
+ exchange messages.</p>
+
+ <p>Each node has a name associated with it. In order for other nodes to
+ connect to each other by using only this name, a <em>port mapper daemon</em>
+ acts a nameserver. The port mapper daemon has details about the nodes running
+ under the network host that the daemon itself is bound to.</p>
+
+ <p>As processes can be created locally, it is also possible to request the
+ creation of processes on remote nodes. A remote process can then be handled as
+ if it was a local process.</p>
+
+ <p>If the nodes that form the virtual network are fully connected (every node
+ is connected bidirectionally to each other), global aliases can be used for
+ the processes. The nodes negotiate and maintain a <em>virtual global
+ registry</em> and also keep updated local copies of the registry.</p>
+
+ <p>Monitors and links for distributed processes are supported with the same
+ semantics as for local processes. Nodes take care of the task of transparently
+ handling errors between distributed processes. In addition, it is possible for
+ processes to monitor nodes as a whole.</p>
+
+ <p>Nodes are required to authenticate before they can communicate. An
+ authenticated node can then be part of the virtual network that the nodes
+ form. A simple security mechanism takes care of this task.</p>
+
+ <h3>Implementation</h3>
+
+ <p>The implementation of ConcurrentLua is based on the Lua component system.
+ The system is organized as a collection of Lua modules and submodules. The
+ main modules are two, and provide the concurrent and distributed programming
+ functionality respectively. One could load only the concurrency module and
+ also for each module there is the option of not loading some of the submodules
+ if the functionality they provide is not needed. A stand-alone port mapper
+ daemon utility is also included.</p>
+
+ <p>The processes in the system are implemented with Lua coroutines. A process
+ is actually a Lua coroutine that yields control when the process suspends its
+ execution and resumes control when the process continues its execution.</p>
+
+ <p>The scheduling of the processes is still based on the cooperative
+ multithreading model that Lua uses. Processes voluntarily suspend their
+ execution and thus other processes get the chance to run. Nevertheless, the
+ suspending and resuming of processes is partly hidden under a higher level
+ mechanism; a process suspends its execution when waiting for a message to
+ arrive and becomes ready to be resumed when new messages have arrived in its
+ mailbox. A simple round-robin scheduler resumes the processes.</p>
+
+ <p>Any type of Lua data, with the exception of memory references, can be sent
+ inside messages. Messages can be booleans, numbers, strings, tables or
+ functions, and any combination of them. Data are automatically serialized on
+ sent and deserialized on receive, and everything is passed by value.</p>
+
+ <p>Interprocess communication between nodes, and subsequently between
+ distributed processes, is based on an asynchronous socket handler. This
+ translates to networking model that uses non-blocking sockets and periodic
+ polling. This is the approach that is mostly used today by Lua libraries.
+ Non-blocking semantics should be also used for IO such as files, pipes,
+ etc.</p>
+
+ <h3>Usage</h3>
+
+ <p>Some examples will provide an introduction to the most essential properties
+ of the system, from process creation and message passing to distributed
+ programming and error handling.</p>
+
+ <h4>Creating processes</h4>
+
+ <p>Processes are created using the <code>spawn()</code> function. The
+ <code>spawn()</code> function takes at least one argument; the function that
+ contains the command set that the process will execute. Any additional
+ arguments are passed directly as arguments of the function.</p>
+
+ <p>The following example demonstrates the creation of a process. The process
+ just prints a message as many times as specified:</p>
+
+ <div class="verbatim"><pre>
+require 'concurrent'
+
+function hello_world(times)
+ for i = 1, times do print('hello world') end
+ print('done')
+end
+
+concurrent.spawn(hello_world, 3)
+
+concurrent.loop()</pre></div>
+
+ <p>The output would be:</p>
+
+ <div class="verbatim"><pre>
+hello world
+hello world
+hello world
+done</pre></div>
+
+ <p>First the system is loaded:</p>
+
+ <div class="verbatim"><pre>
+require 'concurrent'</pre></div>
+
+ <p>The function that the process will execute is defined next:</p>
+
+ <div class="verbatim"><pre>
+function hello_world(times)
+ for i = 1, times do print('hello world') end
+ print('done')
+end</pre></div>
+
+ <p>A new process is created:</p>
+
+ <div class="verbatim"><pre>
+concurrent.spawn(hello_world, 3)</pre></div>
+
+ <p>The system's infinite loop is called last:</p>
+
+ <div class="verbatim"><pre>
+concurrent.loop()</pre></div>
+
+ <h4>Exchanging messages</h4>
+
+ <p>Processes can exchange messages by using the <code>send()</code> and
+ <code>receive()</code> functions. Also, the <code>self()</code> function can
+ be used to get the PID of the calling process.</p>
+
+ <p>The following program implements two processes that exchange messages and
+ then terminate:</p>
+
+ <div class="verbatim"><pre>
+require 'concurrent'
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.body == 'finished' then
+ break
+ elseif msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+function ping(n, pid)
+ for i = 1, n do
+ concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'finished'
+ })
+ print('ping finished')
+end
+
+pid = concurrent.spawn(pong)
+concurrent.spawn(ping, 3, pid)
+
+concurrent.loop()</pre></div>
+
+ <p>The output would be:</p>
+
+ <div class="verbatim"><pre>
+pong received ping
+ping received pong
+pong received ping
+ping received pong
+pong received ping
+ping received pong
+pong finished
+ping finished</pre></div>
+
+ <p>After the <em>pong</em> process is created, the <em>ping</em> process is
+ supplied with the PID of the <em>pong</em> process:</p>
+
+ <div class="verbatim"><pre>
+pid = concurrent.spawn(pong)
+concurrent.spawn(ping, 3, pid)</pre></div>
+
+ <p>The <em>ping</em> process sends a message:</p>
+
+ <div class="verbatim"><pre>
+concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'ping'
+})</pre></div>
+
+ <p>The <em>pong</em> process waits for a message to arrive and saves it in a
+ variable when it does:</p>
+
+ <div class="verbatim"><pre>
+local msg = concurrent.receive()</pre></div>
+
+ <p>The <em>pong</em> process replies:</p>
+
+ <div class="verbatim"><pre>
+ concurrent.send(msg.from, { body = 'pong' })</pre></div>
+
+ <p>The <em>pong</em> process terminates after having received a notification
+ from the <em>ping</em> process.</p>
+
+ <h4>Registering process names</h4>
+
+ <p>Instead of using process PIDs for sending messages, process names can also
+ be used. The <code>register()</code> function can be used to create an alias
+ for a process in the registry:</p>
+
+ <div class="verbatim">
+ <pre>
+require 'concurrent'
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.body == 'finished' then
+ break
+ elseif msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+function ping(n)
+ for i = 1, n do
+ concurrent.send('pong', {
+ from = concurrent.self(),
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ concurrent.send('pong', {
+ from = concurrent.self(),
+ body = 'finished'
+ })
+ print('ping finished')
+end
+
+pid = concurrent.spawn(pong)
+concurrent.register('pong', pid)
+concurrent.spawn(ping, 3)
+
+concurrent.loop()</pre></div>
+
+ <p>The only change from the previous example is the destination that the
+ <em>ping</em> process sends messages to:</p>
+
+ <div class="verbatim"><pre>
+concurrent.send('pong', {
+ from = concurrent.self(),
+ body = 'ping'
+})</pre></div>
+
+ <p>And:</p>
+
+ <div class="verbatim"><pre>
+concurrent.send('pong', {
+ from = concurrent.self(),
+ body = 'finished'
+})</pre></div>
+
+ <p>And the <em>pong</em> process now registers its name:</p>
+
+ <div class="verbatim"><pre>
+concurrent.register('pong', pid)</pre></div>
+
+ <p>Therefore the <em>ping</em> process isn't supplied with the PID of the
+ <em>pong</em> process.</p>
+
+ <h4>Distributed message passing</h4>
+
+ <p>Processes in different nodes can still communicate with the same message
+ passing primitives. Remote processes are denoted by their PID or alias and the
+ node they are executing under. The previous example could be broken into two
+ programs, one for each process.</p>
+
+ <p>The code for the <em>pong</em> process:</p>
+
+ <div class="verbatim"><pre>
+require 'concurrent'
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.body == 'finished' then
+ break
+ elseif msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+concurrent.init('pong@gaia')
+
+pid = concurrent.spawn(pong)
+
+concurrent.register('pong', pid)
+concurrent.loop()
+concurrent.shutdown()</pre></div>
+
+ <p>And the code for the <em>ping</em> process:</p>
+
+ <div class="verbatim"><pre>
+require 'concurrent'
+
+function ping(n)
+ for i = 1, n do
+ concurrent.send({ 'pong', 'pong@gaia' }, {
+ from = { concurrent.self(), concurrent.node() },
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ concurrent.send({ 'pong', 'pong@gaia' }, {
+ from = { concurrent.self(), concurrent.node() },
+ body = 'finished'
+ })
+ print('ping finished')
+end
+
+concurrent.spawn(ping, 3)
+
+concurrent.init('ping@selene')
+concurrent.loop()
+concurrent.shutdown()</pre></div>
+
+ <p>The output of the <em>pong</em> process would be:</p>
+
+ <div class="verbatim"><pre>
+pong received ping
+pong received ping
+pong received ping
+pong finished</pre></div>
+
+ <p>And the output of the <em>ping</em> process would be:</p>
+
+ <div class="verbatim"><pre>
+ping received pong
+ping received pong
+ping received pong
+ping finished</pre></div>
+
+ <p>In this example the runtime system is running in distributed mode. In order
+ for this to happen, first the port mapper daemon has to be started. This can
+ done by typing in a command line shell:</p>
+
+ <div class="verbatim"><pre>
+$ clpmd</pre></div>
+
+ <p>The code that initializes the node that the <em>pong</em> process is
+ running on:</p>
+
+ <div class="verbatim"><pre>
+concurrent.init('pong@gaia')</pre></div>
+
+ <p>And the code for the <em>ping</em> process:</p>
+
+ <div class="verbatim"><pre>
+concurrent.init('ping@selene')</pre></div>
+
+ <p>The previous two code snippets register to the port mapper daemon, the port
+ that each node is listening to. Both nodes unregister their port with:</p>
+
+ <div class="verbatim"><pre>
+concurrent.shutdown()</pre></div>
+
+ <p>The only other changes in this example are the destination that the
+ messages are sent to, along with the introduction of the <code>node()</code>
+ function that returns the name of the node that the calling process is running
+ on:</p>
+
+ <div class="verbatim"><pre>
+concurrent.send({ 'pong', 'pong@gaia' }, {
+ from = { concurrent.self(), concurrent.node() },
+ body = 'ping'
+})</pre></div>
+
+ <p>And later:</p>
+
+ <div class="verbatim"><pre>
+concurrent.send({ 'pong', 'pong@gaia' }, {
+ from = { concurrent.self(), concurrent.node() },
+ body = 'finished'
+})</pre></div>
+
+ <h4>Handling error</h4>
+
+ <p>One approach to handle errors in processes is the notion of linked
+ processes. Two processes are bound together and if one of them terminates
+ abnormally the other one terminates, too. The <code>link()</code> function can
+ be used to link processes:</p>
+
+ <div class="verbatim"><pre>
+require 'concurrent'
+
+function ping(n, pid)
+ concurrent.link(pid)
+ for i = 1, n do
+ concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ print('ping finished')
+ concurrent.exit('finished')
+end
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+pid = concurrent.spawn(pong)
+concurrent.spawn(ping, 3, pid)
+
+concurrent.loop()</pre></div>
+
+ <p>The output would be:</p>
+
+ <div class="verbatim"><pre>
+pong received ping
+ping received pong
+pong received ping
+ping received pong
+pong received ping
+ping received pong
+pong finished</pre></div>
+
+ <p>The <em>pong</em> process never reaches its last line, because it
+ terminates when the <em>ping</em> process exits.</p>
+
+ <p>The code that links the processes is:</p>
+
+ <div class="verbatim"><pre>
+concurrent.link(pid)</pre></div>
+
+ <p>The <code>exit()</code> function is used to make the calling function quit
+ abnormally:</p>
+
+ <div class="verbatim"><pre>
+concurrent.exit('finished')</pre></div>
+
+ <p>It is also possible to trap the exit signal of the terminating process. In
+ this case a special message is received:</p>
+
+ <div class="verbatim"><pre>
+require 'concurrent'
+
+concurrent.setoption('trapexit', true)
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.signal == 'EXIT' then
+ break
+ elseif msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+function ping(n, pid)
+ concurrent.link(pid)
+ for i = 1, n do
+ concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ print('ping finished')
+ concurrent.exit('finished')
+end
+
+pid = concurrent.spawn(pong)
+concurrent.spawn(ping, 3, pid)
+
+concurrent.loop()</pre></div>
+
+ <p>The output would be:</p>
+
+ <div class="verbatim"><pre>
+pong received ping
+ping received pong
+pong received ping
+ping received pong
+pong received ping
+ping received pong
+pong finished
+ping finished</pre></div>
+
+ <p>There is an option related to process linking that can be set with the
+ <code>setoption()</code> function, specifically the <code>trapexit</code>
+ option:</p>
+
+ <div class="verbatim"><pre>
+concurrent.setoption('trapexit', true)</pre></div>
+
+ <p>Then the <em>pong</em> process receives a special exit message:</p>
+
+ <div class="verbatim"><pre>
+if msg.signal == 'EXIT' then
+ break
+</pre></div>
+
+ <p>Alternatively, monitors that are based on notification messages, can be
+ also used for error handling.</p>
+
+</div>
+
+<div class="center">
+ <div class="navigation">
+ <a class="link" href="index.html">home</a> &middot;
+ <a class="link" href="index.html#download">download</a> &middot;
+ <a class="link" href="index.html#installation">installation</a> &middot;
+ <a class="link" href="introduction.html">introduction</a> &middot;
+ <a class="link" href="reference.html">reference</a>
+ </div>
+</div>
+
+</body>
+
+</html>
+
89 doc/license.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></meta>
+<meta name="keywords" content="concurrent lua"></meta>
+<meta name="description" content="ConcurrentLua. Concurrency Oriented
+ Programming in Lua."></meta>
+<title>ConcurrentLua - License</title>
+<link href="stylesheet.css" rel="stylesheet" type="text/css"></link>
+</head>
+
+<body>
+
+<div class="center">
+ <a class="link" href="http://luaforge.net/projects/concurrentlua/">
+ <img src="concurrentlua.png" alt="ConcurrentLua logo"></img>
+ </a>
+ <h1>ConcurrentLua</h1>
+ <p>Concurrency Oriented Programming in Lua</p>
+ <div class="navigation">
+ <a class="link" href="index.html">home</a> &middot;
+ <a class="link" href="index.html#download">download</a> &middot;
+ <a class="link" href="index.html#installation">installation</a> &middot;
+ <a class="link" href="introduction.html">introduction</a> &middot;
+ <a class="link" href="reference.html">reference</a>
+ </div>
+</div>
+
+<div class="box">
+
+ <h3><a>License</a></h3>
+
+ <p>ConcurrentLua is free software: it can be used for both academic and
+ commercial purposes at absolutely no cost. There are no royalties or GNU-like
+ "copyleft" restrictions. ConcurrentLua qualifies as Open Source software.
+ Its licenses are compatible with GPL. ConcurrentLua is not in the public
+ domain and Eleftherios Chatzimparmpas keeps its copyright. The legal details
+ are below.</p>
+
+ <p>The spirit of the license is that you are free to use ConcurrentLua for
+ any purpose at no cost without having to ask me. The only requirement is that
+ if you do use ConcurrentLua, then you should give me credit by including the
+ appropriate copyright notice somewhere in your product or its
+ documentation.</p>
+
+ <p>The ConcurrentLua library is entirely designed and implemented by
+ Eleftherios Chatzimparmpas. The implementation is not derived from licensed
+ software.</p>
+
+ <hr></hr>
+
+ <p>Copyright &copy; 2007-2009 Eleftherios Chatzimparmpas</p>
+
+ <p>Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"), to
+ deal in the Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:</p>
+
+ <p>The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.</p>
+
+ <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.</p>
+
+</div>
+
+<div class="center">
+ <div class="navigation">
+ <a class="link" href="index.html">home</a> &middot;
+ <a class="link" href="index.html#download">download</a> &middot;
+ <a class="link" href="index.html#installation">installation</a> &middot;
+ <a class="link" href="introduction.html">introduction</a> &middot;
+ <a class="link" href="reference.html">reference</a>
+ </div>
+</div>
+
+</body>
+
+</html>
+
314 doc/reference.html
@@ -0,0 +1,314 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></meta>
+<meta name="keywords" content="concurrent lua"></meta>
+<meta name="description" content="ConcurrentLua. Concurrency Oriented
+ Programming in Lua."></meta>
+<title>ConcurrentLua - Reference</title>
+<link href="stylesheet.css" rel="stylesheet" type="text/css"></link>
+</head>
+
+<body>
+
+<div class="center">
+ <a class="link" href="http://luaforge.net/projects/concurrentlua/">
+ <img src="concurrentlua.png" alt="ConcurrentLua logo"></img>
+ </a>
+ <h1>ConcurrentLua</h1>
+ <p>Concurrency Oriented Programming in Lua</p>
+ <div class="navigation">
+ <a class="link" href="index.html">home</a> &middot;
+ <a class="link" href="index.html#download">download</a> &middot;
+ <a class="link" href="index.html#installation">installation</a> &middot;
+ <a class="link" href="introduction.html">introduction</a> &middot;
+ <a class="link" href="reference.html">reference</a>
+ </div>
+</div>
+
+<div class="box">
+
+ <h3>Reference</h3>
+
+ <h4>Processes</h4>
+
+ <p><code>spawn(body, ...)</code></p>
+
+ <div class="description"><p>Creates a process which will execute the body
+ function. Any extra arguments can be passed to the executing function. The PID
+ of the new process is returned. In case of error <code>nil</code> and an error
+ message are returned.</p></div>
+
+ <p><code>spawn(node, body, ...)</code></p>
+
+ <div class="description"><p>Creates a process in a remote node which is a
+ string in the format <code>'nodename@hostname'</code> and the new process will
+ execute the body function. The PID of the new process is returned. In case of
+ error <code>nil</code> and an error message are returned.</p></div>
+
+ <p><code>self()</code></p>
+
+ <div class="description"><p>Returns the PID of the calling process.</p></div>
+
+ <p><code>isalive(process)</code></p>
+
+ <div class="description"><p>Checks if the process, which can be specified by
+ PID or by its registered string name, is alive. Returns <code>true</code> if
+ the process is alive, and <code>false</code> otherwise.</p></div>
+
+ <p><code>exit(reason)</code></p>
+
+ <div class="description"><p>Exits abnormally the calling process with the
+ specified <code>reason</code> string as a cause of exit.</p></div>
+
+ <h4>Messages</h4>
+
+ <p><code>receive([timeout])</code></p>
+
+ <div class="description"><p>Receives the next message in the mailbox of the
+ calling process. If the mailbox is empty it waits indefinitely for a message
+ to arrive, unless a <code>timeout</code> number in milliseconds is specified.
+ A message of any type, that depends on what was sent, is returned.</p></div>
+
+ <p><code>send(process, message)</code></p>
+
+ <div class="description"><p>Sends to the destination <code>process</code> a
+ <code>message</code> which can be one of: boolean, number, string, table,
+ function. Returns <code>true</code> if the message was send successfully, and
+ <code>false</code> if not.</p></div>
+
+ <h4>Scheduling</h4>
+
+ <p><code>sleep(time)</code></p>
+
+ <div class="description"><p>Suspends implicitly the calling process for the
+ specified <code>time</code>, the number of milliseconds.</p></div>
+
+ <p><code>loop([timeout])</code></p>
+
+ <div class="description"><p>Calls the system's infinite loop which executes
+ the process scheduler until all the processes have terminated, or unless the
+ specified <code>timeout</code>, the number of milliseconds, has
+ expired.</p></div>
+
+ <p><code>interrupt()</code></p>
+
+ <div class="description"><p>Interrupts the infinite loop of the process
+ scheduler.</p></div>
+
+ <p><code>step([timeout])</code></p>
+
+ <div class="description"><p>Executes one step of the process scheduler unless
+ the specified <code>timeout</code>, the number of milliseconds, has
+ expired.</p></div>
+
+ <p><code>tick()</code></p>
+
+ <div class="description"><p>Forwards the system's clock by one tick.</p></div>
+
+ <h4>Options</h4>
+
+ <p><code>setoption(key, value)</code></p>
+
+ <div class="description"><p>Sets the <code>key</code> string option to the
+ specified <code>value</code>, the type of which depends on the
+ option.</p></div>
+
+ <p><code>getoption(key)</code></p>
+
+ <div class="description"><p>Returns the value of the <code>key</code> string
+ option.</p></div>
+
+ <h4>Node</h4>
+
+ <p><code>init(node)</code></p>
+
+ <div class="description">
+
+ <p>Makes the runtime system a distributed node. The
+ first argument is the name string of the <code>node</code>, which can be
+ either in <code>'nodename'</code> or <code>'nodename@hostname'</code>
+ format.</p>
+
+ <p>If the <code>'shortnames'</code> option is set to <code>true</code>, then
+ short names are used instead of fully qualified domain names. If the
+ <code>'connectall'</code> option is set to <code>false</code>, then a fully
+ connected virtual network between the nodes will not be maintained.</p>
+
+ </div>
+
+ <p><code>shutdown()</code></p>
+
+ <div class="description"><p>Makes the runtime system stop being a distributed
+ node.</p></div>
+
+ <p><code>node()</code></p>
+
+ <div class="description"><p>Returns the name of the node the calling process
+ is running on.</p></div>
+
+ <p><code>nodes()</code></p>
+
+ <div class="description"><p>Returns a table with the nodes that the node the
+ calling process is running on is connected to.</p></div>
+
+ <p><code>isnodealive()</code></p>
+
+ <div class="description"><p>Returns <code>true</code> if the local node has
+ been initialized, and <code>false</code> otherwise.</p></div>
+
+ <p><code>monitornode(node)</code></p>
+
+ <div class="description"><p>The calling process starts monitoring the
+ specified <code>node</code>, which is a string of the format
+ <code>'nodename@hostname'</code>.</p></div>
+
+ <p><code>demonitornode(node)</code></p>
+
+ <div class="description"><p>The calling process stops monitoring the specified
+ <code>node</code>, which is a string of the format
+ <code>'nodename@hostname'</code>.</p></div>
+
+ <h4>Security</h4>
+
+ <p><code>setcookie(secret)</code></p>
+
+ <div class="description"><p>Sets the pre-shared <code>secret</code> key, a
+ string, also known as the <em>magic cookie</em>, that will be used for node
+ authentication.</p></div>
+
+ <p><code>getcookie()</code></p>
+
+ <div class="description"><p>Returns the pre-shared secret key, also known as
+ the <em>magic cookie</em>, that is being used for node
+ authentication.</p></div>
+
+ <h4>Registering</h4>
+
+ <p><code>register(name, pid)</code></p>
+
+ <div class="description"><p>Registers the <code>name</code> string for the
+ given process <code>pid</code>.</p></div>
+
+ <p><code>unregister(name)</code></p>
+
+ <div class="description"><p>Unregisters the process with the <code>name</code>
+ string.</p></div>
+
+ <p><code>whereis(name)</code></p>
+
+ <div class="description"><p>Returns the PID of the process with the registered
+ <code>name</code> string.</p></div>
+
+ <p><code>registered()</code></p>
+
+ <div class="description"><p>Returns a table with all the registered process
+ names.</p></div>
+
+ <h4>Linking</h4>
+
+ <p><code>link(process)</code></p>
+
+ <div class="description">
+
+ <p>The calling process gets linked with the specified
+ <code>process</code>, which can be either a PID, a registered name, or a
+ remote process. A remote process is a table with two elements, the remote
+ process PID or registered name and the node's name in the format
+ <code>'nodename@hostname' </code>.</p>
+
+ <p>The <code>'trapexit'</code> option can be set to <code>true</code>, if
+ exit signals between linked processes are to be trapped.</p>
+
+ </div>
+
+ <p><code>unlink(process)</code></p>
+
+ <div class="description"><p>The calling process gets unlinked with the
+ specified <code>process</code>, which can be either a PID, a registered name,
+ or a remote process. A remote process is a table with two elements, the remote
+ process PID or registered name and the node's name in the format <code>
+ 'nodename@hostname'</code>.</p></div>
+
+ <p><code>spawnlink(body, ...)</code></p>
+
+ <div class="description">
+
+ <p>Creates a process which will execute the <code> body</code> function and
+ the calling function also gets linked to the new process. Any extra
+ arguments can be passed to the executing function. The PID of the new
+ process is returned. In case of error <code>nil</code> and an error message
+ are returned.</p>
+
+ <p>The <code>'trapexit'</code> option can be set to <code>true</code>, if
+ exit signals between linked processes are to be trapped.</p>
+
+ </div>
+
+ <p><code>spawnlink(node, body, ...)</code></p>
+
+ <div class="description">
+
+ <p>Creates a process in a remote <code>node</code> which is a string in the
+ format <code>'nodename@hostname'</code>, the new process will execute the
+ <code>body</code> function, and also the calling process gets linked to the
+ newly created process. The PID of the new process is returned. In case of
+ error <code>nil</code> and an error message are returned.</p>
+
+ <p>The <code>'trapexit'</code> option can set to <code>true</code>, if exit
+ signals between linked processes are to be trapped.</p>
+
+ </div>
+
+ <h4>Monitoring</h4>
+
+ <p><code>monitor(process)</code></p>
+
+ <div class="description"><p>The calling process starts monitoring the
+ specified <code>process</code>, which can be either a PID, a registered name,
+ or a remote process. A remote process is a table with two elements, the remote
+ process PID or registered name and the node's name in the format
+ <code>'nodename@hostname'</code>.</p></div>
+
+ <p><code>demonitor(process)</code></p>
+
+ <div class="description"><p>The calling process stops monitoring the specified
+ <code>process</code>, which can be either a PID, a registered name, or a
+ remote process. A remote process is a table with two elements, the remote
+ process PID or registered name and the node's name in the format <code>
+ 'nodename@hostname'</code>.</p></div>
+
+ <p><code>spawnmonitor(body, ...)</code></p>
+
+ <div class="description"><p>Creates a process which will execute the <code>
+ body</code> function and the calling function also starts monitoring the new
+ process. Any extra arguments can be passed to the executing function. The PID
+ of the new process is returned. In case of error <code>nil</code> and an error
+ message are returned.</p></div>
+
+ <p><code>spawnmonitor(node, body, ...)</code></p>
+
+ <div class="description"><p>Creates a process in a remote <code>node</code>
+ which is a string in the format <code>'nodename@hostname'</code>, the new
+ process will execute the <code>body</code> function, and also the calling
+ process starts monitoring the newly created process. The PID of the new
+ process is returned. In case of error <code>nil</code> and an error message
+ are returned.</p></div>
+
+</div>
+
+<div class="center">
+ <div class="navigation">
+ <a class="link" href="index.html">home</a> &middot;
+ <a class="link" href="index.html#download">download</a> &middot;
+ <a class="link" href="index.html#installation">installation</a> &middot;
+ <a class="link" href="introduction.html">introduction</a> &middot;
+ <a class="link" href="reference.html">reference</a>
+ </div>
+</div>
+
+</body>
+
+</html>
71 doc/stylesheet.css
@@ -0,0 +1,71 @@
+body {
+ margin: 2%;
+ background-color: #ffffff;
+}
+
+img {
+ border: 0px;
+}
+
+h2 {
+ margin-left: -12px;
+ margin-right: -12px;
+}
+
+h3 {
+ margin-left: -12px;
+ margin-right: -12px;
+}
+
+h4 {
+ margin-left: -12px;
+ margin-right: -12px;
+}
+
+
+div.description {
+ margin-left: 48px;
+}
+
+div.verbatim {
+ margin-left: 48px;
+}
+
+hr {
+ color: #cccccc;
+ background-color: #cccccc;
+}
+
+div.center {
+ text-align: center
+}
+
+div.navigation {
+ padding: 8px;
+ border: 1px solid #cccccc;
+ background-color: #eeeeee;
+}
+
+div.box {
+ padding-left: 24px;
+ padding-right: 24px;
+ border: 1px solid #cccccc;
+}
+
+a.link:link {
+ font-weight: bold;
+ color: #00007f;
+ text-decoration: none;
+}
+
+a.link:visited {
+ font-weight: bold;
+ color: #00007f;
+ text-decoration: none;
+}
+
+a.link:hover {
+ font-weight: bold;
+ color: #00007f;
+ text-decoration: underline;
+}
10 samples/example1.lua
@@ -0,0 +1,10 @@
+require 'concurrent'
+
+function hello_world(times)
+ for i = 1, times do print('hello world') end
+ print('done')
+end
+
+concurrent.spawn(hello_world, 3)
+
+concurrent.loop()
37 samples/example2.lua
@@ -0,0 +1,37 @@
+require 'concurrent'
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.body == 'finished' then
+ break
+ elseif msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+function ping(n, pid)
+ for i = 1, n do
+ concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'finished'
+ })
+ print('ping finished')
+end
+
+pid = concurrent.spawn(pong)
+concurrent.spawn(ping, 3, pid)
+
+concurrent.loop()
38 samples/example3.lua
@@ -0,0 +1,38 @@
+require 'concurrent'
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.body == 'finished' then
+ break
+ elseif msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+function ping(n)
+ for i = 1, n do
+ concurrent.send('pong', {
+ from = concurrent.self(),
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ concurrent.send('pong', {
+ from = concurrent.self(),
+ body = 'finished'
+ })
+ print('ping finished')
+end
+
+pid = concurrent.spawn(pong)
+concurrent.register('pong', pid)
+concurrent.spawn(ping, 3)
+
+concurrent.loop()
22 samples/example4a.lua
@@ -0,0 +1,22 @@
+require 'concurrent'
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.body == 'finished' then
+ break
+ elseif msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+concurrent.init('pong@gaia')
+
+pid = concurrent.spawn(pong)
+
+concurrent.register('pong', pid)
+concurrent.loop()
+concurrent.shutdown()
25 samples/example4b.lua
@@ -0,0 +1,25 @@
+require 'concurrent'
+
+function ping(n)
+ for i = 1, n do
+ concurrent.send({ 'pong', 'pong@gaia' }, {
+ from = { concurrent.self(), concurrent.node() },
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ concurrent.send({ 'pong', 'pong@gaia' }, {
+ from = { concurrent.self(), concurrent.node() },
+ body = 'finished'
+ })
+ print('ping finished')
+end
+
+concurrent.spawn(ping, 3)
+
+concurrent.init('ping@selene')
+concurrent.loop()
+concurrent.shutdown()
33 samples/example5a.lua
@@ -0,0 +1,33 @@
+require 'concurrent'
+
+function ping(n, pid)
+ concurrent.link(pid)
+ for i = 1, n do
+ concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ print('ping finished')
+ concurrent.exit('finished')
+end
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+pid = concurrent.spawn(pong)
+concurrent.spawn(ping, 3, pid)
+
+concurrent.loop()
37 samples/example5b.lua
@@ -0,0 +1,37 @@
+require 'concurrent'
+
+concurrent.setoption('trapexit', true)
+
+function pong()
+ while true do
+ local msg = concurrent.receive()
+ if msg.signal == 'EXIT' then
+ break
+ elseif msg.body == 'ping' then
+ print('pong received ping')
+ concurrent.send(msg.from, { body = 'pong' })
+ end
+ end
+ print('pong finished')
+end
+
+function ping(n, pid)
+ concurrent.link(pid)
+ for i = 1, n do
+ concurrent.send(pid, {
+ from = concurrent.self(),
+ body = 'ping'
+ })
+ local msg = concurrent.receive()
+ if msg.body == 'pong' then
+ print('ping received pong')
+ end
+ end
+ print('ping finished')
+ concurrent.exit('finished')
+end
+
+pid = concurrent.spawn(pong)
+concurrent.spawn(ping, 3, pid)
+
+concurrent.loop()
5 src/Makefile
@@ -0,0 +1,5 @@
+all install uninstall clean:
+ cd cltime && $(MAKE) $@
+ cd concurrent && $(MAKE) $@
+ cd cldaemon && $(MAKE) $@
+ cd clpmd && $(MAKE) $@
42 src/cldaemon/Makefile
@@ -0,0 +1,42 @@
+VERSION = 1.0.0
+
+DESTDIR =
+PREFIX = /usr/local
+LIBDIR = $(PREFIX)/lib/lua/5.1
+
+INCDIRS = -I/usr/local/include
+LIBDIRS = -L/usr/local/lib
+
+MYCFLAGS = -Wall -g -fpic
+MYLDFLAGS = -shared
+
+CFLAGS = $(MYCFLAGS) $(INCDIRS)
+LDFLAGS = $(MYLDFLAGS) $(LIBDIRS)
+
+LIBS = -llua
+
+LIB = cldaemon.so
+OBJ = cldaemon.o
+
+all: $(LIB)
+
+$(LIB): $(OBJ)
+ $(CC) -o $(LIB) $(LDFLAGS) $(OBJ) $(LIBS)
+
+$(OBJ):
+
+install: all
+ if test ! -d $(DESTDIR)$(LIBDIR); \
+ then mkdir -p $(DESTDIR)$(LIBDIR); \
+ fi
+ cp -f $(LIB) $(DESTDIR)$(LIBDIR)/$(LIB).$(VERSION) && \
+ chmod 0755 $(DESTDIR)$(LIBDIR)/$(LIB).$(VERSION) && \
+ cd $(DESTDIR)$(LIBDIR) && \
+ ln -fs $(LIB).$(VERSION) $(LIB)
+
+uninstall:
+ cd $(DESTDIR)$(LIBDIR) && \
+ rm -f $(LIB) $(LIB).$(VERSION)
+
+clean:
+ rm -f $(OBJ) $(LIB) *~
80 src/cldaemon/cldaemon.c
@@ -0,0 +1,80 @@
+#ifndef _WIN32
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+/*
+ * Implements the BSD daemon() functionality, which turns a process into and
+ * a daemon.
+ */
+static int
+cldaemon_daemon(lua_State *lua)
+{
+
+#ifndef _WIN32
+ switch (fork()) {
+ case -1:
+ fprintf(stderr, "forking; %s\n", strerror(errno));
+ exit(1);
+ break;
+ case 0:
+ break;
+ default:
+ exit(0);
+ break;
+ }
+
+ if (setsid() == -1) {
+ fprintf(stderr, "creating session; %s\n", strerror(errno));
+ exit(1);
+ }
+ switch (fork()) {
+ case -1:
+ fprintf(stderr, "creating session; %s\n", strerror(errno));
+ exit(1);
+ break;
+ case 0:
+ break;
+ default:
+ exit(0);
+ break;
+ }
+
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ if (open("/dev/null", O_RDWR) != -1) {
+ dup(STDIN_FILENO);
+ dup(STDIN_FILENO);
+ }
+#endif
+
+ return 0;
+}
+
+/* The cldaemon library. */
+static const luaL_reg lib[] = {
+ { "daemon", cldaemon_daemon },
+ { NULL, NULL }
+};
+
+/*
+ * Opens the cldaemon library.
+ */
+LUALIB_API int
+luaopen_cldaemon(lua_State *lua)
+{
+
+ luaL_openlib(lua, "cldaemon", lib, 0);
+
+ return 1;
+}
2  src/cldaemon/cldaemon.def
@@ -0,0 +1,2 @@
+EXPORTS
+luaopen_cldaemon
24 src/clpmd/Makefile
@@ -0,0 +1,24 @@
+DESTDIR =
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+
+BIN = clpmd
+
+all: $(BIN)
+
+$(BIN):
+
+install: all
+ if test ! -d $(DESTDIR)$(BINDIR); \
+ then mkdir -p $(DESTDIR)$(BINDIR); \
+ fi
+ cp -f $(BIN) $(DESTDIR)$(BINDIR) && \
+ cd $(DESTDIR)$(BINDIR) && \
+ chmod 0755 $(BIN)
+
+uninstall:
+ cd $(DESTDIR)$(BINDIR) && \
+ rm -f $(BIN)
+
+clean:
+ rm -f *~
61 src/clpmd/clpmd
@@ -0,0 +1,61 @@
+#!/usr/bin/lua
+
+require 'socket'
+require 'copas'
+
+require 'cldaemon'
+
+database = {}
+
+server = socket.bind('*', 9634)
+
+function handler(socket)
+ socket = copas.wrap(socket)
+ while true do
+ local data = socket:receive()
+ if not data then
+ break
+ end
+
+ local name, port = string.match(data, '^%+ ([%w_]+@[%w-.]+) (%d+)$')
+ if name and port and not database[name] then
+ database[name] = port
+ print(name .. ' = ' .. port)
+ end
+
+ local name, port = string.match(data, '^%= ([%w_]+@[%w-.]+) (%d+)$')
+ if name and port and database[name] then
+ database[name] = port
+ print(name .. ' = ' .. port)
+ end
+
+ local name = string.match(data, '^%- ([%w_]+@[%w-.]+)$')
+ if name and database[name] then
+ database[name] = nil
+ print(name .. ' = 0')
+ end
+
+ local name = string.match(data, '^%? ([%w_]+@[%w-.]+)$')
+ if name then
+ if database[name] then
+ socket:send(database[name] .. '\r\n')
+ else
+ socket:send('0\r\n')
+ end
+ end
+
+ if string.find(data, '^%*$') then
+ local s = ''
+ for k, v in pairs(database) do
+ s = s .. k .. '=' .. v .. ','
+ end
+ socket:send(s .. '\r\n')
+ end
+ end
+end
+
+cldaemon.daemon()
+
+copas.addserver(server, handler)
+copas.loop()
+
42 src/cltime/Makefile
@@ -0,0 +1,42 @@
+VERSION = 1.0.0
+
+DESTDIR =
+PREFIX = /usr/local
+LIBDIR = $(PREFIX)/lib/lua/5.1
+
+INCDIRS = -I/usr/local/include
+LIBDIRS = -L/usr/local/lib
+
+MYCFLAGS = -Wall -g -fpic
+MYLDFLAGS = -shared
+
+CFLAGS = $(MYCFLAGS) $(INCDIRS)
+LDFLAGS = $(MYLDFLAGS) $(LIBDIRS)
+
+LIBS = -llua
+
+LIB = cltime.so
+OBJ = cltime.o
+
+all: $(LIB)
+
+$(LIB): $(OBJ)
+ $(CC) -o $(LIB) $(LDFLAGS) $(OBJ) $(LIBS)
+
+$(OBJ):
+
+install: all
+ if test ! -d $(DESTDIR)$(LIBDIR); \
+ then mkdir -p $(DESTDIR)$(LIBDIR); \
+ fi
+ cp -f $(LIB) $(DESTDIR)$(LIBDIR)/$(LIB).$(VERSION) && \
+ chmod 0755 $(DESTDIR)$(LIBDIR)/$(LIB).$(VERSION) && \
+ cd $(DESTDIR)$(LIBDIR) && \
+ ln -fs $(LIB).$(VERSION) $(LIB)
+
+uninstall:
+ cd $(DESTDIR)$(LIBDIR) && \
+ rm -f $(LIB) $(LIB).$(VERSION)
+
+clean:
+ rm -f $(OBJ) $(LIB) *~
88 src/cltime/cltime.c
@@ -0,0 +1,88 @@
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+/*
+ * Returns the time elapsed since the epoch in milliseconds.
+ */
+static int
+cltime_time(lua_State *L)
+{
+#ifdef _WIN32
+ SYSTEMTIME st, est;
+ FILETIME ft, eft;
+ ULARGE_INTEGER i, ei;
+
+ GetLocalTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+ i.HighPart = ft.dwHighDateTime;
+ i.LowPart = ft.dwLowDateTime;
+
+ est.wYear = 1970;
+ est.wMonth = 1;
+ est.wDay = 1;
+ est.wHour = 0;
+ est.wMinute = 0;
+ est.wSecond = 0;
+ est.wMilliseconds = 0;
+ SystemTimeToFileTime(&est, &eft);
+ ei.HighPart = eft.dwHighDateTime;
+ ei.LowPart = eft.dwLowDateTime;
+
+ lua_pushnumber(L, ((i.QuadPart - ei.QuadPart) / 10000));
+#else
+ struct timeval tv;
+
+ if (gettimeofday(&tv, NULL) != 0)
+ return 0;
+
+ lua_pushnumber(L, (unsigned long long int)(tv.tv_sec) * 1000 +
+ (unsigned long long int)(tv.tv_usec) / 1000);
+#endif
+ return 1;
+}
+
+/*
+ * Delays for the specified amount of time in milliseconds.
+ */
+static int
+cltime_sleep(lua_State *L)
+{
+
+#ifdef _WIN32
+ Sleep((DWORD)(lua_tonumber(L, 1)));
+#else
+ usleep((useconds_t)(lua_tonumber(L, 1) * 1000));
+#endif
+
+ lua_pop(L, 1);
+
+ return 0;
+}
+
+/* The cltime library. */
+static const luaL_reg lib[] = {
+ { "time", cltime_time },
+ { "sleep", cltime_sleep },
+ { NULL, NULL }
+};
+
+/*
+ * Opens the cltime library.
+ */
+LUALIB_API int
+luaopen_cltime(lua_State *lua)
+{
+
+ luaL_openlib(lua, "cltime", lib, 0);
+
+ return 1;
+}
2  src/cltime/cltime.def
@@ -0,0 +1,2 @@
+EXPORTS
+luaopen_cltime
36 src/concurrent/Makefile
@@ -0,0 +1,36 @@
+DESTDIR =
+PREFIX = /usr/local
+SHAREDIR = $(PREFIX)/share/lua/5.1
+SHAREMODDIR = $(SHAREDIR)/concurrent
+
+SHARE = init.lua \
+ option.lua \
+ process.lua \
+ message.lua \
+ scheduler.lua \
+ register.lua \
+ monitor.lua \
+ link.lua \
+ root.lua
+
+all: $(SHARE)
+
+$(SHARE):
+
+install:
+ if test ! -d $(DESTDIR)$(SHAREMODDIR); \
+ then mkdir -p $(DESTDIR)$(SHAREMODDIR); \
+ fi
+ cp -f $(SHARE) $(DESTDIR)$(SHAREMODDIR) && \
+ cd $(DESTDIR)$(SHAREMODDIR) && \
+ chmod 0644 $(SHARE)
+ cd distributed && $(MAKE) install
+
+uninstall:
+ cd $(DESTDIR)$(SHAREMODDIR) && \
+ rm -f $(SHARE)
+ cd distributed && $(MAKE) uninstall
+
+clean:
+ rm -f *~
+ cd distributed && $(MAKE) clean
34 src/concurrent/distributed/Makefile
@@ -0,0 +1,34 @@
+DESTDIR =
+PREFIX = /usr/local
+SHAREDIR = $(PREFIX)/share/lua/5.1
+SHAREMODDIR = $(SHAREDIR)/concurrent/distributed
+
+SHARE = init.lua \
+ network.lua \
+ node.lua \
+ cookie.lua \
+ process.lua \
+ message.lua \
+ scheduler.lua \
+ register.lua \
+ link.lua \
+ monitor.lua
+
+all: $(SHARE)
+
+$(SHARE):
+
+install:
+ if test ! -d $(DESTDIR)$(SHAREMODDIR); \
+ then mkdir -p $(DESTDIR)$(SHAREMODDIR); \
+ fi
+ cp -f $(SHARE) $(DESTDIR)$(SHAREMODDIR) && \
+ cd $(DESTDIR)$(SHAREMODDIR) && \
+ chmod 0644 $(SHARE)
+
+uninstall:
+ cd $(DESTDIR)$(SHAREMODDIR) && \
+ rm -f $(SHARE)
+
+clean:
+ rm -f *~
19 src/concurrent/distributed/cookie.lua
@@ -0,0 +1,19 @@
+-- Submodule for setting the magic cookie.
+module('concurrent._distributed._cookie', package.seeall)
+
+cookie = nil -- The magic cookie used for authentication.
+
+-- Sets the magic cookie.
+function setcookie(c)
+ if concurrent.node() then
+ cookie = c
+ end
+end
+
+-- Returns the set magic cookie.
+function getcookie()
+ return cookie
+end
+
+concurrent.setcookie = setcookie
+concurrent.getcookie = getcookie
15 src/concurrent/distributed/init.lua
@@ -0,0 +1,15 @@
+-- Main module for distributed programming that loads all the submodules.
+module('concurrent._distributed', package.seeall)
+
+require 'concurrent.distributed.network'
+require 'concurrent.distributed.node'
+require 'concurrent.distributed.cookie'
+
+require 'concurrent.distributed.process'
+require 'concurrent.distributed.message'
+require 'concurrent.distributed.scheduler'
+
+require 'concurrent.distributed.register'
+
+require 'concurrent.distributed.link'
+require 'concurrent.distributed.monitor'
149 src/concurrent/distributed/link.lua
@@ -0,0 +1,149 @@
+-- Submodule for linking between distributed processes.
+module('concurrent._distributed._link', package.seeall)
+
+-- The existing versions of the linking related functions are renamed.
+_link = concurrent._link.link
+_unlink = concurrent._link.unlink
+_signal = concurrent._link.signal
+
+-- Links the calling process with the specified process. If the destination
+-- process is local the old renamed version of the function is called, otherwise
+-- a linking request is sent to the node where the destination process is
+-- executing under.
+function link(dest)
+ if type(dest) ~= 'table' then
+ return _link(concurrent.whereis(dest))
+ end
+
+ local links = concurrent._link.links
+ local s = concurrent.self()
+ local pid, node = unpack(dest)
+ if type(links[s]) == 'nil' then
+ links[s] = {}
+ end
+ for _, v in pairs(links[s]) do
+ if type(v) == 'table' and pid == v[1] and node == v[2] then
+ return
+ end
+ end
+ concurrent.send({ -1, node }, { subject = 'LINK', to = { pid = pid },
+ from = { pid = s, node = concurrent.node() } })
+ table.insert(links[s], dest)
+end
+
+-- Handles linking requests from a remote process.
+function controller_link(msg)
+ local links = concurrent._link.links
+ local pid = concurrent.whereis(msg.to.pid)
+ if not pid then
+ return
+ end
+ if type(links[pid]) == 'nil' then
+ links[pid] = {}
+ end
+ for _, v in pairs(links[pid]) do
+ if type(v) == 'table' and msg.from.pid == v[1] and
+ msg.from.node == v[2] then
+ return
+ end
+ end
+ table.insert(links[pid], { msg.from.pid, msg.from.node })
+end
+
+-- Creates a process either local or remote which is also linked to the calling
+-- process.</