1 /**
2  * This module contains allocation functions for the garbage collector.
3  *
4  * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
5  *            All rights reserved.
6  * License:
7  *  This software is provided 'as-is', without any express or implied
8  *  warranty. In no event will the authors be held liable for any damages
9  *  arising from the use of this software.
10  *
11  *  Permission is granted to anyone to use this software for any purpose,
12  *  including commercial applications, and to alter it and redistribute it
13  *  freely, in both source and binary form, subject to the following
14  *  restrictions:
15  *
16  *  o  The origin of this software must not be misrepresented; you must not
17  *     claim that you wrote the original software. If you use this software
18  *     in a product, an acknowledgment in the product documentation would be
19  *     appreciated but is not required.
20  *  o  Altered source versions must be plainly marked as such, and must not
21  *     be misrepresented as being the original software.
22  *  o  This notice may not be removed or altered from any source
23  *     distribution.
24  * Authors:   Walter Bright, David Friedman, Sean Kelly, Leandro Lucarella
25  */
26 
27 module rt.gc.cdgc.os;
28 
29 
30 // Fork
31 ////////////////////////////////////////////////////////////////////////
32 
33 // Public interface/Documentation
34 
35 /**
36  * Possible results for the wait_pid() function.
37  */
38 enum WRes
39 {
40     DONE, /// The process has finished successfully
41     RUNNING, /// The process is still running
42     ERROR /// There was an error waiting for the process
43 }
44 
45 version (D_Ddoc) {
46 
47 /**
48  * Indicates if an implementation support fork().
49  *
50  * The value shown here is just demostrative, the real value is defined based
51  * on the OS it's being compiled in.
52  */
53 const HAVE_FORK = true;
54 
55 /**
56  * Wait for a process with PID pid to finish.
57  *
58  * If block is false, this function will not block, and return WRes.RUNNING if
59  * the process is still running. Otherwise it will return always WRes.DONE
60  * (unless there is an error, in which case WRes.ERROR is returned).
61  */
62 WRes wait_pid(pid_t pid, bool block = true);
63 
64 public import tango.stdc.posix.unistd: pid_t, fork;
65 
66 }
67 
68 // Implementations
69 else version (Posix) {
70     enum { HAVE_FORK = true }
71     public import tango.stdc.posix.unistd: pid_t, fork;
72     import tango.stdc.posix.sys.wait: waitpid, WNOHANG;
73     public WRes wait_pid(pid_t pid, bool block = true) {
74         int status = void;
75         pid_t waited_pid = waitpid(pid, &status, block ? 0 : WNOHANG);
76         if (waited_pid == 0)
77             return WRes.RUNNING;
78         assert (waited_pid == pid);
79         assert (status == 0);
80         if (waited_pid != pid || status != 0)
81             return WRes.ERROR;
82         return WRes.DONE;
83     }
84 }
85 
86 else {
87     enum { HAVE_FORK = false }
88     alias int pid_t;
89     pid_t fork() { assert (false); return -1; }
90     WRes wait_pid(pid_t, bool = true) { assert (false); return false; }
91 }
92 
93 
94 // Allocation
95 ////////////////////////////////////////////////////////////////////////
96 
97 version (Win32)
98     import tango.sys.win32.UserGdi;
99 else version (Posix)
100     import tango.stdc.posix.sys.mman;
101 else
102     import tango.stdc.stdlib;
103 
104 
105 // Public interface/Documentation
106 
107 /**
108  * Visibility of the mapped memory.
109  */
110 enum Vis
111 {
112     PRIV, /// Private to this process
113     SHARED, /// Shared across fork()ed processes (only when HAVE_SHARED)
114 }
115 
116 version (D_Ddoc) {
117 
118 /**
119  * Indicates if an implementation support mapping shared memory.
120  *
121  * The value shown here is just demostrative, the real value is defined based
122  * on the OS it's being compiled in.
123  */
124 const HAVE_SHARED = false;
125 
126 /**
127  * Map memory.
128  */
129 void* alloc(size_t nbytes, Vis vis = Vis.PRIV);
130 
131 /**
132  * Unmap memory allocated with alloc().
133  * Returns:
134  *      true  success
135  *      false failure
136  */
137 bool dealloc(void* base, size_t nbytes, Vis vis = Vis.PRIV);
138 
139 }
140 
141 // Implementations
142 else static if (is(typeof(VirtualAlloc))) {
143     enum { HAVE_SHARED = false }
144 
145     void* alloc(size_t nbytes, Vis vis = Vis.PRIV)
146     {
147         assert (vis == Vis.PRIV);
148         return VirtualAlloc(null, nbytes, MEM_RESERVE | MEM_COMMIT,
149                 PAGE_READWRITE);
150     }
151 
152     bool dealloc(void* base, size_t nbytes, Vis vis = Vis.PRIV)
153     {
154         assert (vis == Vis.PRIV);
155         return VirtualFree(base, 0, MEM_RELEASE) != 0;
156     }
157 
158 }
159 
160 else static if (is(typeof(mmap)) && is(typeof(MAP_ANON))) {
161     enum { HAVE_SHARED = true }
162 
163     void* alloc(size_t nbytes, Vis vis = Vis.PRIV)
164     {
165         auto flags = MAP_ANON;
166         if (vis == Vis.SHARED)
167             flags |= MAP_SHARED;
168         else // PRIV
169             flags |= MAP_PRIVATE;
170         void* p = mmap(null, nbytes, PROT_READ | PROT_WRITE, flags, -1, 0);
171         return (p == MAP_FAILED) ? null : p;
172     }
173 
174     bool dealloc(void* base, size_t nbytes, Vis vis = Vis.PRIV)
175     {
176         // vis is not necessary to unmap
177         return munmap(base, nbytes) == 0;
178     }
179 }
180 
181 else static if (is(typeof(malloc))) {
182     enum { HAVE_SHARED = false }
183 
184     // NOTE: This assumes malloc granularity is at least (void*).sizeof.  If
185     //       (req_size + PAGESIZE) is allocated, and the pointer is rounded up
186     //       to PAGESIZE alignment, there will be space for a void* at the end
187     //       after PAGESIZE bytes used by the GC.
188 
189     import rt.gc.cdgc.gc: PAGESIZE;
190 
191     const size_t PAGE_MASK = PAGESIZE - 1;
192 
193     void* alloc(size_t nbytes, Vis vis = Vis.PRIV)
194     {
195         assert (vis == Vis.PRIV);
196         byte* p, q;
197         p = cast(byte* ) malloc(nbytes + PAGESIZE);
198         q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK);
199         *cast(void**)(q + nbytes) = p;
200         return q;
201     }
202 
203     bool dealloc(void* base, size_t nbytes, Vis vis = Vis.PRIV)
204     {
205         assert (vis == Vis.PRIV);
206         free(*cast(void**)(cast(byte*) base + nbytes));
207         return true;
208     }
209 }
210 
211 else static assert(false, "No supported allocation methods available.");
212 
213 
214 // vim: set et sw=4 sts=4 :