1 /** 2 * Copyright (c) 2006-2011 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 <common/config.h> 22 23 #include "Thread.h" 24 25 #ifdef LOVE_BUILD_STANDALONE 26 extern "C" int luaopen_love(lua_State * L); 27 #endif // LOVE_BUILD_STANDALONE 28 extern "C" int luaopen_love_thread(lua_State *L); 29 30 namespace love 31 { 32 namespace thread 33 { 34 namespace sdl 35 { threadfunc(ThreadData * comm)36 int threadfunc(ThreadData *comm) 37 { 38 lua_State * L = lua_open(); 39 luaL_openlibs(L); 40 #ifdef LOVE_BUILD_STANDALONE 41 love::luax_preload(L, luaopen_love, "love"); 42 luaopen_love(L); 43 #endif // LOVE_BUILD_STANDALONE 44 luaopen_love_thread(L); 45 { 46 size_t len; 47 const char *name = comm->getName(&len); 48 lua_pushlstring(L, name, len); 49 } 50 luax_convobj(L, lua_gettop(L), "thread", "getThread"); 51 lua_getglobal(L, "love"); 52 lua_pushvalue(L, -2); 53 lua_setfield(L, -2, "_curthread"); 54 if(luaL_dostring(L, comm->getCode()) == 1) 55 { 56 SDL_mutexP((SDL_mutex*) comm->mutex); 57 ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1), lua_strlen(L, -1)); 58 comm->setValue("error", v); 59 v->release(); 60 SDL_mutexV((SDL_mutex*) comm->mutex); 61 SDL_CondBroadcast((SDL_cond*) comm->cond); 62 } 63 lua_close(L); 64 return 0; 65 } 66 ThreadVariant(bool boolean)67 ThreadVariant::ThreadVariant(bool boolean) 68 { 69 type = BOOLEAN; 70 data.boolean = boolean; 71 } 72 ThreadVariant(double number)73 ThreadVariant::ThreadVariant(double number) 74 { 75 type = NUMBER; 76 data.number = number; 77 } 78 ThreadVariant(const char * string,size_t len)79 ThreadVariant::ThreadVariant(const char *string, size_t len) 80 { 81 type = STRING; 82 char *buf = new char[len+1]; 83 memset(buf, 0, len+1); 84 memcpy(buf, string, len); 85 data.string.str = buf; 86 data.string.len = len; 87 } 88 ThreadVariant(void * userdata)89 ThreadVariant::ThreadVariant(void *userdata) 90 { 91 type = LUSERDATA; 92 data.userdata = userdata; 93 } 94 ThreadVariant(Type udatatype,void * userdata)95 ThreadVariant::ThreadVariant(Type udatatype, void *userdata) 96 { 97 type = FUSERDATA; 98 this->udatatype = udatatype; 99 Proxy *p = (Proxy *) userdata; 100 flags = p->flags; 101 data.userdata = p->data; 102 ((love::Object *) data.userdata)->retain(); 103 } 104 ~ThreadVariant()105 ThreadVariant::~ThreadVariant() 106 { 107 switch(type) 108 { 109 case STRING: 110 delete[] data.string.str; 111 break; 112 case FUSERDATA: 113 ((love::Object *) data.userdata)->release(); 114 break; 115 default: 116 break; 117 } 118 } 119 ThreadData(const char * name,size_t len,const char * code,void * mutex,void * cond)120 ThreadData::ThreadData(const char *name, size_t len, const char *code, void *mutex, void *cond) 121 : len(len), mutex(mutex), cond(cond) 122 { 123 this->name = new char[len+1]; 124 memset(this->name, 0, len+1); 125 memcpy(this->name, name, len); 126 if (code) 127 { 128 len = strlen(code); 129 this->code = new char[len+1]; 130 memset(this->code, 0, len+1); 131 memcpy(this->code, code, len); 132 } 133 else 134 this->code = 0; 135 } 136 ~ThreadData()137 ThreadData::~ThreadData() 138 { 139 delete[] name; 140 delete[] code; 141 } 142 getCode()143 const char *ThreadData::getCode() 144 { 145 return code; 146 } 147 getName(size_t * len)148 const char *ThreadData::getName(size_t *len) 149 { 150 if (len) 151 *len = this->len; 152 return name; 153 } 154 getValue(const std::string & name)155 ThreadVariant* ThreadData::getValue(const std::string & name) 156 { 157 if (shared.count(name) == 0) 158 return 0; 159 return shared[name]; 160 } 161 clearValue(const std::string & name)162 void ThreadData::clearValue(const std::string & name) 163 { 164 if (shared.count(name) == 0) 165 return; 166 shared[name]->release(); 167 shared.erase(name); 168 } 169 setValue(const std::string & name,ThreadVariant * v)170 void ThreadData::setValue(const std::string & name, ThreadVariant *v) 171 { 172 if (shared.count(name) != 0) 173 shared[name]->release(); 174 v->retain(); 175 shared[name] = v; 176 } 177 Thread(love::thread::ThreadModule * module,const std::string & name,love::Data * data)178 Thread::Thread(love::thread::ThreadModule *module, const std::string & name, love::Data *data) 179 : handle(0), module(module), name(name), isThread(true) 180 { 181 module->retain(); 182 unsigned int len = data->getSize(); 183 this->data = new char[len+1]; 184 memset(this->data, 0, len+1); 185 memcpy(this->data, data->getData(), len); 186 mutex = SDL_CreateMutex(); 187 cond = SDL_CreateCond(); 188 comm = new ThreadData(name.c_str(), name.length(), this->data, mutex, cond); 189 } 190 Thread(love::thread::ThreadModule * module,const std::string & name)191 Thread::Thread(love::thread::ThreadModule *module, const std::string & name) 192 : handle(0), module(module), name(name), data(0), isThread(false) 193 { 194 module->retain(); 195 mutex = SDL_CreateMutex(); 196 cond = SDL_CreateCond(); 197 comm = new ThreadData(name.c_str(), name.length(), NULL, mutex, cond); 198 } 199 ~Thread()200 Thread::~Thread() 201 { 202 if (data) 203 delete[] data; 204 delete comm; 205 module->unregister(name); 206 SDL_DestroyMutex(mutex); 207 SDL_DestroyCond(cond); 208 module->release(); 209 } 210 start()211 void Thread::start() 212 { 213 if (!handle && isThread) 214 handle = SDL_CreateThread((int (*)(void*)) threadfunc, (void*) comm); 215 } 216 kill()217 void Thread::kill() 218 { 219 if (handle) 220 { 221 SDL_mutexP((SDL_mutex *) _gcmutex); 222 SDL_KillThread(handle); 223 handle = 0; 224 SDL_mutexV((SDL_mutex *) _gcmutex); 225 } 226 } 227 wait()228 void Thread::wait() 229 { 230 if (handle) 231 { 232 SDL_WaitThread(handle, NULL); 233 handle = 0; 234 } 235 } 236 lock()237 void Thread::lock() 238 { 239 SDL_mutexP(mutex); 240 } 241 unlock()242 void Thread::unlock() 243 { 244 SDL_mutexV(mutex); 245 } 246 getName()247 std::string Thread::getName() 248 { 249 return name; 250 } 251 receive(const std::string & name)252 ThreadVariant *Thread::receive(const std::string & name) 253 { 254 ThreadVariant *v = comm->getValue(name); 255 if (v) 256 v->retain(); 257 return v; 258 } 259 demand(const std::string & name)260 ThreadVariant *Thread::demand(const std::string & name) 261 { 262 ThreadVariant *v = comm->getValue(name); 263 while (!v) 264 { 265 if (comm->getValue("error")) 266 return 0; 267 SDL_CondWait(cond, mutex); 268 v = comm->getValue(name); 269 } 270 v->retain(); 271 return v; 272 } 273 clear(const std::string & name)274 void Thread::clear(const std::string & name) 275 { 276 comm->clearValue(name); 277 } 278 send(const std::string & name,ThreadVariant * v)279 void Thread::send(const std::string & name, ThreadVariant *v) 280 { 281 lock(); //this function explicitly locks 282 comm->setValue(name, v); //because we need 283 unlock(); //it to unlock here for the cond 284 SDL_CondBroadcast(cond); 285 } 286 ThreadModule()287 ThreadModule::ThreadModule() 288 { 289 threads["main"] = new Thread(this, "main"); 290 } 291 ~ThreadModule()292 ThreadModule::~ThreadModule() 293 { 294 for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++) 295 { 296 i->second->kill(); 297 } 298 } 299 newThread(const std::string & name,love::Data * data)300 Thread *ThreadModule::newThread(const std::string & name, love::Data *data) 301 { 302 if (threads.count(name) != 0) 303 return 0; 304 Thread *t = new Thread(this, name, data); 305 threads[name] = t; 306 return t; 307 } 308 getThread(const std::string & name)309 Thread *ThreadModule::getThread(const std::string & name) 310 { 311 if (threads.count(name) == 0) 312 return 0; 313 threadlist_t::iterator i = threads.find(name); 314 return i->second; 315 } 316 getThreads(Thread ** list)317 void ThreadModule::getThreads(Thread ** list) 318 { 319 int c = 0; 320 for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++, c++) 321 { 322 list[c] = i->second; 323 } 324 } 325 getThreadCount() const326 unsigned ThreadModule::getThreadCount() const 327 { 328 return threads.size(); 329 } 330 unregister(const std::string & name)331 void ThreadModule::unregister(const std::string & name) 332 { 333 if (threads.count(name) == 0) 334 return; 335 threadlist_t::iterator i = threads.find(name); 336 threads.erase(i); 337 } 338 getName() const339 const char *ThreadModule::getName() const 340 { 341 return "love.thread.sdl"; 342 } 343 } // sdl 344 } // thread 345 } // love 346