1 /*
2     Title:      Lightweight process library
3     Author:     David C.J. Matthews
4 
5     Copyright (c) 2007-8, 2012, 2015, 2017, 2019, 2020 David C.J. Matthews
6 
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License version 2.1 as published by the Free Software Foundation.
10 
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Lesser General Public License for more details.
15 
16     You should have received a copy of the GNU Lesser General Public
17     License along with this library; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 
20 */
21 
22 #ifndef _PROCESSES_H_
23 #define _PROCESSES_H_
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #elif defined(_WIN32)
28 #include "winconfig.h"
29 #else
30 #error "No configuration file"
31 #endif
32 
33 #include "globals.h"
34 #include "rts_module.h"
35 #include "save_vec.h"
36 
37 #include "noreturn.h"
38 #include "locking.h"
39 
40 class SaveVecEntry;
41 typedef SaveVecEntry *Handle;
42 class StackSpace;
43 class PolyWord;
44 class ScanAddress;
45 class MDTaskData;
46 class Exporter;
47 class StackObject;
48 
49 #ifdef HAVE_WINDOWS_H
50 typedef void *HANDLE;
51 #endif
52 
53 #ifdef HAVE_SIGNAL_H
54 #include <signal.h>
55 #endif
56 
57 #ifdef HAVE_UCONTEXT_H
58 #include <ucontext.h>
59 #endif
60 
61 #ifdef HAVE_PTHREAD_H
62 #include <pthread.h>
63 #endif
64 
65 // SIGNALCONTEXT is the argument type that is passed to GetPCandSPFromContext
66 // to get the actual PC and SP in a profiling trap.
67 #if defined(HAVE_WINDOWS_H)
68 // First because it's used in both native Windows and Cygwin.
69 #include <windows.h>
70 #define SIGNALCONTEXT CONTEXT // This is the thread context.
71 #elif defined(HAVE_UCONTEXT_T)
72 #define SIGNALCONTEXT ucontext_t
73 #elif defined(HAVE_STRUCT_SIGCONTEXT)
74 #define SIGNALCONTEXT struct sigcontext
75 #else
76 #define SIGNALCONTEXT void
77 #endif
78 
79 #define MIN_HEAP_SIZE   4096 // Minimum and initial heap segment size (words)
80 
81 // This is the ML "thread identifier" object.  The fields
82 // are read and set by the ML code.
83 class ThreadObject: public PolyObject {
84 public:
85     PolyWord    threadRef;  // Weak ref containing the address of the thread data. Not used by ML
86     PolyWord    flags;  // Tagged integer containing flags indicating how interrupts
87                         // are handled.  Set by ML but only by the thread itself
88     PolyWord    threadLocal; // Head of a list of thread-local store items.
89                         // Handled entirely by ML but only by the thread.
90     PolyWord    requestCopy; // A tagged integer copy of the "requests" field.
91                         // This is provided so that ML can easily test if there
92                         // is an interrupt pending.
93     PolyWord    mlStackSize; // A tagged integer with the maximum ML stack size in bytes
94     PolyWord    debuggerSlots[4]; // These are used by the debugger.
95 };
96 
97 // Other threads may make requests to a thread.
98 typedef enum {
99     kRequestNone = 0, // Increasing severity
100     kRequestInterrupt = 1,
101     kRequestKill = 2
102 } ThreadRequests;
103 
104 // Per-thread data.  This is subclassed for each architecture.
105 class TaskData {
106 public:
107     TaskData();
108     virtual ~TaskData();
109 
110     void FillUnusedSpace(void);
111     virtual void GarbageCollect(ScanAddress *process);
112 
113     virtual void EnterPolyCode() = 0; // Start running ML
114 
115     virtual void InterruptCode() = 0;
116     virtual bool AddTimeProfileCount(SIGNALCONTEXT *context) = 0;
117     // Initialise the stack for a new thread.  The parent task object is passed in because any
118     // allocation that needs to be made must be made in the parent.
119     virtual void InitStackFrame(TaskData *parentTask, Handle proc, Handle arg) = 0;
120     virtual void SetException(poly_exn *exc) = 0;
121 
122     // The scheduler needs versions of atomic decrement and atomic reset that
123     // work in exactly the same way as the code-generated versions (if any).
124     // Atomic decrement isn't needed since it only ever releases a mutex.
125     virtual Handle AtomicDecrement(Handle mutexp) = 0;
126     // Reset a mutex to one.  This needs to be atomic with respect to the
127     // atomic increment and decrement instructions.
128     virtual void AtomicReset(Handle mutexp) = 0;
129 
130     virtual void CopyStackFrame(StackObject *old_stack, uintptr_t old_length,
131                                 StackObject *new_stack, uintptr_t new_length) = 0;
132 
133 
134     virtual uintptr_t currentStackSpace(void) const = 0;
135     // Add a count to the local function if we are using store profiling.
136     virtual void addProfileCount(POLYUNSIGNED words) = 0;
137 
138     // Functions called before and after an RTS call.
PreRTSCall(void)139     virtual void PreRTSCall(void) { inML = false; }
PostRTSCall(void)140     virtual void PostRTSCall(void) { inML = true; }
141 
142     SaveVec     saveVec;
143     PolyWord    *allocPointer;  // Allocation pointer - decremented towards...
144     PolyWord    *allocLimit;    // ... lower limit of allocation
145     uintptr_t   allocSize;     // The preferred heap segment size
146     unsigned    allocCount;     // The number of allocations since the last GC
147     StackSpace  *stack;
148     ThreadObject *threadObject;  // Pointer to the thread object.
149     int         lastError;      // Last error from foreign code.
150     void        *signalStack;  // Stack to handle interrupts (Unix only)
151     bool        inML;          // True when this is in ML, false in the RTS
152 
153     // Get a TaskData pointer given the ML taskId.
154     // This is called at the start of every RTS function that may allocate memory.
155     // It is can be called safely to get the thread's own TaskData object without
156     // a lock but any call to get the TaskData for another thread must take the
157     // schedLock first in case the thread is exiting.
FindTaskForId(PolyWord taskId)158     static TaskData *FindTaskForId(PolyWord taskId) {
159         return *(TaskData**)(((ThreadObject*)taskId.AsObjPtr())->threadRef.AsObjPtr());
160     }
161 
162 private:
163     // If a thread has to block it will block on this.
164     PCondVar threadLock;
165     // External requests made are stored here until they
166     // can be actioned.
167     ThreadRequests requests;
168     // Pointer to the mutex when blocked. Set to NULL when it doesn't apply.
169     PolyObject *blockMutex;
170     // This is set to false when a thread blocks or enters foreign code,
171     // While it is true the thread can manipulate ML memory so no other
172     // thread can garbage collect.
173     bool inMLHeap;
174 
175     // In Linux, at least, we need to run a separate timer in each thread
176     bool runningProfileTimer;
177 
178 #ifdef HAVE_WINDOWS_H
179     LONGLONG lastCPUTime; // Used for profiling
180 #endif
181 public:
182     bool threadExited;
183 private:
184 #ifdef HAVE_PTHREAD_H
185     pthread_t threadId;
186 #endif
187 #ifdef HAVE_WINDOWS_H
188 public: // Because, on Cygwin, it's used in NewThreadFunction
189     HANDLE threadHandle;
190 private:
191 #endif
192 
193     friend class Processes;
194 };
195 
196 NORETURNFN(extern Handle exitThread(TaskData *mdTaskData));
197 
198 class ScanAddress;
199 
200 // Indicate what the main thread is doing if the profile
201 // timer goes off.
202 extern enum _mainThreadPhase {
203     MTP_USER_CODE=0,
204     MTP_GCPHASESHARING,
205     MTP_GCPHASEMARK,
206     MTP_GCPHASECOMPACT,
207     MTP_GCPHASEUPDATE,
208     MTP_GCQUICK,
209     MTP_SHARING,
210     MTP_EXPORTING,
211     MTP_SAVESTATE,
212     MTP_LOADSTATE,
213     MTP_PROFILING,
214     MTP_SIGHANDLER,
215     MTP_CYGWINSPAWN,
216     MTP_STOREMODULE,
217     MTP_LOADMODULE,
218     MTP_MAXENTRY
219 } mainThreadPhase;
220 
221 // Data structure used for requests from a thread to the root
222 // thread.  These are GCs or similar.
223 class MainThreadRequest
224 {
225 public:
MainThreadRequest(enum _mainThreadPhase phase)226     MainThreadRequest (enum _mainThreadPhase phase): mtp(phase), completed(false) {}
~MainThreadRequest()227     virtual ~MainThreadRequest () {} // Suppress silly GCC warning
228     const enum _mainThreadPhase mtp;
229     bool completed;
230     virtual void Perform() = 0;
231 };
232 
233 class PLock;
234 
235 // Class to wait for a given time or for an event, whichever comes first.
236 //
237 // A pointer to this class or a subclass is passed to ThreadPauseForIO.
238 // Because a thread may be interrupted or killed by another ML thread we
239 // don't allow any thread to block indefinitely.  Instead whenever a
240 // thread wants to do an operation that may block we have it enter a
241 // loop that polls for the desired condition and if it is not ready it
242 // calls ThreadPauseForIO.  The default action is to block for a short
243 // period and then return so that the caller can poll again.  That can
244 // limit performance when, for example, reading from a pipe so where possible
245 // we use a sub-class that waits until either input is available or it times
246 // out, whichever comes first, using "select" in Unix or MsgWaitForMultipleObjects
247 // in Windows.
248 // During a call to Waiter::Wait the thread is set as "not using ML memory"
249 // so a GC can happen while this thread is blocked.
250 class Waiter
251 {
252 public:
Waiter()253     Waiter() {}
~Waiter()254     virtual ~Waiter() {}
255     virtual void Wait(unsigned maxMillisecs);
256     static Waiter *defaultWaiter;
257 };
258 
259 #ifdef _WIN32
260 class WaitHandle: public Waiter
261 {
262 public:
WaitHandle(HANDLE h,unsigned maxWait)263     WaitHandle(HANDLE h, unsigned maxWait): m_Handle(h), m_maxWait(maxWait) {}
264     virtual void Wait(unsigned maxMillisecs);
265 private:
266     HANDLE m_Handle;
267     unsigned m_maxWait;
268 };
269 
270 #else
271 
272 // Unix: Wait until a file descriptor is available for input
273 class WaitInputFD: public Waiter
274 {
275 public:
WaitInputFD(int fd)276     WaitInputFD(int fd): m_waitFD(fd) {}
277     virtual void Wait(unsigned maxMillisecs);
278 private:
279     int m_waitFD;
280 };
281 #endif
282 
283 
284 // External interface to the Process module.  These functions are all implemented
285 // by the Processes class.
286 class ProcessExternal
287 {
288 public:
~ProcessExternal()289     virtual ~ProcessExternal() {} // Defined to suppress a warning from GCC
290 
291     virtual TaskData *GetTaskDataForThread(void) = 0;
292     virtual TaskData *CreateNewTaskData(Handle threadId, Handle threadFunction,
293                            Handle args, PolyWord flags) = 0;
294     // Request all ML threads to exit and set the result code.  Does not cause
295     // the calling thread itself to exit since this may be called on the GUI thread.
296     virtual void RequestProcessExit(int n) = 0;
297     // Exit from this thread.
298     virtual NORETURNFN(void ThreadExit(TaskData *taskData)) = 0;
299 
300     virtual void BroadcastInterrupt(void) = 0;
301 
302     virtual void BeginRootThread(PolyObject *rootFunction) = 0;
303 
304     // Called when a thread may block.  Returns some time later when perhaps
305     // the input is available.
306     virtual void ThreadPauseForIO(TaskData *taskData, Waiter *pWait) = 0;
307     // As ThreadPauseForIO but when there is no stream
ThreadPause(TaskData * taskData)308     virtual void ThreadPause(TaskData *taskData) { ThreadPauseForIO(taskData, Waiter::defaultWaiter); }
309 
310     // If a thread is blocking for some time it should release its use
311     // of the ML memory.  That allows a GC. ThreadUseMLMemory returns true if
312     // a GC was in progress.
313     virtual void ThreadUseMLMemory(TaskData *taskData) = 0;
314     virtual void ThreadReleaseMLMemory(TaskData *taskData) = 0;
315 
316     // Requests from the threads for actions that need to be performed by
317     // the root thread.
318     virtual void MakeRootRequest(TaskData *taskData, MainThreadRequest *request) = 0;
319 
320     // Deal with any interrupt or kill requests.
321     virtual bool ProcessAsynchRequests(TaskData *taskData) = 0;
322     // Process an interrupt request synchronously.
323     virtual void TestSynchronousRequests(TaskData *taskData) = 0;
324     // Process any events, synchronous or asynchronous.
325     virtual void TestAnyEvents(TaskData *taskData) = 0;
326 
327     // ForkFromRTS.  Creates a new thread from within the RTS.
328     virtual bool ForkFromRTS(TaskData *taskData, Handle proc, Handle arg) = 0;
329 
330     // Profiling control.
331     virtual void StartProfiling(void) = 0;
332     virtual void StopProfiling(void) = 0;
333 
334     // Find space for an object.  Returns a pointer to the start.  "words" must include
335     // the length word and the result points at where the length word will go.
336     // If the allocation succeeds it may update the allocation values in the taskData object.
337     // If the heap is exhausted it may set this thread (or other threads) to raise an exception.
338     virtual PolyWord *FindAllocationSpace(TaskData *taskData, POLYUNSIGNED words, bool alwaysInSeg) = 0;
339 
340     // Signal handling support.  The ML signal handler thread blocks until it is
341     // woken up by the signal detection thread.
342     virtual bool WaitForSignal(TaskData *taskData, PLock *sigLock) = 0;
343     virtual void SignalArrived(void) = 0;
344 
345     virtual poly_exn* GetInterrupt(void) = 0;
346 };
347 
348 // Return the number of processors.  Used when configuring multi-threaded GC.
349 extern unsigned NumberOfProcessors(void);
350 extern unsigned NumberOfPhysicalProcessors(void);
351 
352 extern ProcessExternal *processes;
353 
354 extern struct _entrypts processesEPT[];
355 
356 #endif
357