Skip to content

Commit f6b1f85

Browse files
committed
CI test prior to release
1 parent 982cf06 commit f6b1f85

File tree

14 files changed

+236
-130
lines changed

14 files changed

+236
-130
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.precomp/
22
/OO-Monitors-*
3+
*.rakucov

Changes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
Revision history for OO-Monitors
22

33
{{$NEXT}}
4+
- Adapt build logic to also allow for the new
5+
POPULATE method
6+
- Update copyright year
47

58
1.1.3 2024-11-30T19:50:06+01:00
69
- Fix issue with source-url

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ COPYRIGHT AND LICENSE
105105

106106
Copyright 2014 - 2021 Jonathan Worthington
107107

108-
Copyright 2024 Raku Community
108+
Copyright 2024, 2025 Raku Community
109109

110110
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.
111111

dist.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = OO-Monitors
22

33
[ReadmeFromPod]
4-
filename = lib/OO/Monitors.rakumod
4+
filename = doc/OO-Monitors.rakudoc
55

66
[UploadToZef]
77

doc/OO-Monitors.rakudoc

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
=begin pod
2+
3+
=head1 NAME
4+
5+
OO::Monitors - Objects with mutual exclusion and condition variables
6+
7+
=head1 SYNOPSIS
8+
9+
=begin code :lang<raku>
10+
11+
use OO::Monitors;
12+
13+
monitor Foo {
14+
has $.bar
15+
16+
# accessible by one thread at a time
17+
method frobnicate() { }
18+
}
19+
20+
=end code
21+
22+
=head1 DESCRIPTION
23+
24+
A monitor provides per-instance mutual exclusion for objects. This means
25+
that for a given object instance, only one thread can ever be inside its
26+
methods at a time. This is achieved by a lock being associated with each
27+
object. The lock is acquired automatically at the entry to each method
28+
in the monitor. Condition variables are also supported.
29+
30+
=head2 Basic Usage
31+
32+
A monitor looks like a normal class, but declared with the C<monitor> keyword.
33+
34+
=begin code :lang<raku>
35+
36+
use OO::Monitors;
37+
38+
monitor IPFilter {
39+
has %!active;
40+
has %!blacklist;
41+
has $.limit = 10;
42+
has $.blocked = 0;
43+
44+
method should-start-request($ip) {
45+
if %!blacklist{$ip}
46+
|| (%!active{$ip} // 0) == $.limit {
47+
$!blocked++;
48+
return False;
49+
}
50+
else {
51+
%!active{$ip}++;
52+
return True;
53+
}
54+
}
55+
56+
method end-request($ip) {
57+
%!active{$ip}--;
58+
}
59+
}
60+
61+
=end code
62+
63+
That's about all there is to it. The monitor meta-object enforces mutual
64+
exclusion.
65+
66+
=head2 Conditions
67+
68+
Condition variables are declared with the C<conditioned> trait on the
69+
monitor. To wait on a condition, use C<wait-condition>. To signal that
70+
a condition has been met, use C<meet-condition>. Here is an example of
71+
a bounded queue.
72+
73+
=begin code :lang<raku>
74+
75+
monitor BoundedQueue is conditioned(<not-full not-empty>) {
76+
has @!tasks;
77+
has $.limit = die "Must specify a limit";
78+
79+
method add-task($task) {
80+
while @!tasks.elems == $!limit {
81+
wait-condition <not-full>;
82+
}
83+
@!tasks.push($task);
84+
meet-condition <not-empty>;
85+
}
86+
87+
method take-task() {
88+
until @!tasks {
89+
wait-condition <not-empty>;
90+
}
91+
meet-condition <not-full>;
92+
return @!tasks.shift;
93+
}
94+
}
95+
96+
=end code
97+
98+
When C<wait-condition> is used, the lock is released and the thread
99+
blocks until the condition is met by some other thread. By contrast,
100+
C<meet-condition> just marks a waiting thread as unblocked, but retains
101+
the lock until the method is over.
102+
103+
=head2 Circular waiting
104+
105+
Monitors are vulnerable to deadlock, if you set up a circular dependency. Keep
106+
object graphs involving monitors simple and cycle-free, so far as is possible.
107+
108+
=head1 AUTHOR
109+
110+
Jonathan Worthington
111+
112+
Source can be located at: https://github.com/raku-community-modules/OO-Monitors .
113+
Comments and Pull Requests are welcome.
114+
115+
=head1 COPYRIGHT AND LICENSE
116+
117+
Copyright 2014 - 2021 Jonathan Worthington
118+
119+
Copyright 2024, 2025 Raku Community
120+
121+
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.
122+
123+
=end pod

lib/OO/Monitors.rakumod

Lines changed: 12 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class MetamodelX::MonitorHOW is Metamodel::ClassHOW {
2020
}
2121

2222
method add_method(Mu \type, $name, $meth) {
23-
$name ne 'BUILDALL' && $meth.wrap(-> \SELF, | {
23+
!($name eq 'BUILDALL' | 'POPULATE') && $meth.wrap(-> \SELF, | {
2424
if SELF.DEFINITE {
2525
# Instance method call; acquire lock.
2626
my $*MONITOR := SELF;
@@ -65,12 +65,20 @@ class MetamodelX::MonitorHOW is Metamodel::ClassHOW {
6565
callsame();
6666
};
6767
}
68+
elsif self.method_table(type)<POPULATE>:exists {
69+
self.method_table(type)<POPULATE>.wrap: -> \SELF, | {
70+
$!lock-attr.set_value(SELF, Lock.new);
71+
callsame();
72+
};
73+
}
6874
else {
6975
my $lock-attr := $!lock-attr;
70-
self.add_method(type, 'BUILDALL', anon method BUILDALL(Mu \SELF: |) {
76+
my $method := anon method POPULATE(Mu \SELF: |) {
7177
$lock-attr.set_value(SELF, Lock.new);
7278
callsame();
73-
});
79+
}
80+
self.add_method(type, 'BUILDALL', $method);
81+
self.add_method(type, 'POPULATE', $method);
7482
}
7583
self.Metamodel::ClassHOW::compose(type);
7684
}
@@ -113,126 +121,4 @@ my package EXPORTHOW {
113121
}
114122
}
115123

116-
=begin pod
117-
118-
=head1 NAME
119-
120-
OO::Monitors - Objects with mutual exclusion and condition variables
121-
122-
=head1 SYNOPSIS
123-
124-
=begin code :lang<raku>
125-
126-
use OO::Monitors;
127-
128-
monitor Foo {
129-
has $.bar
130-
131-
# accessible by one thread at a time
132-
method frobnicate() { }
133-
}
134-
135-
=end code
136-
137-
=head1 DESCRIPTION
138-
139-
A monitor provides per-instance mutual exclusion for objects. This means
140-
that for a given object instance, only one thread can ever be inside its
141-
methods at a time. This is achieved by a lock being associated with each
142-
object. The lock is acquired automatically at the entry to each method
143-
in the monitor. Condition variables are also supported.
144-
145-
=head2 Basic Usage
146-
147-
A monitor looks like a normal class, but declared with the C<monitor> keyword.
148-
149-
=begin code :lang<raku>
150-
151-
use OO::Monitors;
152-
153-
monitor IPFilter {
154-
has %!active;
155-
has %!blacklist;
156-
has $.limit = 10;
157-
has $.blocked = 0;
158-
159-
method should-start-request($ip) {
160-
if %!blacklist{$ip}
161-
|| (%!active{$ip} // 0) == $.limit {
162-
$!blocked++;
163-
return False;
164-
}
165-
else {
166-
%!active{$ip}++;
167-
return True;
168-
}
169-
}
170-
171-
method end-request($ip) {
172-
%!active{$ip}--;
173-
}
174-
}
175-
176-
=end code
177-
178-
That's about all there is to it. The monitor meta-object enforces mutual
179-
exclusion.
180-
181-
=head2 Conditions
182-
183-
Condition variables are declared with the C<conditioned> trait on the
184-
monitor. To wait on a condition, use C<wait-condition>. To signal that
185-
a condition has been met, use C<meet-condition>. Here is an example of
186-
a bounded queue.
187-
188-
=begin code :lang<raku>
189-
190-
monitor BoundedQueue is conditioned(<not-full not-empty>) {
191-
has @!tasks;
192-
has $.limit = die "Must specify a limit";
193-
194-
method add-task($task) {
195-
while @!tasks.elems == $!limit {
196-
wait-condition <not-full>;
197-
}
198-
@!tasks.push($task);
199-
meet-condition <not-empty>;
200-
}
201-
202-
method take-task() {
203-
until @!tasks {
204-
wait-condition <not-empty>;
205-
}
206-
meet-condition <not-full>;
207-
return @!tasks.shift;
208-
}
209-
}
210-
211-
=end code
212-
213-
When C<wait-condition> is used, the lock is released and the thread
214-
blocks until the condition is met by some other thread. By contrast,
215-
C<meet-condition> just marks a waiting thread as unblocked, but retains
216-
the lock until the method is over.
217-
218-
=head2 Circular waiting
219-
220-
Monitors are vulnerable to deadlock, if you set up a circular dependency. Keep
221-
object graphs involving monitors simple and cycle-free, so far as is possible.
222-
223-
=head1 AUTHOR
224-
225-
Jonathan Worthington
226-
227-
Source can be located at: https://github.com/raku-community-modules/OO-Monitors .
228-
Comments and Pull Requests are welcome.
229-
230-
=head1 COPYRIGHT AND LICENSE
231-
232-
Copyright 2014 - 2021 Jonathan Worthington
233-
234-
Copyright 2024 Raku Community
235-
236-
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.
237-
238-
=end pod
124+
# vim: expandtab shiftwidth=4

0 commit comments

Comments
 (0)