Skip to content

Commit

Permalink
Bug 1933284 [wpt PR 49359] - [shared storage] Implement 'with_lock' m…
Browse files Browse the repository at this point in the history
…odifier options for Window and SharedStorageWorklet, a=testonly

Automatic update from web-platform-tests
[shared storage] Implement 'with_lock' modifier options for Window and SharedStorageWorklet

Implement the { withLock: <lock resource name> } option for the
modifier methods for Window and SharedStorageWorklet context. The
SharedStorageLockManager manages the state of the locks and locked
requests. It acts as the LockRequest receiver to listen to Granted()
calls to resolve those requests. The locks uses the shared storage
origin as the partitioning origin, and thus can interact with the
regular Web Locks API (i.e. navigator.locks.request()) from within
the shared storage worklet.

The locking function is gated behind
features::kSharedStorageWebLocks, which is checked in the browser
process in SharedStorageLockManager::SharedStorageUpdate().

Explainer PR(s):
- WICG/shared-storage#199
- WICG/shared-storage#205

Bug: 373899210
Change-Id: I7003d392076a65a9ff2d277f9f0c2791436d2f68
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6020796
Reviewed-by: Giovanni Ortuno Urquidi <ortuno@chromium.org>
Commit-Queue: Yao Xiao <yaoxia@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1387751}

--

wpt-commits: 7e168195e3629f88bef6293c18ae8674f90893fd
wpt-pr: 49359
  • Loading branch information
yaoxiachromium authored and moz-wptsync-bot committed Nov 28, 2024
1 parent 04d3bf1 commit d65f615
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,39 @@ class GetWaitIncrementWithinLockOperation {
}
}

class GetWaitSetWithinLockOperation {
async run(urls, data) {
if (data && data.hasOwnProperty('key') && data.hasOwnProperty('lock_name')
&& data.hasOwnProperty('append_letter')) {
await navigator.locks.request(data['lock_name'], async (lock) => {
let value_read = await sharedStorage.get(data['key']);

if (value_read === undefined) {
value_read = "";
}

await busyWaitMs(500);

await sharedStorage.set(data['key'], value_read + data['append_letter']);
});

return 1;
}
return -1;
}
}

class AppendWithLockOptionOperation {
async run(urls, data) {
if (data && data.hasOwnProperty('key') && data.hasOwnProperty('lock_name')
&& data.hasOwnProperty('append_letter')) {
sharedStorage.append(data['key'], data['append_letter'], {withLock: data['lock_name']});
return 1;
}
return -1;
}
}

register('test-url-selection-operation', TestURLSelectionOperation);
register('test-url-selection-operation-2', TestURLSelectionOperationTwo);
register('test-slow-url-selection-operation', TestSlowURLSelectionOperation);
Expand All @@ -131,3 +164,5 @@ register('verify-key-value', VerifyKeyValue);
register('verify-key-not-found', VerifyKeyNotFound);
register('verify-interest-groups', VerifyInterestGroups);
register('get-wait-increment-within-lock', GetWaitIncrementWithinLockOperation);
register('get-wait-set-within-lock', GetWaitSetWithinLockOperation);
register('append-with-lock-option', AppendWithLockOptionOperation);
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<script src="/shared-storage/resources/util.js"></script>
<script src="/fenced-frame/resources/utils.js"></script>

<body>
<script>
'use strict';

promise_test(async t => {
let worklet = await sharedStorage.createWorklet('resources/simple-module.js');

const ancestor_key = token();
let url0 = generateURL("/shared-storage/resources/frame0.html",
[ancestor_key]);
let url1 = generateURL("/shared-storage/resources/frame1.html",
[ancestor_key]);

// Invoke `selectURL()` to perform the following steps:
// 1. Acquires the lock.
// 2. Reads the current value at the given key.
// 3. Waits for 500ms.
// 4. Sets the shared storage value to the read value appended with the given letter.
// 5. Releases the lock.
//
// After 100ms, invoke `sharedStorage.append()` with the same lock and the
// same letter to append.
//
// Expected behavior: After both of them finish, the value at the given key
// should contain the letter repeated twice.
//
// This demonstrates that the `withLock` option is effective, preventing the
// `append()` method interfering with the "get and set" operation. If the lock
// were not used, the final value would likely be a single letter.
//
// Note: This test remains valid even if the `append()` call happens outside
// the critical section protected by the lock within the worklet. The test
// effectively demonstrates mutual exclusion as long as there's a reasonable
// chance for `append()` to occur while the worklet is still running.
let select_url_result = await worklet.selectURL(
"get-wait-set-within-lock",
[{url: url0}, {url: url1}],
{data: {'key': 'key',
'lock_name': 'lock1',
'append_letter': 'a'},
resolveToConfig: true});

// Busy wait for 100ms.
const startWaitTime = Date.now();
while (Date.now() - startWaitTime < 100) {}

sharedStorage.append('key', 'a', {withLock: 'lock1'});

attachFencedFrame(select_url_result, 'opaque-ads');
const result = await nextValueFromServer(ancestor_key);
assert_equals(result, "frame1_loaded");

await verifyKeyValueForOrigin('key', 'aa', location.origin);

await deleteKeyForOrigin('key', location.origin);
}, 'Test for withLock option in a Window context');

</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<script src="/shared-storage/resources/util.js"></script>
<script src="/fenced-frame/resources/utils.js"></script>

<body>
<script>
'use strict';

promise_test(async t => {
let worklet1 = await sharedStorage.createWorklet('resources/simple-module.js');
let worklet2 = await sharedStorage.createWorklet('resources/simple-module.js');

const ancestor_key1 = token();
let url1_0 = generateURL("/shared-storage/resources/frame0.html",
[ancestor_key1]);
let url1_1 = generateURL("/shared-storage/resources/frame1.html",
[ancestor_key1]);

const ancestor_key2 = token();
let url2_0 = generateURL("/shared-storage/resources/frame0.html",
[ancestor_key2]);
let url2_1 = generateURL("/shared-storage/resources/frame1.html",
[ancestor_key2]);

// Invoke `selectURL()` to perform the following steps:
// 1. Acquires the lock.
// 2. Reads the current value at the given key.
// 3. Waits for 500ms.
// 4. Sets the shared storage value to the read value appended with the given letter.
// 5. Releases the lock.
//
// In parallel, invoke another `selectURL()`, which subsequently invokes
// `sharedStorage.append()` with the same lock and the same letter to append.
//
// Expected behavior: After both of them finish, the value at the given key
// should contain the letter repeated twice.
//
// Note: This test remains valid even if the `append()` call happens outside
// the critical section protected by the lock within the worklet. The test
// effectively demonstrates mutual exclusion as long as there's a reasonable
// chance for `append()` to occur while the worklet is still running.
let select_url_result1 = await worklet1.selectURL(
"get-wait-set-within-lock",
[{url: url1_0}, {url: url1_1}],
{data: {'key': 'key',
'lock_name': 'lock1',
'append_letter': 'a'},
resolveToConfig: true});

let select_url_result2 = await worklet2.selectURL(
"append-with-lock-option",
[{url: url2_0}, {url: url2_1}],
{data: {'key': 'key',
'lock_name': 'lock1',
'append_letter': 'a'},
resolveToConfig: true});

attachFencedFrame(select_url_result1, 'opaque-ads');
const result1 = await nextValueFromServer(ancestor_key1);
assert_equals(result1, "frame1_loaded");

attachFencedFrame(select_url_result2, 'opaque-ads');
const result2 = await nextValueFromServer(ancestor_key2);
assert_equals(result2, "frame1_loaded");

await verifyKeyValueForOrigin('key', 'aa', location.origin);

await deleteKeyForOrigin('key', location.origin);
}, 'Test for withLock option in a SharedStorageWorklet context');

</script>
</body>
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
assert_equals(result2, "frame1_loaded");

await verifyKeyValueForOrigin('key', '2', location.origin);

await deleteKeyForOrigin('key', location.origin);
}, 'Basic test for Web Locks API in the shared storage worklet');

</script>
Expand Down

0 comments on commit d65f615

Please sign in to comment.