1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "LuaThread.h"
22#include "event/Event.h"
23#include "common/config.h"
24
25#ifdef LOVE_BUILD_STANDALONE
26extern "C" int luaopen_love(lua_State * L);
27#endif // LOVE_BUILD_STANDALONE
28
29namespace love
30{
31namespace thread
32{
33
34love::Type LuaThread::type("Thread", &Threadable::type);
35
36LuaThread::LuaThread(const std::string &name, love::Data *code)
37 : code(code)
38 , name(name)
39 , haserror(false)
40{
41 threadName = name;
42}
43
44LuaThread::~LuaThread()
45{
46}
47
48void LuaThread::threadFunction()
49{
50 error.clear();
51 haserror = false;
52
53 lua_State *L = luaL_newstate();
54 luaL_openlibs(L);
55
56#ifdef LOVE_BUILD_STANDALONE
57 luax_preload(L, luaopen_love, "love");
58 luax_require(L, "love");
59 lua_pop(L, 1);
60#endif // LOVE_BUILD_STANDALONE
61
62 luax_require(L, "love.thread");
63 lua_pop(L, 1);
64
65 // We load love.filesystem by default, since require still exists without it
66 // but won't load files from the proper paths. love.filesystem also must be
67 // loaded before using any love function that can take a filepath argument.
68 luax_require(L, "love.filesystem");
69 lua_pop(L, 1);
70
71 lua_pushcfunction(L, luax_traceback);
72 int tracebackidx = lua_gettop(L);
73
74 if (luaL_loadbuffer(L, (const char *) code->getData(), code->getSize(), name.c_str()) != 0)
75 {
76 error = luax_tostring(L, -1);
77 haserror = true;
78 }
79 else
80 {
81 int pushedargs = (int) args.size();
82
83 for (int i = 0; i < pushedargs; i++)
84 args[i].toLua(L);
85
86 args.clear();
87
88 if (lua_pcall(L, pushedargs, 0, tracebackidx) != 0)
89 {
90 error = luax_tostring(L, -1);
91 haserror = true;
92 }
93 }
94
95 lua_close(L);
96
97 if (haserror)
98 onError();
99}
100
101bool LuaThread::start(const std::vector<Variant> &args)
102{
103 if (isRunning())
104 return false;
105
106 this->args = args;
107 error.clear();
108 haserror = false;
109
110 return Threadable::start();
111}
112
113const std::string &LuaThread::getError() const
114{
115 return error;
116}
117
118void LuaThread::onError()
119{
120 auto eventmodule = Module::getInstance<event::Event>(Module::M_EVENT);
121 if (!eventmodule)
122 return;
123
124 std::vector<Variant> vargs = {
125 Variant(&LuaThread::type, this),
126 Variant(error.c_str(), error.length())
127 };
128
129 StrongRef<event::Message> msg(new event::Message("threaderror", vargs), Acquire::NORETAIN);
130 eventmodule->push(msg);
131}
132
133} // thread
134} // love
135