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