summaryrefslogtreecommitdiffstats
path: root/README.markdown
blob: 8cfcabb656fea050532b275f88979ea33a30f20e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
A Lua Event Machine
===================


About
-----
The Lua Event Machine is an attempt to make multitasking easier.
It makes heavy use of Lua coroutines so code that does I/O
can be suspended until data is ready. This allows you write code
as if you're using blocking I/O, while still allowing code in other
coroutines to run when you'd otherwise wait for I/O.

Hovewer unlike traditional multithreading there is no need for locks since
only one coroutine is running at a given time and you know exactly
when control might switch to another coroutine. That is when you're
doing I/O.

Here is a minimal chat server:
```lua
local io = require 'lem.io'
local queue = require 'lem.io.queue'

local socket = assert(io.tcp.listen('*', '5555'))
local clients = {}

socket:autospawn(function(client)
  client:write('What is your name?\r\n')
  local name = client:read('*l')
  if not name then
    client:close()
    return
  end
  name = name:match('[^\r]*')

  local self = queue.wrap(client)
  clients[self] = true

  while true do
    local line = client:read('*l')
    if not line then break end

    for c, _ in pairs(clients) do
      if c ~= self then
        c:write(string.format('%s : %s\r\n', name, line))
      end
    end
  end

  clients[self] = nil
  client:close()
end)
```
Use `telnet <your ip> 5555` to connect to it.


How It Works
------------
LEM is basically a [Lua][] interpreter with a built-in
[libev][] main loop.

All Lua code is run in coroutines so that modules can suspend the currently
running code, register callbacks with the event loop and wait for events
to happen before resuming the coroutine.

This allows libraries to be written such that calls appear to be blocking,
while still allowing other Lua coroutines to run. It also allows you to write
libraries which automatically spawn new coroutines to handle incoming events.
In the above example the autospawn method automatically spawns new coroutines
to handle incoming connections, and the read and write methods suspends the
the running coroutine while waiting for I/O.

For this to work properly LEM modules needs to use non-blocking I/O. However,
not all I/O can easily be done non-blocking. Filesystem operations is one example.
Therefore LEM also includes a thread pool and an API to easily push work to a
separate OS thread and receive an event when it's done.

[Lua]: http://www.lua.org/
[libev]: http://libev.schmorp.de/


Getting Started
---------------
Check out the sources

    $ git clone git://github.com/esmil/lem.git
    $ cd lem

and do

    $ ./configure --prefix=<your prefix>
    $ make

Now you can try out some of the test scripts. The test scripts also serve as examples.

    $ test/sleep.lua
    $ test/lfs.lua

If you're happy with the result run

    $ make install

to install the event machine to `<your prefix>`.

Both the Lua 5.2.1 and libev 4.11 sources are included so having Lua or
libev installed on your system is not required.
However if you already have a Lua 5.1 or 5.2 library installed the configure
script should find it and link against it.
Use `./configure --with-lua=builtin` or `./configure --with-lua=<pkg-config name>`
to use a specific version of Lua.
Eg. to build against the [LuaJIT][] library I do

    $ ./configure --with-lua=luajit

[LuaJIT]: http://luajit.org/luajit.html


Usage
-----
The `lem` interpreter will behave just like the normal standalone Lua
interpreter except it doesn't take any command line options yet.
All your normal Lua scripts should run with the LEM interpreter just fine. Type

    $ lem myscript.lua

to run `myscript.lua` or make the script executable and add a hash-bang
header as in

```lua
#!/usr/bin/env lem

local utils = require 'lem.utils'
local io    = require 'lem.io'

(etc.)
```

Just like the normal stand-alone interpreter LEM stores command line
arguments in the global table `arg` where `arg[-1]` is the interpreter,
`arg[0]` is the script name and normal arguments begin at `arg[1]`.

Running Lua scripts in the Lua Event Machine however, will allow you
to load the LEM modules, which will fail in the normal interpreter.

See the test folder for examples of how to use the different parts of LEM.

License
-------
The Lua Event Machine is free software. It is distributed under the terms
of the [GNU Lesser General Public License][lgpl].

[lgpl]: http://www.gnu.org/licenses/lgpl.html


Contact
-------
Please send bug reports, patches, feature requests, praise and general gossip
to me, Emil Renner Berthing <esmil@mailme.dk>.