1 /**
2 Copyright: Copyright (c) 2021, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 Allocators used by system.
7 */
8 module my.actor.memory;
9 
10 import my.actor.actor : Actor, ActorState;
11 import my.actor.mailbox : StrongAddress, makeAddress2;
12 
13 /** Assuming that the `System` instance ensure that only actors creating with
14  * the allocator are deallocated. If everything goes OK it means that an actor
15  * reach the state `shutdown` and is then disposed of by `System`.
16  *
17  */
18 struct ActorAlloc {
19     import core.memory : GC;
20     import std.experimental.allocator.mallocator : Mallocator;
21 
22     // lazy for now and just use the global allocator.
23     alias allocator_ = Mallocator.instance;
24 
25     enum Sz = Actor.sizeof;
26 
27     Actor* make(StrongAddress addr) @trusted {
28         import std.experimental.allocator : make;
29 
30         auto rval = make!Actor(allocator_, addr);
31         GC.addRange(rval, Sz);
32 
33         return rval;
34     }
35 
36     void dispose(Actor* a) @trusted
37     in (a.state_ == ActorState.stopped, "actors must be stopped before disposed") {
38         static import my.alloc.dispose_;
39 
40         my.alloc.dispose_.dispose(allocator_, a);
41         GC.removeRange(a);
42     }
43 }
44 
45 @("shall allocate and dellacate an actor")
46 unittest {
47     import core.memory : GC;
48     import std.variant;
49     import std.typecons;
50     import std.datetime : Clock;
51     import my.actor.mailbox;
52 
53     ActorAlloc aa;
54     foreach (_1; 0 .. 10) {
55         auto addr = makeAddress2;
56         auto a = aa.make(addr);
57 
58         // adding a StrongAddress is normally blocked by the user BUT the
59         // teardown of messages should release it such that it is no longer on
60         // the GC.
61         auto smurf = tuple(addr.weakRef);
62         auto b = smurf;
63         addr.get.put!Msg(Msg(42, MsgType(MsgOneShot(Variant(smurf)))));
64 
65         foreach (_2; 0 .. 5)
66             a.process(Clock.currTime);
67 
68         a.shutdown;
69         while (a.isAlive)
70             a.process(Clock.currTime);
71 
72         aa.dispose(a);
73         GC.collect;
74     }
75 }