1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
/*
Title: Lightweight process library
Author: David C.J. Matthews
Copyright (c) 2007,8 David C.J. Matthews
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _PROCESSES_H_
#define _PROCESSES_H_
#ifdef WIN32
#include "winconfig.h"
#else
#include "config.h"
#endif
#include "globals.h"
#include "rts_module.h"
#include "save_vec.h"
#include "noreturn.h"
class SaveVecEntry;
typedef SaveVecEntry *Handle;
class StackObject;
class PolyWord;
class ScanAddress;
class MDTaskData;
class Exporter;
#define MIN_HEAP_SIZE 4096 // Minimum and initial heap segment size (words)
// This is the ML "thread identifier" object. The fields
// are read and set by the ML code.
class ThreadObject: public PolyObject {
public:
PolyWord index; // Tagged integer with the index into the taskArray
// Not used by ML
PolyWord flags; // Tagged integer containing flags indicating how interrupts
// are handled. Set by ML but only by the thread itself
PolyWord threadLocal; // Head of a list of thread-local store items.
// Handled entirely by ML but only by the thread.
PolyWord requestCopy; // A tagged integer copy of the "requests" field.
// This is provided so that ML can easily test if there
// is an interrupt pending.
};
// Per-thread data.
class TaskData {
public:
TaskData();
virtual ~TaskData();
void FillUnusedSpace(void);
virtual void GarbageCollect(ScanAddress *process) = 0;
virtual void Lock(void) = 0;
virtual void Unlock(void) = 0;
// Increment the allocation count and adjust the allocation size for
// the next allocation. Doubles the allocation for next time.
virtual void IncrementAllocationCount(void) { allocCount++; allocSize = allocSize*2; }
MDTaskData *mdTaskData; // Machine-specific task data.
SaveVec saveVec;
PolyWord *allocPointer; // Allocation pointer - decremented towards...
PolyWord *allocLimit; // ... lower limit of allocation
POLYUNSIGNED allocSize; // The preferred heap segment size
unsigned allocCount; // The number of allocations since the last GC
StackObject *stack;
ThreadObject *threadObject; // Pointer to the thread object.
int lastError; // Last error from foreign code.
Handle x_ehandle, y_ehandle; // Space to extend short precision args.
void *signalStack; // Stack to handle interrupts (Unix only)
bool pendingInterrupt; // The thread should trap into the RTS soon.
private:
PolyWord x_extend[2], y_extend[2];
SaveVecEntry x_extend_addr, y_extend_addr;
};
NORETURNFN(extern Handle exitThread(TaskData *mdTaskData));
Handle AtomicIncrement(TaskData *taskData, Handle mutexp);
Handle AtomicDecrement(TaskData *taskData, Handle mutexp);
Handle ThreadSelf(TaskData *taskData);
Handle ThreadDispatch(TaskData *taskData, Handle args, Handle code);
class ScanAddress;
// Data structure used for requests from a thread to the root
// thread. These are GCs or similar.
class MainThreadRequest
{
public:
MainThreadRequest (): completed(false) {}
virtual ~MainThreadRequest () {} // Suppress silly GCC warning
bool completed;
virtual void Perform() = 0;
};
class PLock;
// External interface to the Process module. These functions are all implemented
// by the Processes class.
class ProcessExternal
{
public:
virtual ~ProcessExternal() {} // Defined to suppress a warning from GCC
virtual TaskData *GetTaskDataForThread(void) = 0;
// Request all ML threads to exit and set the result code. Does not cause
// the calling thread itself to exit since this may be called on the GUI thread.
virtual void Exit(int n) = 0;
// Exit from this thread.
virtual NORETURNFN(void ThreadExit(TaskData *taskData)) = 0;
virtual void BroadcastInterrupt(void) = 0;
virtual void BeginRootThread(PolyObject *rootFunction) = 0;
// Called when a thread may block. Never returns. May cause a retry.
virtual NORETURNFN(void BlockAndRestart(TaskData *taskData, int fd,
bool posixInterruptable, int ioCall)) = 0;
// Called when a thread may block. Returns some time later when perhaps
// the input is available.
virtual void ThreadPauseForIO(TaskData *taskData, int fd) = 0;
// As ThreadPauseForIO but when there is no file descriptor
virtual void ThreadPause(TaskData *taskData) { ThreadPauseForIO(taskData, -1); }
// If a thread is blocking for some time it should release its use
// of the ML memory. That allows a GC. ThreadUseMLMemory returns true if
// a GC was in progress.
virtual void ThreadUseMLMemory(TaskData *taskData) = 0;
virtual void ThreadReleaseMLMemory(TaskData *taskData) = 0;
// Requests from the threads for actions that need to be performed by
// the root thread.
virtual void MakeRootRequest(TaskData *taskData, MainThreadRequest *request) = 0;
// Deal with any interrupt or kill requests.
virtual bool ProcessAsynchRequests(TaskData *taskData) = 0;
// Process an interrupt request synchronously.
virtual void TestSynchronousRequests(TaskData *taskData) = 0;
// ForkFromRTS. Creates a new thread from within the RTS.
virtual bool ForkFromRTS(TaskData *taskData, Handle proc, Handle arg) = 0;
// Profiling control.
virtual void StartProfiling(void) = 0;
virtual void StopProfiling(void) = 0;
// Find space for an object. Returns a pointer to the start. "words" must include
// the length word and the result points at where the length word will go.
// If the allocation succeeds it may update the allocation values in the taskData object.
// If the heap is exhausted it may set this thread (or other threads) to raise an exception.
virtual PolyWord *FindAllocationSpace(TaskData *taskData, POLYUNSIGNED words, bool alwaysInSeg) = 0;
// Signal handling support. The ML signal handler thread blocks until it is
// woken up by the signal detection thread.
virtual bool WaitForSignal(TaskData *taskData, PLock *sigLock) = 0;
virtual void SignalArrived(void) = 0;
// After a Unix fork we only have a single thread in the new process.
virtual void SetSingleThreaded(void) = 0;
};
extern ProcessExternal *processes;
#define IO_SPACING 8 // This is a bit of a mess.
#endif
|