lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


For what it's worth, this has already been fixed on LuaSocket's github repository. If you have anything else to report, please open an issue there.

On Mon, Mar 11, 2019 at 1:17 AM Philippe Verdy <verdy_p@wanadoo.fr> wrote:
Le lun. 11 mars 2019 à 03:46, Tim Hill <drtimhill@gmail.com> a écrit :
I think you misunderstand the OP. Lus itself is not multi-threaded, but IS thread-safe. That is, you can create multiple Lua states using lua_newstate() and run these in independent, concurrent thread with perfect safety WITHOUT any special patching or locking, since these two Lua states will not share ANY state at all.

And your "ANY" word is wrong here: the state alone is not enough given that the Lua VM itself runs as a thread and uses libraries that are not thread-safe if they use C/C++ static variables instead of dynamic memory, or stack, or thread local storage.

But the cooperative model of "states" in Lua (that the doc also names "threads"... very confusively) has its own security limits: the cooperative Lua threads do not have any resource limits: they are very sensitive to DoS attacks given that there's no preemption for their allowed time slot or memory: a single Lua thread can steal indefinitely all resources that other Lua threads are waiting. Great, concurrent Lua threads cannot inspect what other Lua threads are doing because there's no preemption, but then privacy has a cost: DoS sensitivity, and also lack of interactivity and lot of unpredictable and unbounded delays for response times: remote clients of a Lua-based server will experiment very frequent timeouts, they can start doing things then be suspended for minutes or hours because of any other Lua thread that is just computing something intensively without ever yield()'ing (or making blocking I/O calls, such thing including an implicit internal yield).
 
The OP was noting that, should you do such a thing, the library in question may fail since it is NOT thread safe. This is quite different from a SINGLE Lua VM running multiple threads concurrently.

But then you run concurrent Lua VMs (in as many OS-level threads), not concurrent Lua threads (that run in a single OS-level thread), but you suppose that these separate VMs are completely independant (they are not: they also share critical resources, notably the OS-level memory allocator). The Lua VM does not really offer a good protection, and in such situation the multiple Lua VMs should better run as concurrent processes (e.g. in Fast-CGI for Apache servers, with a set of worker processes, like in traditional PHP servers: this makes the service much more resistant to DoS attacks and allows faster restart if ever one of these VMs is crashing or exhaust its limits and must be aborted, including for security reasons).

If we want true multithreading in Lua, the Lua states (those exposed in the Lua language, not those in LuaC!) should also be runnable concurrently without even having to yield: a thread could be started with a time slot limit (by default infinite like today) that the VM would preempt and it's natural in that case that these Lua states (not LuaC states) are implementede on top of preemptable POSIX-like threads, managed at OS level.

The LuaC state jsut represents the first main OS-level thread that serializes the cooperative threads, but cooperative threads would run in another OS-level thread. I/O and networking integration would also run in another OS-level thread. Any one of these Lua threads (not LuaC=OS thread) could then be interrupted. service listeners, and blocking I/O would use aynchrnous completion or timeout events and preemption when these events occur.

Of course not all environments where Lua is integrated have capabilities to run Posix-like threads. But it's really unfortunate that Lua cannot make use of real threads (except by instantiating multiple separate VMs) to make use of today's multicore CPUs or multi-CPU systems (notably for app servers!). Having to instaciate multiple separate VMs also does not allow easy cooperation and interaction between them, and is also problematic in terms of resource allocation and management (notably for memory: large applications cannot share memory for their common code, Lua applications have to be compiled multiple times, by each VM).

Basically Lua just works today just like Windows 3.x in the 1990's before OS/2 and then NT were created: Windows 3.x worked but as long as there were not thousands "threads" as of today but only one or two dozens (above that level, we could see the UI freeze almost constantly, by the DoS-like effect of absence of preemption). The same happens in Lua: there's absolutely no balancing of resource usage and no way to control it and pace those that are using the CPU too much. The cooperative model is still very fragile (and we remember what it was in Windows 3.x when interminable "hangs" required users to CTRL+ALT+DEL for rebooting abruptly...

There's still no virtalization at all and the term "VM" is abused when we speak about Lua if it is just a "virtual machine" but without virtual memory and virtual CPU.

The cooperative model is only good if all Lua threads are part of the same application developed and managed by the same source/authour, but not for handling services with user-written scripts (see how Lua is used in Wikimedia: it has no other choice than fixing a timeout limit and run each request in a separate VM, itself running in a separate worker process, and then kill it it the timeslot is exhausted, it works with FastCGI as long as we can a large pool of worker threads ready to service a request and an external monitor that can kill the offenders; but it's not a good solution for many servers because killing worker processes means that we also need additional processes to perform cleanup and unlock/release the temporary resources; and it requires a large amount of resources: many CPUs or cores, much more memory, and large farms of servers: this solution does not scale very well, it is too costly). But if we can do real multi-threading, we can better use the resources, avoid starvation of concurrent works, avoid most timeouts for clients, and manage the workload of servers with reasonnable response time and with more modest resources available to service many more requests.