-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTeamState.cpp
287 lines (242 loc) · 7.6 KB
/
TeamState.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#include "TeamState.h"
#include "RadeonDevice.h"
#include <stdio.h>
ExternalPtr<TeamRoster> gTeamRoster = MakeExternal<TeamRoster>();
//#pragma mark - RadeonServerThreadLink
RadeonServerThreadLink::RadeonServerThreadLink(port_id clientPort):
ServerThreadLink(clientPort)
{
fTeamState = gTeamRoster.Switch()->ThisTeam(ClientTeam(), true);
auto teamStateLocked = fTeamState.Switch();
teamStateLocked->fThreadLinks.Insert(this);
fAddedToList = true;
InitCompleted();
}
RadeonServerThreadLink::~RadeonServerThreadLink()
{
printf("-RadeonServerThreadLink, team: %" B_PRId32 "\n", ClientTeam());
ExternalRef<TeamState> teamState = fTeamState;
if (!teamState.IsSet()) {
printf("[!] ~RadeonServerThreadLink(): fTeamState == NULL\n");
return;
}
auto teamStateLocked = teamState.Switch();
if (!fRemovedFromList) {
teamStateLocked->fThreadLinks.Remove(this);
fRemovedFromList = true;
}
}
ExternalRef<TeamState> RadeonServerThreadLink::StateFor(team_id team)
{
return gTeamRoster.Switch()->ThisTeam(team, false);
}
ExternalRef<TeamState> RadeonServerThreadLink::ThisState()
{
return StateFor(ClientTeam());
}
//#pragma mark - TeamState
TeamState::TeamState(team_id team):
fTeam(team),
fAddressSpace(new AddressSpace(), true),
fCsSeq(0),
fLastCsSeq(0)
{
printf("+TeamState(%" B_PRId32 ")\n", fTeam);
fVirtMemPool.Register(0, 0x200000);
}
TeamState::~TeamState()
{
printf("-TeamState(%" B_PRId32 ")\n", fTeam);
}
void TeamState::FirstReferenceAcquired()
{
atomic_or((int32*)&fFlags.val, Flags{.reacquired = true}.val);
}
void TeamState::LastReferenceReleased()
{
Flags oldFlags {.val = atomic_or((int32*)&fFlags.val, Flags{.finalized = true}.val)};
auto teamRoster = gTeamRoster.Switch();
if (!oldFlags.finalized) {
auto it = teamRoster->fTeamStates.find(fTeam);
if (it == teamRoster->fTeamStates.end()) abort();
teamRoster->fTeamStates.erase(it);
}
oldFlags.val = atomic_and((int32*)&fFlags.val, ~Flags{.reacquired = true}.val);
if (!oldFlags.reacquired) {
RefObject::LastReferenceReleased();
}
}
void TeamState::Terminate()
{
for (;;) {
RadeonServerThreadLink *threadLink = fThreadLinks.First();
if (threadLink == NULL) break;
threadLink->fRemovedFromList = true;
fThreadLinks.Remove(threadLink);
threadLink->Close();
}
}
int32 TeamState::RegisterHandle(const Handle &handleObj)
{
return fHandles.Register(handleObj);
}
status_t TeamState::FreeHandle(int32 handle)
{
return fHandles.Free(handle);
}
TeamState::Handle TeamState::ThisHandle(int32 handle)
{
return fHandles.This(handle);
}
BReferenceable *TeamState::ThisHandle(int32 handle, HandleType type)
{
const Handle &handleObj = fHandles.This(handle);
if (handleObj.type != HandleType::buffer) return NULL;
BReferenceable *ref = handleObj.ref.Get();
ref->AcquireReference();
return ref;
}
//#pragma mark - Buffers
int32 TeamState::AllocBuffer(MemoryDomain domain, uint64 size, uint64 alignment, uint32 flags, area_id area, uint64 offset)
{
void *clonedAreaAdr = NULL;
// TODO: read only area support
AreaDeleter clonedArea;
if (area >= B_OK) {
clonedArea.SetTo(clone_area("userptr", &clonedAreaAdr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, area));
CheckRet(clonedArea.Get());
area_info info;
CheckRet(get_area_info(clonedArea.Get(), &info));
if (size < offset || info.size - offset < size) return B_ERROR;
switch (info.lock) {
case B_FULL_LOCK:
case B_CONTIGUOUS:
case B_LOMEM:
case B_32_BIT_FULL_LOCK:
case B_32_BIT_CONTIGUOUS:
break;
default:
return B_ERROR; // area physical memory must be locked
}
}
BReference<BufferObject> buffer = gDevice.MemMgr().Switch()->Alloc(domain, size, alignment, flags, clonedArea.Get(), offset);
if (!buffer.IsSet()) {
printf("buffer alloc failed, domain: %d, size: %#" B_PRIx64 "\n", (int)domain, size);
return B_NO_MEMORY;
}
clonedArea.Detach();
return RegisterHandle(Handle{.type = HandleType::buffer, .ref = buffer});
}
BReference<BufferObject> TeamState::ThisBuffer(int32 handle)
{
const Handle &handleObj = fHandles.This(handle);
if (handleObj.type != HandleType::buffer) return NULL;
return BReference<BufferObject>((BufferObject*)handleObj.ref.Get(), false);
}
status_t TeamState::Map(uint64 virtAdr, int32 handle, uint64 offset, uint64 size, uint32 flags)
{
//printf("\nMap(%#" B_PRIx64 ", %" B_PRId32 ", %#" B_PRIx64 ", %#" B_PRIx64 ")\n", virtAdr, handle, offset, size);
(void)flags;
BReference<BufferObject> buffer = ThisBuffer(handle);
if (!buffer.IsSet()) return B_ERROR;
status_t res = fAddressSpace->Map(buffer, virtAdr, offset, size);
if (res < B_OK) return res;
return res;
}
status_t TeamState::Unmap(uint64 virtAdr, int32 handle, uint64 offset, uint64 size, uint32 flags)
{
(void)flags;
//printf("\nUnmap(%#" B_PRIx64 ", %" B_PRId32 ", %#" B_PRIx64 ", %#" B_PRIx64 ")\n", virtAdr, handle, offset, size);
BReference<BufferObject> buffer = ThisBuffer(handle);
if (!buffer.IsSet()) return B_ERROR;
return fAddressSpace->Unmap(buffer, virtAdr, offset, size);
}
status_t TeamState::CpuMap(void *&adr, int32 handle, uint64 offset, uint64 size, uint32 flags)
{
(void)flags;
BReference<BufferObject> buffer = ThisBuffer(handle);
if (!buffer.IsSet()) return B_ERROR;
return gDevice.MemMgr().Switch()->CpuMap(adr, buffer, offset, size);
}
status_t TeamState::CpuUnmap(void *adr, int32 handle, uint64 offset, uint64 size, uint32 flags)
{
(void)adr;
(void)handle;
(void)offset;
(void)size;
(void)flags;
return B_OK;
}
//#pragma mark - Syncobjs
int32 TeamState::CreateSyncobj(Syncobj::CreateFlags flags)
{
SyncobjRef syncobj(new Syncobj(flags), true);
return RegisterHandle(Handle{.type = HandleType::syncobj, .ref = syncobj});
}
SyncobjRef TeamState::ThisSyncobj(int32 handle)
{
const Handle &handleObj = fHandles.This(handle);
if (handleObj.type != HandleType::syncobj) return NULL;
return SyncobjRef((Syncobj*)handleObj.ref.Get(), false);
}
void TeamState::DumpSyncobjs()
{
for (auto it = fHandles.Handles().begin(); it != fHandles.Handles().end(); it++) {
int32 handle = it->first;
const Handle &handleObj = it->second;
if (handleObj.type == HandleType::syncobj) {
SyncobjRef syncobj((Syncobj*)handleObj.ref.Get(), false);
printf("%" B_PRId32 "(%p): ", handle, syncobj.Get());
syncobj->Dump();
}
}
printf("\n");
}
//#pragma mark - Command submissions
status_t TeamState::ScheduleCS(uint64 &handle, CommandSubmission *cs)
{
if (GetDomain() != CurrentDomain()) {
printf("[!] Domain() != CurrentDomain()\n");
abort();
}
handle = fLastCsSeq++;
cs->seq = handle;
//printf("TeamState::ScheduleCS() -> %" B_PRIu64 "\n", handle);
CheckRet(cs->Schedule());
fCmdSubs.emplace(handle, cs);
return B_OK;
}
status_t TeamState::WaitCS(uint64 handle)
{
//printf("TeamState::WaitCS(%" B_PRIu64 ")\n", handle);
if ((int32)fCsSeq - (int32)handle >= 0) return B_OK;
auto it = fCmdSubs.find((uint32)handle);
if (it == fCmdSubs.end()) return B_ERROR;
CommandSubmission *cs = it->second;
if (auto ring = ExternalPtr<RadeonRingBuffer>(cs->fence->Ring()).Switch()) {
CheckRet(cs->fence->Wait());
}
return B_OK;
}
//#pragma mark - TeamRoster
ExternalRef<TeamState> TeamRoster::ThisTeam(team_id team, bool create)
{
auto it = fTeamStates.find(team);
if (it == fTeamStates.end()) {
if (!create) return NULL;
ExternalRef<TeamState> newTeamState(MakeExternal<TeamState>(team), true);
fTeamStates.emplace(team, newTeamState);
return newTeamState;
}
return ExternalRef<TeamState>(it->second, false);
}
int32 TeamRoster::CountTeams()
{
return fTeamStates.size();
}
void TeamRoster::ListTeams(bool (*Handler)(ExternalRef<TeamState> ts, void *arg), void *arg)
{
for (auto it = fTeamStates.begin(); it != fTeamStates.end(); it++) {
if (!Handler(it->second, arg)) return;
}
}