1515// dep cache without trashing manifest.txt (docs/26 §5.4 V2).
1616
1717module ;
18+ #if defined(_WIN32)
19+ #include < io.h>
20+ #include < windows.h>
21+ #else
1822#include < fcntl.h>
1923#include < sys/file.h>
2024#include < unistd.h>
25+ #endif
2126
2227export module mcpp.bmi_cache;
2328
@@ -184,9 +189,35 @@ stage_into(const CacheKey& key,
184189
185190namespace {
186191
187- // Acquire an exclusive non-blocking flock on <dir>/.lock. Returns the fd on
188- // success (caller closes it to release), or -1 if another mcpp is already
189- // populating this entry — in which case the caller should skip writing.
192+ // Acquire an exclusive non-blocking lock on <dir>/.lock. Returns a handle
193+ // on success, or -1/INVALID_HANDLE if another mcpp is already populating.
194+ #if defined(_WIN32)
195+ // Windows: use LockFileEx on a file handle
196+ HANDLE try_lock_dir (const std::filesystem::path& dir) {
197+ std::error_code ec;
198+ std::filesystem::create_directories (dir, ec);
199+ auto lockPath = dir / " .lock" ;
200+ HANDLE h = CreateFileW (lockPath.wstring ().c_str (),
201+ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
202+ NULL , OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
203+ if (h == INVALID_HANDLE_VALUE) return h;
204+ OVERLAPPED ov = {};
205+ if (!LockFileEx (h, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
206+ 0 , 1 , 0 , &ov)) {
207+ CloseHandle (h);
208+ return INVALID_HANDLE_VALUE;
209+ }
210+ return h;
211+ }
212+
213+ void release_lock (HANDLE h) {
214+ if (h == INVALID_HANDLE_VALUE) return ;
215+ OVERLAPPED ov = {};
216+ UnlockFileEx (h, 0 , 1 , 0 , &ov);
217+ CloseHandle (h);
218+ }
219+ #else
220+ // POSIX: use flock(2)
190221int try_lock_dir (const std::filesystem::path& dir) {
191222 std::error_code ec;
192223 std::filesystem::create_directories (dir, ec);
@@ -205,6 +236,7 @@ void release_lock(int fd) {
205236 ::flock (fd, LOCK_UN);
206237 ::close (fd);
207238}
239+ #endif
208240
209241} // namespace
210242
@@ -214,6 +246,16 @@ populate_from(const CacheKey& key,
214246 const DepArtifacts& arts)
215247{
216248 auto cacheDir = key.dir ();
249+ #if defined(_WIN32)
250+ HANDLE lockHandle = try_lock_dir (cacheDir);
251+ if (lockHandle == INVALID_HANDLE_VALUE) {
252+ return {};
253+ }
254+ struct LockGuard {
255+ HANDLE h;
256+ ~LockGuard () { release_lock (h); }
257+ } guard{ lockHandle };
258+ #else
217259 int lockFd = try_lock_dir (cacheDir);
218260 if (lockFd < 0 ) {
219261 // Another writer holds the lock; treat as success (they'll do it).
@@ -223,6 +265,7 @@ populate_from(const CacheKey& key,
223265 int fd;
224266 ~LockGuard () { release_lock (fd); }
225267 } guard{ lockFd };
268+ #endif
226269
227270 auto cacheBmi = key.bmiDir ();
228271 auto cacheObj = key.objDir ();
0 commit comments