Skip to content

Commit e1c063b

Browse files
fix(sysman): fixes multithread access issue with FSAccess
Related-To: NEO-9720 Signed-off-by: Kulkarni, Ashwin Kumar <[email protected]> Source: b33d995
1 parent 033885c commit e1c063b

File tree

6 files changed

+81
-62
lines changed

6 files changed

+81
-62
lines changed

level_zero/sysman/source/shared/linux/sysman_fs_access_interface.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ void FdCacheInterface::eraseLeastUsedEntryFromCache() {
4545
}
4646

4747
int FdCacheInterface::getFd(std::string file) {
48-
std::unique_lock<std::mutex> lock(fdMutex);
4948
int fd = -1;
5049
if (fdMap.find(file) == fdMap.end()) {
5150
fd = NEO::SysCalls::open(file.c_str(), O_RDONLY);
@@ -72,6 +71,7 @@ FdCacheInterface::~FdCacheInterface() {
7271

7372
template <typename T>
7473
ze_result_t FsAccessInterface::readValue(const std::string file, T &val) {
74+
auto lock = this->obtainMutex();
7575

7676
std::string readVal(64, '\0');
7777
int fd = pFdCacheInterface->getFd(file);
@@ -303,6 +303,10 @@ bool FsAccessInterface::directoryExists(const std::string path) {
303303
return true;
304304
}
305305

306+
std::unique_lock<std::mutex> FsAccessInterface::obtainMutex() {
307+
return std::unique_lock<std::mutex>(this->fsMutex);
308+
}
309+
306310
// Procfs Access
307311
ProcFsAccessInterface::ProcFsAccessInterface() = default;
308312
ProcFsAccessInterface::~ProcFsAccessInterface() = default;

level_zero/sysman/source/shared/linux/sysman_fs_access_interface.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ class FdCacheInterface {
3232
std::map<std::string, std::pair<int, uint32_t>> fdMap = {};
3333

3434
private:
35-
std::mutex fdMutex{};
3635
void eraseLeastUsedEntryFromCache();
3736
};
3837

@@ -65,11 +64,13 @@ class FsAccessInterface {
6564

6665
protected:
6766
FsAccessInterface();
67+
MOCKABLE_VIRTUAL std::unique_lock<std::mutex> obtainMutex();
6868

6969
private:
7070
template <typename T>
7171
ze_result_t readValue(const std::string file, T &val);
7272
std::unique_ptr<FdCacheInterface> pFdCacheInterface = nullptr;
73+
std::mutex fsMutex{};
7374
};
7475

7576
class ProcFsAccessInterface : private FsAccessInterface {

level_zero/sysman/test/unit_tests/sources/linux/test_sysman.cpp

+33-29
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,39 @@ TEST_F(SysmanDeviceFixture, GivenSysfsAccessClassAndIntegerWhenCallingReadOnMult
219219
delete tempSysfsAccess;
220220
}
221221

222+
TEST_F(SysmanDeviceFixture, GivenValidMockMutexFsAccessWhenCallingReadThenMutexLockCounterMatchesNumberOfReadCalls) {
223+
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, [](const char *pathname, int flags) -> int {
224+
return 1;
225+
});
226+
227+
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
228+
std::string value = "123";
229+
memcpy(buf, value.data(), value.size());
230+
return value.size();
231+
});
232+
233+
class MockMutexFsAccess : public L0::Sysman::FsAccessInterface {
234+
public:
235+
uint32_t mutexLockCounter = 0;
236+
std::unique_lock<std::mutex> obtainMutex() override {
237+
mutexLockCounter++;
238+
std::unique_lock<std::mutex> mutexLock = L0::Sysman::FsAccessInterface::obtainMutex();
239+
EXPECT_TRUE(mutexLock.owns_lock());
240+
return mutexLock;
241+
}
242+
};
243+
MockMutexFsAccess *tempFsAccess = new MockMutexFsAccess();
244+
std::string fileName = {};
245+
uint32_t iVal32;
246+
uint32_t testReadCount = 10;
247+
for (uint32_t i = 0; i < testReadCount; i++) {
248+
fileName = "mockfile" + std::to_string(i) + ".txt";
249+
EXPECT_EQ(ZE_RESULT_SUCCESS, tempFsAccess->read(fileName, iVal32));
250+
}
251+
EXPECT_EQ(tempFsAccess->mutexLockCounter, testReadCount);
252+
delete tempFsAccess;
253+
}
254+
222255
TEST(FdCacheTest, GivenValidFdCacheWhenCallingGetFdOnSameFileThenVerifyCacheIsUpdatedProperly) {
223256

224257
class MockFdCache : public FdCache {
@@ -257,35 +290,6 @@ TEST(FdCacheTest, GivenValidFdCacheWhenCallingGetFdOnSameFileThenVerifyCacheIsUp
257290
EXPECT_EQ(pFdCache->fdMap.end(), pFdCache->fdMap.find("mockfile9.txt"));
258291
}
259292

260-
TEST(FdCacheTest, GivenValidFdCacheWhenCallingGetFdOnMultipleFilesManyTimesThenVerifyCacheIsUpdatedCorrectly) {
261-
262-
class MockFdCache : public FdCacheInterface {
263-
public:
264-
using FdCacheInterface::fdMap;
265-
};
266-
267-
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, [](const char *pathname, int flags) -> int {
268-
return 1;
269-
});
270-
271-
std::unique_ptr<MockFdCache> pFdCache = std::make_unique<MockFdCache>();
272-
std::string fileName = {};
273-
for (auto i = 0; i < L0::Sysman::FdCacheInterface::maxSize; i++) {
274-
fileName = "mockfile" + std::to_string(i) + ".txt";
275-
int j = i + 1;
276-
while (j--) {
277-
EXPECT_LE(0, pFdCache->getFd(fileName));
278-
}
279-
}
280-
281-
// replace a least referred file and add new file
282-
fileName = "mockfile100.txt";
283-
EXPECT_LE(0, pFdCache->getFd(fileName));
284-
285-
// Verify cache doesn't have an element that is accessed less number of times.
286-
EXPECT_EQ(pFdCache->fdMap.end(), pFdCache->fdMap.find("mockfile0.txt"));
287-
}
288-
289293
TEST(FdCacheTest, GivenValidFdCacheWhenClearingCacheThenVerifyProperFdsAreClosedAndCacheIsUpdatedProperly) {
290294

291295
class MockFdCache : public FdCache {

level_zero/tools/source/sysman/linux/fs_access.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ void FdCache::eraseLeastUsedEntryFromCache() {
4646
}
4747

4848
int FdCache::getFd(std::string file) {
49-
std::unique_lock<std::mutex> lock(fdMutex);
5049
int fd = -1;
5150
if (fdMap.find(file) == fdMap.end()) {
5251
fd = NEO::SysCalls::open(file.c_str(), O_RDONLY);
@@ -73,6 +72,7 @@ FdCache::~FdCache() {
7372

7473
template <typename T>
7574
ze_result_t FsAccess::readValue(const std::string file, T &val) {
75+
auto lock = this->obtainMutex();
7676

7777
std::string readVal(64, '\0');
7878
int fd = pFdCache->getFd(file);
@@ -308,6 +308,10 @@ bool FsAccess::directoryExists(const std::string path) {
308308
return true;
309309
}
310310

311+
std::unique_lock<std::mutex> FsAccess::obtainMutex() {
312+
return std::unique_lock<std::mutex>(this->fsMutex);
313+
}
314+
311315
// Procfs Access
312316
const std::string ProcfsAccess::procDir = "/proc/";
313317
const std::string ProcfsAccess::fdDir = "/fd/";

level_zero/tools/source/sysman/linux/fs_access.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class FdCache {
4242
std::map<std::string, std::pair<int, uint32_t>> fdMap = {};
4343

4444
private:
45-
std::mutex fdMutex{};
4645
void eraseLeastUsedEntryFromCache();
4746
};
4847

@@ -79,11 +78,13 @@ class FsAccess {
7978
FsAccess();
8079
decltype(&NEO::SysCalls::access) accessSyscall = NEO::SysCalls::access;
8180
decltype(&stat) statSyscall = stat;
81+
MOCKABLE_VIRTUAL std::unique_lock<std::mutex> obtainMutex();
8282

8383
private:
8484
template <typename T>
8585
ze_result_t readValue(const std::string file, T &val);
8686
std::unique_ptr<FdCache> pFdCache = nullptr;
87+
std::mutex fsMutex{};
8788
};
8889

8990
class ProcfsAccess : private FsAccess {

level_zero/tools/test/unit_tests/sources/sysman/linux/test_sysman.cpp

+34-29
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,40 @@ TEST_F(SysmanDeviceFixture, GivenSysfsAccessClassAndIntegerWhenCallingReadThenSu
414414
delete tempSysfsAccess;
415415
}
416416

417+
TEST_F(SysmanDeviceFixture, GivenValidMockMutexFsAccessWhenCallingReadThenMutexLockCounterMatchesNumberOfReadCalls) {
418+
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, [](const char *pathname, int flags) -> int {
419+
return 1;
420+
});
421+
422+
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
423+
std::string value = "123";
424+
memcpy(buf, value.data(), value.size());
425+
return value.size();
426+
});
427+
428+
class MockMutexFsAccess : public L0::FsAccess {
429+
public:
430+
uint32_t mutexLockCounter = 0;
431+
std::unique_lock<std::mutex> obtainMutex() override {
432+
mutexLockCounter++;
433+
std::unique_lock<std::mutex> mutexLock = L0::FsAccess::obtainMutex();
434+
EXPECT_TRUE(mutexLock.owns_lock());
435+
return mutexLock;
436+
}
437+
};
438+
439+
MockMutexFsAccess *tempFsAccess = new MockMutexFsAccess();
440+
std::string fileName = {};
441+
uint32_t iVal32;
442+
uint32_t testReadCount = 10;
443+
for (uint32_t i = 0; i < testReadCount; i++) {
444+
fileName = "mockfile" + std::to_string(i) + ".txt";
445+
EXPECT_EQ(ZE_RESULT_SUCCESS, tempFsAccess->read(fileName, iVal32));
446+
}
447+
EXPECT_EQ(tempFsAccess->mutexLockCounter, testReadCount);
448+
delete tempFsAccess;
449+
}
450+
417451
TEST_F(SysmanDeviceFixture, GivenSysfsAccessClassAndOpenSysCallFailsWhenCallingReadThenFailureIsReturned) {
418452

419453
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, [](const char *pathname, int flags) -> int {
@@ -540,35 +574,6 @@ TEST(FdCacheTest, GivenValidFdCacheWhenClearingCacheThenVerifyProperFdsAreClosed
540574
delete pFdCache;
541575
}
542576

543-
TEST(FdCacheTest, GivenValidFdCacheWhenCallingGetFdOnMultipleFilesManyTimesThenVerifyCacheIsUpdatedCorrectly) {
544-
545-
class MockFdCache : public FdCache {
546-
public:
547-
using FdCache::fdMap;
548-
};
549-
550-
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, [](const char *pathname, int flags) -> int {
551-
return 1;
552-
});
553-
554-
std::unique_ptr<MockFdCache> pFdCache = std::make_unique<MockFdCache>();
555-
std::string fileName = {};
556-
for (auto i = 0; i < L0::FdCache::maxSize; i++) {
557-
fileName = "mockfile" + std::to_string(i) + ".txt";
558-
int j = i + 1;
559-
while (j--) {
560-
EXPECT_LE(0, pFdCache->getFd(fileName));
561-
}
562-
}
563-
564-
// replace a least referred file and add new file
565-
fileName = "mockfile100.txt";
566-
EXPECT_LE(0, pFdCache->getFd(fileName));
567-
568-
// Verify cache doesn't have an element that is accessed less number of times.
569-
EXPECT_EQ(pFdCache->fdMap.end(), pFdCache->fdMap.find("mockfile0.txt"));
570-
}
571-
572577
TEST_F(SysmanDeviceFixture, GivenSysfsAccessClassAndUnsignedIntegerWhenCallingReadThenSuccessIsReturned) {
573578

574579
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, [](const char *pathname, int flags) -> int {

0 commit comments

Comments
 (0)