1 module lwdr;
2 
3 pragma(LDC_no_moduleinfo);
4 
5 import lifetime.delegate_;
6 public import lwdr.tracking;
7 
8 /// A static class by which to interface with core features of LWDR.
9 static final class LWDR
10 {
11 	/+/// Finalise and deallocate object `obj`
12 	static void free(ref Object obj) nothrow @nogc
13 	{
14 		import lifetime.class_;
15 		_d_delclass(&obj);
16 		obj = null;
17 	}+/
18 	
19 	static void free(T)(ref T obj) nothrow @nogc @trusted
20 		if(is(T == class) || is(T == interface))
21 	{
22 		import lifetime.class_;
23 		Object o = cast(Object)obj;
24 		_d_delclass(&o);
25 		obj = null;
26 	}
27 
28 	version(LWDR_DynamicArray)
29 	/// Finalise (if possible) and deallocate dynamic array `arr`
30 	static void free(TArr : T[], T)(ref TArr arr) nothrow @trusted
31 	{
32 		import lifetime.array_;
33 		_d_delarray_t(cast(void[]*)&arr, cast(TypeInfo_Struct)typeid(TArr)); // cast to TypeInfo_Struct is acceptable
34 		arr = null;
35 	}
36 
37 	/// Deallocate `ptr`
38 	static void free(TPtr : T*, T)(ref TPtr ptr) nothrow @trusted
39 		if(!is(T == struct))
40 	{
41 		import lifetime.common;
42 		_d_delmemory(cast(void**)&ptr);
43 		ptr = null;
44 	}
45 
46 	/// Finalise (if possible) and deallocate struct pointed to by `ptr`.
47 	static void free(TPtr : T*, T)(ref TPtr ptr) nothrow @trusted
48 		if(is(T == struct))
49 	{
50 		import lifetime.common;
51 		TypeInfo_Struct s = cast(TypeInfo_Struct)typeid(T);
52 		s.dtor(ptr);
53 		_d_delmemory(cast(void**)&ptr);
54 		ptr = null;
55 	}
56 
57 	version(LWDR_ManualDelegate)
58 	{
59 		/++
60 		Deallocate the context for a delegate. If the pointer isn't valid,
61 		then no action is taken. Hence, it is safe to call this for all types
62 		of delegate context types.
63 		++/
64 		static void freeDelegateContext(void* contextPtr) nothrow @trusted
65 		{
66 			freeDelegate(contextPtr);
67 		}
68 	}
69 
70 	/// Start the runtime. Must be called once per process and before any runtime functionality is used!
71 	static void startRuntime() @trusted nothrow
72 	{
73 		version(LWDR_Sync)
74 		{
75 			import rt.monitor_;
76 			__lwdr_monitor_init;
77 		}
78 		version(LWDR_ModuleCtors)
79 		{
80 			import rt.moduleinfo;
81 			__lwdr_moduleInfo_runModuleCtors();
82 		}
83 		version(LWDR_ManualDelegate)
84 		{
85 			__lwdr_initLifetimeDelegate();
86 		}
87 	}
88 
89 	/// Stop the runtime. Must be called once per process after all D code has exited.
90 	static void stopRuntime() @trusted nothrow
91 	{
92 		version(LWDR_ModuleCtors)
93 		{
94 			import rt.moduleinfo;
95 			__lwdr_moduleInfo_runModuleDtors();
96 		}
97 		version(LWDR_ManualDelegate)
98 		{
99 			__lwdr_deinitLifetimeDelegate();
100 		}
101 		version(LWDR_Sync)
102 		{
103 			import rt.monitor_;
104 			__lwdr_monitor_deinit;
105 		}
106 	}
107 
108 	version(LWDR_TLS)
109 	{
110 		/++ Register the current thread with LWDR.
111 		 + This will perform the necessary TLS allocations for this thread. ++/
112 		static void registerCurrentThread() nothrow @trusted
113 		{
114 			import rt.tls;
115 			initTLSRanges();
116 			import rt.moduleinfo;
117 			__lwdr_moduleInfo_runTlsCtors();
118 		}
119 
120 		/++ Deregister the current thread from LWDR.
121 		 + If this thread was not registered, it will cause unknown behaviour.
122 		 + This will deallocate TLS memory for this thread. ++/
123 		static void deregisterCurrentThread() nothrow @trusted
124 		{
125 			import rt.moduleinfo;
126 			__lwdr_moduleInfo_runTlsDtors();
127 			import rt.tls;
128 			freeTLSRanges();
129 		}
130 	}
131 }
132 
133 /// Initialise LWDR. This forwards to `LWDR.startRuntime`. It is intended for external C code.
134 extern(C) void lwdrStartRuntime() @system nothrow
135 { LWDR.startRuntime; }
136 
137 /// Terminate LWDR. This forwards to `LWDR.stopRuntime`. It is intended for external C code.
138 extern(C) void lwdrStopRuntime() @system nothrow
139 { LWDR.stopRuntime; }
140 
141 /++
142  + Mixin for the entry point of the application. Calls `startRuntime` and
143  + `registerCurrentThread` and the respective stop functions on `scope(exit)`.
144  +
145  + May be extended to contain more initialization in the future.
146  +
147  + Examples:
148  + ---
149  + extern(C) void myMain()
150  + {
151  +     mixin(LWDREntryPointMixin);
152  + }
153  + ---
154  +/
155 enum LWDREntryPointMixin = q{
156     LWDR.startRuntime; // runs the shared static constructors
157     scope(exit) LWDR.stopRuntime; // runs the shared static destructors
158     LWDR.registerCurrentThread; 
159     scope(exit) LWDR.deregisterCurrentThread;
160 };
161 
162 /++
163  + Mixin for the entry point of a secondary thread. Calls
164  + `registerCurrentThread` and the respective stop function on `scope(exit)`.
165  +
166  + May be extended to contain more initialization in the future.
167  +
168  + Don't combine this mixin with `LWDREntryPointMixin` as it already registers
169  + the thread.
170  +
171  + Examples:
172  + ---
173  + extern(C) void secondThreadEntryPoint()
174  + {
175  +     mixin(LWDRThreadEntryMixin);
176  + }
177  + ---
178  +/
179 enum LWDRThreadEntryMixin = q{
180     LWDR.registerCurrentThread; 
181     scope(exit) LWDR.deregisterCurrentThread;
182 };