diff options
author | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-05-12 16:00:09 +0200 |
---|---|---|
committer | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-05-12 16:00:09 +0200 |
commit | 7f368d46ea06164da025c1ac4ed9a65ad23b25ef (patch) | |
tree | e5b740ebcb3cdc58e9c87f25556c20d8bfdccadd /common/lock.js | |
parent | 89db6823fae5099816732c3cd2ba39700c1c4607 (diff) | |
download | browser-extension-7f368d46ea06164da025c1ac4ed9a65ad23b25ef.tar.gz browser-extension-7f368d46ea06164da025c1ac4ed9a65ad23b25ef.zip |
stop using js modules
Diffstat (limited to 'common/lock.js')
-rw-r--r-- | common/lock.js | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/common/lock.js b/common/lock.js new file mode 100644 index 0000000..107287f --- /dev/null +++ b/common/lock.js @@ -0,0 +1,61 @@ +/** +* 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"; + +(() => { + function make_lock() { + return {free: true, queue: []}; + } + + function _lock(lock, cb) { + if (lock.free) { + lock.free = false; + setTimeout(cb); + } else { + lock.queue.push(cb); + } + } + + function lock(lock) { + return new Promise((resolve, reject) => _lock(lock, resolve)); + } + + 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); + } + } + + window.make_lock = make_lock; + window.lock = lock; + window.unlock = unlock; +})(); |