Commit 7079082b authored by Tomáš Peterka's avatar Tomáš Peterka Committed by Tomáš Peterka

[renderjs_ui] Add non-recursive locking for gadgets into gadget_global

/reviewed-on nexedi/erp5!536
parent f09062e5
......@@ -126,4 +126,115 @@
});
};
/** Internal function to prepare gadget to hold a mutex */
function ensureLockable(gadget) {
if (gadget.props === undefined) {
gadget.props = {};
}
// waiting_line is container of mutexes which already blocks some Promise
if (gadget.props.waiting_line === undefined) {
gadget.props.waiting_line = [];
}
}
/** Synchronously lock gadget and return previous lock's promise.
NON-RECURSIVE lock! If you lock inside locked execution you will wait forever.
If used in a Queue (@see lockGadgetInQueue) it blocks when acquiring the lock.
*/
window.lockGadget = function (gadget) {
var ahead_of_me;
ensureLockable(gadget);
// step in line
gadget.props.waiting_line.push(RSVP.defer());
if (gadget.props.waiting_line.length >= 2) {
// wait for the promise ahead of me
ahead_of_me = gadget.props.waiting_line[gadget.props.waiting_line.length - 2].promise;
} else {
ahead_of_me = RSVP.resolve();
}
// return previous lock's Promise to postpone execution
return ahead_of_me;
};
/** Lock gadget as a step in RSVP.Queue waiting for previous lock to unlock.
Use in RSVP.Queue to block execution until manually called `unlockGadget`.
Both lock/unlockGadget pass through any value in RSVP.Queue manner.
Pass through any value.
Example:
new RSVP.Queue()
.push(function () {return some_value;})
.push(lockGadgetInQueue(gadget), lockGadgetInFailedQueue(gadget))
.push(function (some_value) {return someWork(some_value);})
.push(unlockGadgetInQueue(gadget), unlockGadgetInFailedQueue(gadget));
*/
window.lockGadgetInQueue = function (gadget) {
// return function to be used in RSVP.Queue
return function (pass_through) {
return new RSVP.Queue()
.push(function () {
return window.lockGadget(gadget);
})
.push(function () {
return pass_through;
});
};
};
/** Lock Gagdet in Queue but intended to be used in "fail" branch (the second function).
Rethrows any argument.
*/
window.lockGadgetInFailedQueue = function (gadget) {
// return function to be used in RSVP.Queue
return function (error) {
return new RSVP.Queue()
.push(function () {
return window.lockGadget(gadget);
})
.push(function () {
throw error;
});
};
};
/** Synchronously unlock gadget by resolving props.mutex.promise.
That promise is most likely blocking some RSVP.Queue or is then-ed on another
Promise.
*/
window.unlockGadget = function (gadget) {
if (gadget.props === undefined ||
gadget.props.waiting_line === undefined ||
gadget.props.waiting_line.length === 0) {
throw new Error("Gadget " + gadget + " is not locked!");
}
gadget.props.waiting_line.shift().resolve();
};
/** Unlock gadget without blocking as a step in RSVP.Queue.
Pass through any value. Not re-throwing errors in fail branch!
For example @see lockGadgetInQueue.
*/
window.unlockGadgetInQueue = function (gadget) {
return function (pass_through) {
window.unlockGadget(gadget);
return pass_through;
};
};
/** Unlock gadget without blocking and throw any argument received. */
window.unlockGadgetInFailedQueue = function (gadget) {
return function (error) {
window.unlockGadget(gadget);
throw error;
};
};
}(window, RSVP, FileReader));
\ No newline at end of file
......@@ -230,7 +230,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>947.51167.64410.14796</string> </value>
<value> <string>964.19771.1861.12424</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -248,7 +248,7 @@
</tuple>
<state>
<tuple>
<float>1450099422.01</float>
<float>1513956134.36</float>
<string>UTC</string>
</tuple>
</state>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment