Skip to content

Instantly share code, notes, and snippets.

@araraloren
Last active January 27, 2019 05:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save araraloren/cfb7d7b694be76e0bbe53491df573d3a to your computer and use it in GitHub Desktop.
Save araraloren/cfb7d7b694be76e0bbe53491df573d3a to your computer and use it in GitHub Desktop.
unit module Song::Command::List;
unit class Song::Pluggable is export;
state $threadlock = Lock::Async.new;
has $.file;
has $!lock;
has @!plugins;
submethod TWEAK() {
$!lock = $!file.IO.dirname.IO.add(".lock").open(:create, :rw);
}
class Info { ... }
method load() {
my %config = Rakudo::Internals::JSON.from-json(slurp($!file));
@!plugins = [];
for @(%config<plugins>) -> $plugin {
@!plugins.push(self!make-plugin-info($plugin<name>.Str, $plugin<enable>.Bool));
}
self;
}
method plugins() {
@!plugins;
}
method lock() {
$threadlock.protect: {
$!lock.lock();
}
}
method unlock() {
$threadlock.protect: {
$!lock.unlock();
}
}
method find(Str $name) {
@!plugins.grep(*.name eq $name);
}
method exists(Str $name) {
@!plugins.grep(*.name eq $name).elems > 0;
}
method register(Str $name, Bool $enable) {
if self.exists($name) {
die "The plugin is already existed: $name";
}
else {
@!plugins.push($name, $enable);
self!append-plugin-to-config($name, $enable);
}
}
method !append-plugin-to-config(Str $name, Bool $enable) {
my %config = Rakudo::Internals::JSON.from-json(slurp($!file));
%config<plugins>.push(%{ name => $name, enable => $enable });
spurt($!file, Rakudo::Internals::JSON.to-json(%config));
}
method !make-plugin-info(Str $name, Bool $enable) {
$threadlock.protect: {
Info.new(
enable => $enable,
plugin => do {
((try require ::($name)) === Nil) ?? Any !! ::($name)
},
name => $name,
installed => !((try require ::($name)) === Nil),
)
}
}
class Info {
has $.enable;
has $.plugin;
has $.installed;
has $.name;
method get-instance(*%_) {
$!plugin.new(|%_);
}
}
{
"plugins" : [
{
"name" : "Song::Command::Install",
"enable" : true
},
{
"name" : "Song::Command::Remove",
"enable" : true
},
{
"name" : "Song::Command::List",
"enable" : true
},
{
"name" : "Song::Command::Update",
"enable" : true
}
]
}
use Song::Pluggable;
my @threads;
for ^5 {
@threads.push(
start {
given Song::Pluggable.new(file => "plugin.json") {
say "IN THREAD {$*THREAD.id}: ", .gist, .WHICH;
.lock();
.load();
.unlock();
say "IN THREAD {$*THREAD.id}: ", .gist for .plugins();
.lock();
try .register('Song::Command::Update', True);
.unlock();
say "IN THREAD {$*THREAD.id} LOAD AGAIN";
.lock();
.load();
.unlock();
say "AGAIN, IN THREAD {$*THREAD.id}: ", .gist for .plugins();
}
}
)
}
await @threads;
@b2gills
Copy link

b2gills commented Jan 26, 2019

It is recommended to use Lock.protect instead of Lock.lock and Lock.unlock

For one, if there is an error in one of those calls the corresponding unlock might not get called.

Also if Song::Pluggable.load needs to be locked, why doesn't it do the locking itself?

If every method needs to be locked, use OO::Monitors, and it will do all the locking for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment