1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12
13 #if defined _WIN32
14
15 #include <cstdio>
16 #include <Windows.h>
17
18 #include "chrono/parallel/ChThreadsWIN32.h"
19 #include "chrono/core/ChLog.h"
20
21 namespace chrono {
22
ChThreadsWIN32(ChThreadConstructionInfo & threadConstructionInfo)23 ChThreadsWIN32::ChThreadsWIN32(ChThreadConstructionInfo& threadConstructionInfo) {
24 makeThreads(threadConstructionInfo);
25 }
26
~ChThreadsWIN32()27 ChThreadsWIN32::~ChThreadsWIN32() {
28 stopSPU();
29
30 // STOP thread fx
31
32 for (int i = 0; i < m_activeSpuStatus.size(); i++)
33 this->sendRequest(1, 0, i);
34
35 for (int i = 0; i < m_activeSpuStatus.size(); i++) {
36 WaitForSingleObject(m_activeSpuStatus[i].m_threadHandle, 1000);
37 CloseHandle(m_activeSpuStatus[i].m_threadHandle);
38 CloseHandle(m_activeSpuStatus[i].m_eventCompletetHandle);
39 CloseHandle(m_activeSpuStatus[i].m_eventStartHandle);
40 }
41 }
42
Thread_no_1(LPVOID lpParam)43 DWORD WINAPI Thread_no_1(LPVOID lpParam) {
44 ChThreadStateWIN32* status = (ChThreadStateWIN32*)lpParam;
45
46 while (1) {
47 WaitForSingleObject(status->m_eventStartHandle, INFINITE);
48 btAssert(status->m_status);
49
50 void* userPtr = status->m_userPtr;
51
52 if (userPtr) {
53 status->m_userThreadFunc(userPtr, status->m_lsMemory);
54 status->m_status = 2;
55 SetEvent(status->m_eventCompletetHandle);
56 } else {
57 // exit Thread
58 break;
59 }
60 }
61
62 return 0;
63 }
64
65 /// send messages to SPUs
sendRequest(uint32_t uiCommand,void * uiUserPtr,uint32_t threadId)66 void ChThreadsWIN32::sendRequest(uint32_t uiCommand, void* uiUserPtr, uint32_t threadId) {
67 ChThreadStateWIN32& spuStatus = m_activeSpuStatus[threadId];
68 btAssert(threadId >= 0);
69 btAssert(threadId < (unsigned)m_activeSpuStatus.size());
70
71 spuStatus.m_commandId = uiCommand;
72 spuStatus.m_status = 1;
73 spuStatus.m_userPtr = uiUserPtr;
74
75 /// fire event to start new task
76 SetEvent(spuStatus.m_eventStartHandle);
77 }
78
79 /// check for messages from SPUs
waitForResponse(unsigned int * puiArgument0,unsigned int * puiArgument1)80 void ChThreadsWIN32::waitForResponse(unsigned int* puiArgument0, unsigned int* puiArgument1) {
81 btAssert(m_activeSpuStatus.size());
82
83 int last = -1;
84
85 DWORD res = WaitForMultipleObjects(m_completeHandles.size(), &m_completeHandles[0], 0, INFINITE);
86 btAssert(res != WAIT_FAILED);
87 last = res - WAIT_OBJECT_0;
88
89 ChThreadStateWIN32& spuStatus = m_activeSpuStatus[last];
90 btAssert(spuStatus.m_threadHandle);
91 btAssert(spuStatus.m_eventCompletetHandle);
92
93 btAssert(spuStatus.m_status > 1);
94 spuStatus.m_status = 0;
95
96 /// need to find an active spu
97 btAssert(last >= 0);
98
99 *puiArgument0 = spuStatus.m_taskId;
100 *puiArgument1 = spuStatus.m_status;
101 }
102
makeThreads(ChThreadConstructionInfo & threadConstructionInfo)103 void ChThreadsWIN32::makeThreads(ChThreadConstructionInfo& threadConstructionInfo) {
104 m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads);
105 m_completeHandles.resize(threadConstructionInfo.m_numThreads);
106
107 uniqueName = threadConstructionInfo.m_uniqueName;
108
109 for (int i = 0; i < threadConstructionInfo.m_numThreads; i++) {
110 ChThreadStateWIN32& spuStatus = m_activeSpuStatus[i];
111
112 LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
113 SIZE_T dwStackSize = threadConstructionInfo.m_threadStackSize;
114 LPTHREAD_START_ROUTINE lpStartAddress = &Thread_no_1;
115 LPVOID lpParameter = &spuStatus;
116 DWORD dwCreationFlags = 0;
117 LPDWORD lpThreadId = 0;
118
119 spuStatus.m_userPtr = 0;
120
121 sprintf(spuStatus.m_eventStartHandleName, "eventStart%s%d", threadConstructionInfo.m_uniqueName, i);
122 spuStatus.m_eventStartHandle = CreateEvent(0, false, false, spuStatus.m_eventStartHandleName);
123
124 sprintf(spuStatus.m_eventCompletetHandleName, "eventComplete%s%d", threadConstructionInfo.m_uniqueName, i);
125 spuStatus.m_eventCompletetHandle = CreateEvent(0, false, false, spuStatus.m_eventCompletetHandleName);
126
127 m_completeHandles[i] = spuStatus.m_eventCompletetHandle;
128 HANDLE handle =
129 CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
130 SetThreadPriority(handle, THREAD_PRIORITY_HIGHEST);
131
132 spuStatus.m_taskId = i;
133 spuStatus.m_commandId = 0;
134 spuStatus.m_status = 0;
135 spuStatus.m_threadHandle = handle;
136 spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc();
137 spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
138 }
139 }
140
flush()141 void ChThreadsWIN32::flush() {
142 int nthreads = m_activeSpuStatus.size();
143
144 while (1) {
145 bool stillrunning = false;
146 for (int i = 0; i < nthreads; i++) {
147 if (m_activeSpuStatus[i].m_status != 0) {
148 stillrunning = true;
149 unsigned int mtaskid;
150 unsigned int mres2;
151 waitForResponse(&mtaskid, &mres2);
152 }
153 }
154 if (!stillrunning)
155 return;
156 }
157 }
158
startSPU()159 void ChThreadsWIN32::startSPU() {
160 }
161
stopSPU()162 void ChThreadsWIN32::stopSPU() {
163 }
164
165 } // end namespace chrono
166
167 #endif
168