1#pragma once
2
3#include "taichi/common/cleanup.h"
4#include "taichi/common/core.h"
5#include <thread>
6
7#if defined(TI_PLATFORM_WINDOWS)
8#include <io.h>
9#include <fcntl.h>
10#else // POSIX
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <unistd.h>
15#endif
16
17namespace taichi {
18
19inline bool try_lock_with_file(const std::string &path) {
20 int fd{-1};
21#if defined(TI_PLATFORM_WINDOWS)
22 // See
23 // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/sopen-s-wsopen-s
24 ::_sopen_s(&fd, path.c_str(), _O_CREAT | _O_EXCL, _SH_DENYNO,
25 _S_IREAD | _S_IWRITE);
26 if (fd != -1)
27 ::_close(fd);
28#else
29 // See https://www.man7.org/linux/man-pages/man2/open.2.html
30 fd = ::open(path.c_str(), O_CREAT | O_EXCL,
31 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
32 if (fd != -1)
33 ::close(fd);
34#endif
35 return fd != -1;
36}
37
38inline bool unlock_with_file(const std::string &path) {
39 return std::remove(path.c_str()) == 0;
40}
41
42inline bool lock_with_file(const std::string &path,
43 int ms_delay = 50,
44 int try_count = 5) {
45 if (try_lock_with_file(path)) {
46 return true;
47 }
48 for (int i = 1; i < try_count; ++i) {
49 std::chrono::milliseconds delay{ms_delay};
50 std::this_thread::sleep_for(delay);
51 if (try_lock_with_file(path)) {
52 return true;
53 }
54 }
55 return false;
56}
57
58inline RaiiCleanup make_unlocker(const std::string &path) {
59 return make_cleanup([&path]() {
60 if (!unlock_with_file(path)) {
61 TI_WARN(
62 "Unlock {} failed. You can remove this .lock file manually and try "
63 "again.",
64 path);
65 }
66 });
67}
68
69} // namespace taichi
70