&& requestedMode === 'shared') ) {
storeAndNotify(whichOp, 0);
existing.mode = requestedMode/* ??? */;
- fh.lockType = lockType;
+ fh.xLock = lockType;
return 0 /* Already held at required or higher level */;
}
/*
Upgrade path: we must release shared and acquire exclusive.
This transition is NOT atomic in Web Locks API.
*/
- if( 0 ){
+ if( 1 ){
/* Except that it _effectively_ is atomic if we don't call
closeSyncHandle(fh), as no other worker can lock that
- until we let it go. */
+ until we let it go. But we can't do that without leading
+ to a deadly embrace, so... */
await closeSyncHandle(fh);
}
existing.resolveRelease();
}
const oldLockType = fh.xLock;
- let didNotify = false;
return new Promise((resolveWaitLoop) => {
//error("xLock() initial promise entered...");
navigator.locks.request(lockName, { mode: requestedMode }, async (lock) => {
//error("xLock() Web Lock entered.", fh);
- fh.xLock = lockType;
+ fh.xLock = lockType/*must be set before getSyncHandle() is called*/;
__implicitLocks.delete(fid);
- if( 1 ){
+ let rc = 0;
+ try{
/* Make ONE attempt to get the handle, but with a
- higher-than-default retry-wait time. */
- await getSyncHandle(fh, 'xLock', 1000, 5);
- }else{
- /* Try to get a lock until either we get one or trying to
- results in a "not found" error (see getSyncHandle() docs). */
- while( !fh.syncHandle ){
- try{
- await getSyncHandle(fh, 'xLock', 1000, 3);
- }catch(e){
- const rc = GetSyncHandleError.convertRc(e, 0);
- if( rc === state.sq3Codes.SQLITE_CANTOPEN ){
- /* File was deleted - see getSyncHandle() */
- throw e;
- }
- error("xLock() still waiting to unlock SyncAccessHandle",fh);
- }
- }
+ higher-than-default retry-wait. */
+ await getSyncHandle(fh, 'xLock', 317, 5);
+ }catch(e){
+ fh.xLock = oldLockType;
+ state.s11n.storeException(1, e);
+ rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_BUSY);
}
- error("xLock() SAH acquired.", fh);
- const releasePromise = new Promise((resolveRelease) => {
- __activeWebLocks[fid] = { mode: requestedMode, resolveRelease };
- });
- didNotify = true;
- storeAndNotify(whichOp, 0) /* Unblock the C side */;
+ const releasePromise = rc
+ ? undefined
+ : new Promise((resolveRelease) => {
+ __activeWebLocks[fid] = { mode: requestedMode, resolveRelease };
+ });
+ storeAndNotify(whichOp, rc) /* Unblock the C side */;
resolveWaitLoop(0) /* Unblock waitLoop() */;
await releasePromise; // Hold the lock until xUnlock
- }).catch(e=>{
- /**
- We have(?) a potential deadlock situation: if the above
- throws, we can't just blindly storeAndNotify() here to
- unlock the C side, as it might interfere with an
- unrelated operation. The `didNotify` check here assumes
- that any exception which can be thrown will happen before
- the above `didNotify=true`. e.g. getSyncHandle() can
- throw. Apropos: we probably need to be able to configure
- the async side with busy timeout values, and try until
- that limit is reached, or tell it to wait indefinitely.
-
- Because waitLoop() is `await`ing on this Promise, we can
- be sure that the following storeAndNotify() is not
- crossing wires with a different operation.
- */
- fh.xLock = oldLockType;
- error("Exception acquiring Web Lock", e);
- if( !didNotify ){
- state.s11n.storeException(1, e);
- const rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_LOCK);
- storeAndNotify(whichOp, rc);
- }
- throw e /* what else can we do? */;
- })
+ });
});
};
+ const wlCloseHandle = async(fh)=>{
+ let rc = 0;
+ try{
+ await closeSyncHandle(fh);
+ }catch(e){
+ state.s11n.storeException(1,e);
+ rc = state.sq3Codes.SQLITE_IOERR_UNLOCK;
+ }
+ return rc;
+ };
+
vfsAsyncImpls.xUnlock = async function(fid/*sqlite3_file pointer*/,
lockType/*SQLITE_LOCK_...*/){
const fh = __openFiles[fid];
const existing = __activeWebLocks[fid];
if( !existing ){
- await closeSyncHandle(fh);
- storeAndNotify('xUnlock', 0);
- return 0;
+ const rc = await wlCloseHandle(fh);
+ storeAndNotify('xUnlock', rc);
+ return rc;
}
error("xUnlock()",fid, lockType, fh);
let rc = 0;
if( lockType === state.sq3Codes.SQLITE_LOCK_NONE ){
/* SQLite usually unlocks all the way to NONE */
+ rc = await wlCloseHandle(fh);
existing.resolveRelease();
delete __activeWebLocks[fid];
- try {await closeSyncHandle(fh)}
- catch(e){
- state.s11n.storeException(1,e);
- rc = state.sq3Codes.SQLITE_IOERR_UNLOCK;
- }
+ fh.xLock = lockType;
}else if( lockType === state.sq3Codes.SQLITE_LOCK_SHARED
&& existing.mode === 'exclusive' ){
/* downgrade Exclusive -> Shared */
- existing.resolveRelease();
- delete __activeWebLocks[fid];
- return vfsAsyncImpls.xLock(fid, lockType, true);
+ rc = await wlCloseHandle(fh);
+ if( 0===rc ){
+ fh.xLock = lockType;
+ existing.resolveRelease();
+ delete __activeWebLocks[fid];
+ return vfsAsyncImpls.xLock(fid, lockType, true);
+ }
}else{
/* ??? */
error("xUnlock() unhandled condition", fh);
}
storeAndNotify('xUnlock', rc);
- if( 0===rc ) fh.lockType = lockType;
return 0;
}
-C Correct\san\sinternal\sdoc\sfalsehood.
-D 2026-03-06T16:15:32.423
+C This\sone\sreliably\sruns\s5\sworkers.\sChecking\sin\sbefore\ssubsequent\scleanups\sand\sdebug\soutput\sremoval\sbreak\sit.
+D 2026-03-06T17:10:28.455
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938
F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc
-F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js fd41c554fa0f25770841f4973eeaeda78db5fd9c24b2cbe7c62ce43bfae89840
+F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b3235922c15ee9b92a5424e34580bf16cb971adf23559c9e7119d563b8da2fe9
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P d4e8583e2e80665adfe4e814adb6c219936af1dcac4105795045cb1a7b1e4864
-R 88b88687281dda4abda2f12f0e145b46
+P 53aa080e357d7a2ffeab68a3584fda43d51ecef3dc8a1d46dd32392ae4f9740c
+R fcfb0bfb06d58bd7f0d57908763a15cf
U stephan
-Z de5c6fc88fd27ce91eec8f28640e7eb1
+Z 62318d6c194878a798365e388df66b6b
# Remove this line to create a well-formed Fossil manifest.