thread_manager.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. #include "thread_manager.h"
  2. #include "core_manager.h"
  3. #include "performance_model.h"
  4. #include "instruction.h"
  5. #include "hooks_manager.h"
  6. #include "config.h"
  7. #include "log.h"
  8. #include "stats.h"
  9. #include "transport.h"
  10. #include "simulator.h"
  11. #include "clock_skew_minimization_object.h"
  12. #include "core.h"
  13. #include "thread.h"
  14. #include "scheduler.h"
  15. #include "syscall_server.h"
  16. #include "circular_log.h"
  17. #include <sys/syscall.h>
  18. #include "os_compat.h"
  19. const char* ThreadManager::stall_type_names[] = {
  20. "unscheduled", "broken", "join", "mutex", "cond", "barrier", "futex", "pause", "sleep", "syscall"
  21. };
  22. static_assert(ThreadManager::STALL_TYPES_MAX == sizeof(ThreadManager::stall_type_names) / sizeof(char*),
  23. "Not enough values in ThreadManager::stall_type_names");
  24. ThreadManager::ThreadManager()
  25. : m_thread_tls(TLS::create())
  26. , m_scheduler(Scheduler::create(this))
  27. {
  28. }
  29. ThreadManager::~ThreadManager()
  30. {
  31. for (UInt32 i = 0; i < m_thread_state.size(); i++)
  32. {
  33. #if 0 // Disabled: applications are not required to do proper cleanup
  34. if (m_thread_state[i].status != Core::IDLE)
  35. fprintf(stderr, "Thread %d still active when ThreadManager destructs\n", i);
  36. #endif
  37. delete m_threads[i];
  38. }
  39. delete m_thread_tls;
  40. delete m_scheduler;
  41. }
  42. Thread* ThreadManager::getThreadFromID(thread_id_t thread_id)
  43. {
  44. LOG_ASSERT_ERROR((size_t)thread_id < m_threads.size(), "Invalid thread_id %d", thread_id);
  45. return m_threads.at(thread_id);
  46. }
  47. Thread* ThreadManager::getCurrentThread(int threadIndex)
  48. {
  49. return m_thread_tls->getPtr<Thread>(threadIndex);
  50. }
  51. Thread* ThreadManager::findThreadByTid(pid_t tid)
  52. {
  53. for (UInt32 thread_id = 0; thread_id < m_threads.size(); ++thread_id)
  54. {
  55. if (m_threads.at(thread_id)->m_os_info.tid == tid)
  56. return m_threads.at(thread_id);
  57. }
  58. return NULL;
  59. }
  60. Thread* ThreadManager::createThread(app_id_t app_id, thread_id_t creator_thread_id)
  61. {
  62. ScopedLock sl(m_thread_lock);
  63. return createThread_unlocked(app_id, creator_thread_id);
  64. }
  65. Thread* ThreadManager::createThread_unlocked(app_id_t app_id, thread_id_t creator_thread_id)
  66. {
  67. thread_id_t thread_id = m_threads.size();
  68. Thread *thread = new Thread(thread_id, app_id);
  69. m_threads.push_back(thread);
  70. m_thread_state.push_back(ThreadState());
  71. m_thread_state[thread->getId()].status = Core::INITIALIZING;
  72. core_id_t core_id = m_scheduler->threadCreate(thread_id);
  73. if (core_id != INVALID_CORE_ID)
  74. {
  75. Core *core = Sim()->getCoreManager()->getCoreFromID(core_id);
  76. thread->setCore(core);
  77. core->setState(Core::INITIALIZING);
  78. }
  79. Sim()->getStatsManager()->logEvent(StatsManager::EVENT_THREAD_CREATE, SubsecondTime::MaxTime(), core_id, thread_id, app_id, creator_thread_id, "");
  80. HooksManager::ThreadCreate args = { thread_id: thread_id, creator_thread_id: creator_thread_id };
  81. Sim()->getHooksManager()->callHooks(HookType::HOOK_THREAD_CREATE, (UInt64)&args);
  82. CLOG("thread", "Create %d", thread_id);
  83. return thread;
  84. }
  85. void ThreadManager::onThreadStart(thread_id_t thread_id, SubsecondTime time)
  86. {
  87. ScopedLock sl(m_thread_lock);
  88. LOG_PRINT("onThreadStart(%i)", thread_id);
  89. Thread *thread = getThreadFromID(thread_id);
  90. m_thread_tls->set(thread);
  91. thread->updateCoreTLS();
  92. // Set thread state to running for the duration of HOOK_THREAD_START, we'll move it to stalled later on if it didn't have a core
  93. m_thread_state[thread_id].status = Core::RUNNING;
  94. HooksManager::ThreadTime args = { thread_id: thread_id, time: time };
  95. Sim()->getHooksManager()->callHooks(HookType::HOOK_THREAD_START, (UInt64)&args);
  96. // Note: we may have been rescheduled during HOOK_THREAD_START
  97. // (Happens if core was occupied during our createThread() but became free since then)
  98. CLOG("thread", "Start %d", thread_id);
  99. Core *core = thread->getCore();
  100. if (core)
  101. {
  102. // Set the CoreState to 'RUNNING'
  103. core->setState(Core::RUNNING);
  104. PerformanceModel *pm = core->getPerformanceModel();
  105. // If the core already has a later time, we have to wait
  106. time = std::max(time, pm->getElapsedTime());
  107. pm->queuePseudoInstruction(new SpawnInstruction(time));
  108. LOG_PRINT("Setting status[%i] -> RUNNING", thread_id);
  109. m_thread_state[thread_id].status = Core::RUNNING;
  110. HooksManager::ThreadMigrate args = { thread_id: thread_id, core_id: core->getId(), time: time };
  111. Sim()->getHooksManager()->callHooks(HookType::HOOK_THREAD_MIGRATE, (UInt64)&args);
  112. }
  113. else
  114. {
  115. m_thread_state[thread_id].status = Core::STALLED;
  116. m_thread_state[thread_id].stalled_reason = STALL_UNSCHEDULED;
  117. }
  118. if (m_thread_state[thread_id].waiter != INVALID_THREAD_ID)
  119. {
  120. getThreadFromID(m_thread_state[thread_id].waiter)->signal(time);
  121. m_thread_state[thread_id].waiter = INVALID_THREAD_ID;
  122. }
  123. }
  124. void ThreadManager::onThreadExit(thread_id_t thread_id)
  125. {
  126. ScopedLock sl(m_thread_lock);
  127. LOG_ASSERT_ERROR((UInt32)thread_id < m_thread_state.size(), "Thread id out of range: %d", thread_id);
  128. Thread *thread = getThreadFromID(thread_id);
  129. Core *core = thread->getCore();
  130. LOG_ASSERT_ERROR(core != NULL, "Thread ended while not running on a core?");
  131. SubsecondTime time = core->getPerformanceModel()->getElapsedTime();
  132. assert(m_thread_state[thread_id].status == Core::RUNNING);
  133. m_thread_state[thread_id].status = Core::IDLE;
  134. // Implement pthread_join
  135. wakeUpWaiter(thread_id, time);
  136. // Implement CLONE_CHILD_CLEARTID
  137. if (thread->m_os_info.clear_tid)
  138. {
  139. uint32_t zero = 0;
  140. core->accessMemory(Core::NONE, Core::WRITE, thread->m_os_info.tid_ptr, (char*)&zero, sizeof(zero));
  141. SubsecondTime end_time; // ignored
  142. Sim()->getSyscallServer()->futexWake(thread_id, (int*)thread->m_os_info.tid_ptr, 1, FUTEX_BITSET_MATCH_ANY, time, end_time);
  143. }
  144. // Set the CoreState to 'IDLE'
  145. core->setState(Core::IDLE);
  146. m_thread_tls->set(NULL);
  147. thread->setCore(NULL);
  148. thread->updateCoreTLS();
  149. Sim()->getStatsManager()->logEvent(StatsManager::EVENT_THREAD_EXIT, SubsecondTime::MaxTime(), core->getId(), thread_id, 0, 0, "");
  150. HooksManager::ThreadTime args = { thread_id: thread_id, time: time };
  151. Sim()->getHooksManager()->callHooks(HookType::HOOK_THREAD_EXIT, (UInt64)&args);
  152. CLOG("thread", "Exit %d", thread_id);
  153. }
  154. thread_id_t ThreadManager::spawnThread(thread_id_t thread_id, app_id_t app_id)
  155. {
  156. ScopedLock sl(getLock());
  157. SubsecondTime time_start = SubsecondTime::Zero();
  158. if (thread_id != INVALID_THREAD_ID)
  159. {
  160. Thread *thread = getThreadFromID(thread_id);
  161. Core *core = thread->getCore();
  162. time_start = core->getPerformanceModel()->getElapsedTime();
  163. }
  164. Thread *new_thread = createThread_unlocked(app_id, thread_id);
  165. // Insert the request in the thread request queue
  166. ThreadSpawnRequest req = { thread_id, new_thread->getId(), time_start };
  167. m_thread_spawn_list.push(req);
  168. LOG_PRINT("Done with (2)");
  169. return new_thread->getId();
  170. }
  171. thread_id_t ThreadManager::getThreadToSpawn(SubsecondTime &time)
  172. {
  173. ScopedLock sl(getLock());
  174. LOG_ASSERT_ERROR(!m_thread_spawn_list.empty(), "Have no thread to spawn");
  175. ThreadSpawnRequest req = m_thread_spawn_list.front();
  176. m_thread_spawn_list.pop();
  177. time = req.time;
  178. return req.thread_id;
  179. }
  180. void ThreadManager::waitForThreadStart(thread_id_t thread_id, thread_id_t wait_thread_id)
  181. {
  182. ScopedLock sl(getLock());
  183. Thread *self = getThreadFromID(thread_id);
  184. if (m_thread_state[wait_thread_id].status == Core::INITIALIZING)
  185. {
  186. LOG_ASSERT_ERROR(m_thread_state[wait_thread_id].waiter == INVALID_THREAD_ID,
  187. "Multiple threads waiting for thread: %d", wait_thread_id);
  188. m_thread_state[wait_thread_id].waiter = thread_id;
  189. self->wait(getLock());
  190. }
  191. }
  192. void ThreadManager::moveThread(thread_id_t thread_id, core_id_t core_id, SubsecondTime time)
  193. {
  194. Thread *thread = getThreadFromID(thread_id);
  195. CLOG("thread", "Move %d from %d to %d", thread_id, thread->getCore() ? thread->getCore()->getId() : -1, core_id);
  196. if (Core *core = thread->getCore())
  197. core->setState(Core::IDLE);
  198. if (core_id == INVALID_CORE_ID)
  199. {
  200. thread->setCore(NULL);
  201. }
  202. else
  203. {
  204. if (thread->getCore() == NULL)
  205. {
  206. // Unless thread was stalled for sync/futex/..., wake it up
  207. if (
  208. m_thread_state[thread_id].status == Core::STALLED
  209. && m_thread_state[thread_id].stalled_reason == STALL_UNSCHEDULED
  210. )
  211. resumeThread(thread_id, INVALID_THREAD_ID, time);
  212. }
  213. Core *core = Sim()->getCoreManager()->getCoreFromID(core_id);
  214. thread->setCore(core);
  215. if (getThreadState(thread_id) != Core::STALLED)
  216. core->setState(Core::RUNNING);
  217. }
  218. HooksManager::ThreadMigrate args = { thread_id: thread_id, core_id: core_id, time: time };
  219. Sim()->getHooksManager()->callHooks(HookType::HOOK_THREAD_MIGRATE, (UInt64)&args);
  220. }
  221. bool ThreadManager::areAllCoresRunning()
  222. {
  223. // Check if all the cores are running
  224. bool is_all_running = true;
  225. for (SInt32 i = 0; i < (SInt32) m_thread_state.size(); i++)
  226. {
  227. if (m_thread_state[i].status == Core::IDLE)
  228. {
  229. is_all_running = false;
  230. break;
  231. }
  232. }
  233. return is_all_running;
  234. }
  235. void ThreadManager::joinThread(thread_id_t thread_id, thread_id_t join_thread_id)
  236. {
  237. Thread *thread = getThreadFromID(thread_id);
  238. Core *core = thread->getCore();
  239. SubsecondTime end_time;
  240. LOG_PRINT("Joining on thread: %d", join_thread_id);
  241. {
  242. ScopedLock sl(getLock());
  243. if (m_thread_state[join_thread_id].status == Core::IDLE)
  244. {
  245. LOG_PRINT("Not running.");
  246. return;
  247. }
  248. SubsecondTime start_time = core->getPerformanceModel()->getElapsedTime();
  249. LOG_ASSERT_ERROR(m_thread_state[join_thread_id].waiter == INVALID_THREAD_ID,
  250. "Multiple threads joining on thread: %d", join_thread_id);
  251. m_thread_state[join_thread_id].waiter = thread_id;
  252. end_time = stallThread(thread_id, ThreadManager::STALL_JOIN, start_time);
  253. }
  254. if (thread->reschedule(end_time, core))
  255. core = thread->getCore();
  256. core->getPerformanceModel()->queuePseudoInstruction(new SyncInstruction(end_time, SyncInstruction::JOIN));
  257. LOG_PRINT("Exiting join thread.");
  258. }
  259. void ThreadManager::wakeUpWaiter(thread_id_t thread_id, SubsecondTime time)
  260. {
  261. if (m_thread_state[thread_id].waiter != INVALID_THREAD_ID)
  262. {
  263. LOG_PRINT("Waking up core: %d at time: %s", m_thread_state[thread_id].waiter, itostr(time).c_str());
  264. // Resume the 'pthread_join' caller
  265. resumeThread(m_thread_state[thread_id].waiter, thread_id, time);
  266. m_thread_state[thread_id].waiter = INVALID_THREAD_ID;
  267. }
  268. LOG_PRINT("Exiting wakeUpWaiter");
  269. }
  270. void ThreadManager::stallThread_async(thread_id_t thread_id, stall_type_t reason, SubsecondTime time)
  271. {
  272. LOG_PRINT("Core(%i) -> STALLED", thread_id);
  273. m_thread_state[thread_id].status = Core::STALLED;
  274. m_thread_state[thread_id].stalled_reason = reason;
  275. HooksManager::ThreadStall args = { thread_id: thread_id, reason: reason, time: time };
  276. Sim()->getHooksManager()->callHooks(HookType::HOOK_THREAD_STALL, (UInt64)&args);
  277. CLOG("thread", "Stall %d (%s)", thread_id, ThreadManager::stall_type_names[reason]);
  278. }
  279. SubsecondTime ThreadManager::stallThread(thread_id_t thread_id, stall_type_t reason, SubsecondTime time)
  280. {
  281. stallThread_async(thread_id, reason, time);
  282. // When all threads are stalled, we have a deadlock -- unless we let the barrier advance time
  283. // which may wake up threads that are sleeping or waiting on a futex with a timeout value.
  284. while(!anyThreadRunning())
  285. {
  286. Sim()->getClockSkewMinimizationServer()->advance();
  287. }
  288. // It's possible that a HOOK_PERIODIC, called by SkewMinServer::signal(), called by stallThread_async(), woke us up again.
  289. // We will then have been signal()d, but this signal was lost since we weren't in wait()
  290. // If this is the case, don't go to sleep but return our wakeup time immediately
  291. if (m_thread_state[thread_id].status == Core::RUNNING)
  292. return getThreadFromID(thread_id)->getWakeupTime();
  293. else
  294. return getThreadFromID(thread_id)->wait(m_thread_lock);
  295. }
  296. void ThreadManager::resumeThread_async(thread_id_t thread_id, thread_id_t thread_by, SubsecondTime time, void *msg)
  297. {
  298. LOG_PRINT("Core(%i) -> RUNNING", thread_id);
  299. m_thread_state[thread_id].status = Core::RUNNING;
  300. HooksManager::ThreadResume args = { thread_id: thread_id, thread_by: thread_by, time: time };
  301. Sim()->getHooksManager()->callHooks(HookType::HOOK_THREAD_RESUME, (UInt64)&args);
  302. CLOG("thread", "Resume %d (by %d)", thread_id, thread_by);
  303. }
  304. void ThreadManager::resumeThread(thread_id_t thread_id, thread_id_t thread_by, SubsecondTime time, void *msg)
  305. {
  306. // We still have the m_thread_lock, so thread doesn't actually start running again until caller releases this lock
  307. getThreadFromID(thread_id)->signal(time, msg);
  308. resumeThread_async(thread_id, thread_by, time, msg);
  309. }
  310. bool ThreadManager::isThreadRunning(thread_id_t thread_id)
  311. {
  312. return (m_thread_state[thread_id].status == Core::RUNNING);
  313. }
  314. bool ThreadManager::isThreadInitializing(thread_id_t thread_id)
  315. {
  316. return (m_thread_state[thread_id].status == Core::INITIALIZING);
  317. }
  318. bool ThreadManager::anyThreadRunning()
  319. {
  320. for(thread_id_t thread_id = 0; thread_id < (thread_id_t)getNumThreads(); ++thread_id)
  321. {
  322. if (isThreadRunning(thread_id) || isThreadInitializing(thread_id))
  323. return true;
  324. }
  325. return false;
  326. }