diff options
author | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-05-10 18:07:05 +0200 |
---|---|---|
committer | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-05-10 18:18:52 +0200 |
commit | 01937dc9d5215ef96ce756e3ccda51bf29032f58 (patch) | |
tree | 609ec5bb48c692796520f7982c06b30633038588 /common/lock.mjs | |
download | browser-extension-01937dc9d5215ef96ce756e3ccda51bf29032f58.tar.gz browser-extension-01937dc9d5215ef96ce756e3ccda51bf29032f58.zip |
initial commit
Diffstat (limited to 'common/lock.mjs')
-rw-r--r-- | common/lock.mjs | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/common/lock.mjs b/common/lock.mjs new file mode 100644 index 0000000..596dd9c --- /dev/null +++ b/common/lock.mjs @@ -0,0 +1,55 @@ +/** +* Myext lock (aka binary semaphore aka mutex) +* +* Copyright (C) 2021 Wojtek Kosior +* +* Dual-licensed under: +* - 0BSD license +* - GPLv3 or (at your option) any later version +*/ + +/* + * Javascript runs single-threaded, with an event loop. Because of that, + * explicit synchronization is often not needed. An exception is when we use + * an API function that must wait. Ajax is an example. Callback passed to ajax + * call doesn't get called immediately, but after some time. In the meantime + * some other piece of code might get to execute and modify some variables. + * Access to WebExtension local storage is another situation where this problem + * can occur. + * + * This is a solution. A lock object, that can be used to delay execution of + * some code until other code finishes its critical work. Locking is wrapped + * in a promise. + */ + +"use strict"; + +export function make_lock() { + return {free: true, queue: []}; +} + +function _lock(lock, cb) { + if (lock.free) { + lock.free = false; + setTimeout(cb); + } else { + lock.queue.push(cb); + } +} + +export function lock(lock) { + return new Promise((resolve, reject) => _lock(lock, resolve)); +} + +export function unlock(lock) { + if (lock.free) + throw new Exception("Attempting to release a free lock"); + + if (lock.queue.length === 0) { + lock.free = true; + } else { + let cb = lock.queue[0]; + lock.queue.splice(0, 1); + setTimeout(cb); + } +} |