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 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
|
/*
Title: Main program
Copyright (c) 2000-7
Cambridge University Technical Services Limited
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
*/
#ifdef WIN32
#include "winconfig.h"
#else
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_ASSERT_H
#include <assert.h>
#define ASSERT(x) assert(x)
#else
#define ASSERT(x) 0
#endif
#ifdef HAVE_TCHAR_H
#include <tchar.h>
#endif
#include "globals.h"
#include "sys.h"
#include "gc.h"
#include "run_time.h"
#include "machine_dep.h"
#include "version.h"
#include "diagnostics.h"
#include "processes.h"
#include "mpoly.h"
#include "scanaddrs.h"
#include "save_vec.h"
#include "polyexports.h"
#include "memmgr.h"
#include "pexport.h"
#ifdef WINDOWS_PC
#include "Console.h"
#endif
static void InitHeaderFromExport(exportDescription *exports);
NORETURNFN(static void Usage(const char *message));
// Return the entry in the io vector corresponding to the Poly system call.
PolyWord *IoEntry(unsigned sysOp)
{
MemSpace *space = gMem.IoSpace();
return space->bottom + sysOp * IO_SPACING;
}
/* This macro must make a whole number of chunks */
#define K_to_words(k) ROUNDUP((k) * (1024 / sizeof(PolyWord)),BITSPERWORD)
struct _userOptions userOptions;
UNSIGNEDADDR exportTimeStamp;
unsigned hsize, isize, msize;
struct __argtab {
const char *argName, *argHelp;
unsigned scale, *argVal;
} argTable[] =
{
{ "-H", "Initial heap size (MB)", 1024, &hsize }, // Leave this for the moment
{ "--heap", "Initial heap size (MB)", 1024, &hsize },
{ "--immutable", "Initial size of immutable buffer (MB)", 1024, &isize },
{ "--mutable", "Initial size of mutable buffer(MB)", 1024, &msize },
{ "--debug", "Debug options", 1, &userOptions.debug }
};
/* In the Windows version this is called from WinMain in Console.c */
int polymain(int argc, char **argv, exportDescription *exports)
{
POLYUNSIGNED memsize = GetPhysicalMemorySize();
if (memsize == 0) // Unable to determine memory size so default to 64M.
memsize = 64 * 1024 * 1024;
// Set the default initial size to half the memory.
hsize = memsize / 2 / 1024;
isize = 0; /* use standard default */
msize = 0; /* use standard default */
/* Get arguments. */
memset(&userOptions, 0, sizeof(userOptions)); /* Reset it */
// Get the program name for CommandLine.name. This is allowed to be a full path or
// just the last component so we return whatever the system provides.
if (argc > 0)
userOptions.programName = argv[0];
else
userOptions.programName = ""; // Set it to a valid empty string
char *importFileName = 0;
userOptions.debug = 0;
userOptions.noDisplay = false;
userOptions.user_arg_count = 0;
userOptions.user_arg_strings = (char**)malloc(argc * sizeof(char*)); // Enough room for all of them
// Process the argument list removing those recognised by the RTS and adding the
// remainder to the user argument list.
for (int i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
bool argUsed = false;
for (unsigned j = 0; j < sizeof(argTable)/sizeof(argTable[0]); j++)
{
unsigned argl = strlen(argTable[j].argName);
if (strncmp(argv[i], argTable[j].argName, argl) == 0)
{
char *p;
if (strlen(argv[i]) == argl)
{ // If it has used all the argument pick the next
i++;
p = argv[i];
}
else
{
p = argv[i]+argl;
if (*p == '=') p++; // Skip an equals sign
}
if (i >= argc)
printf("Incomplete %s option\n", argTable[j].argName);
else
*(argTable[j].argVal) = atoi(p) * argTable[j].scale;
argUsed = true;
break;
}
}
if (! argUsed) // Add it to the user args.
userOptions.user_arg_strings[userOptions.user_arg_count++] = argv[i];
}
else if (exports == 0 && importFileName == 0)
importFileName = argv[i];
else
userOptions.user_arg_strings[userOptions.user_arg_count++] = argv[i];
}
if (exports == 0 && importFileName == 0)
Usage("Missing import file name");
if (hsize < 500) Usage ("Invalid heap-size value");
if (hsize < isize) hsize = isize;
if (hsize < msize) hsize = msize;
if (msize == 0) msize = 4 * 1024 + hsize / 5; /* set default mutable buffer size */
if (isize == 0) isize = hsize - msize; /* set default immutable buffer size */
// Set the heap size and segment sizes. We allocate in units of this size,
userOptions.heapSize = K_to_words(hsize);
userOptions.immutableSegSize = K_to_words(isize);
userOptions.mutableSegSize = K_to_words(msize);
// The space we need to have free at the end of a partial collection. If we have less
// than this we do a full GC.
// For an immutable area this is zero. For the mutable area, though, this is 80% of the
// mutable segment size since we allocate new objects in the mutable area and this
// determines how soon we will need to do another GC.
userOptions.immutableMinFree = 0;
userOptions.mutableMinFree = userOptions.mutableSegSize - userOptions.mutableSegSize / 5;
// This is the space we try to have free at the end of a major collection. If
// we have less than this we allocate another segment.
userOptions.immutableFreeSpace = userOptions.immutableSegSize/2; // 50% full
if (userOptions.immutableFreeSpace < userOptions.immutableMinFree)
userOptions.immutableFreeSpace = userOptions.immutableMinFree;
// For the mutable area it is 90% of the segment size.
userOptions.mutableFreeSpace = userOptions.mutableSegSize - userOptions.mutableSegSize/10;
if (userOptions.mutableFreeSpace < userOptions.mutableMinFree)
userOptions.mutableFreeSpace = userOptions.mutableMinFree;
/* initialise the run-time system before opening the database */
init_run_time_system();
CreateHeap();
PolyObject *rootFunction = 0;
if (exports != 0)
{
InitHeaderFromExport(exports);
rootFunction = (PolyObject *)exports->rootFunction;
}
else
{
if (importFileName != 0)
rootFunction = ImportPortable(importFileName);
if (rootFunction == 0)
exit(1);
}
/* Initialise the interface vector. */
machineDependent->InitInterfaceVector(); /* machine dependent entries. */
// This word has a zero value and is used for null strings.
add_word_to_io_area(POLY_SYS_emptystring, PolyWord::FromUnsigned(0));
// This is used to represent zero-sized vectors.
// N.B. This assumes that the word before is zero because it's
// actually the length word we want to be zero here.
add_word_to_io_area(POLY_SYS_nullvector, PolyWord::FromUnsigned(0));
/* The standard input and output streams are persistent i.e. references
to the the standard input in one session will refer to the standard
input in the next. */
add_word_to_io_area(POLY_SYS_stdin, PolyWord::FromUnsigned(0));
add_word_to_io_area(POLY_SYS_stdout, PolyWord::FromUnsigned(1));
add_word_to_io_area(POLY_SYS_stderr, PolyWord::FromUnsigned(2));
re_init_run_time_system();
// Set up the initial process to run the root function.
processes->BeginRootThread(rootFunction);
finish(0);
/*NOTREACHED*/
return 0; /* just to keep lint happy */
}
void Uninitialise(void)
// Close down everything and free all resources. Stop any threads or timers.
{
uninit_run_time_system();
}
void finish (int n)
{
// Make sure we don't get any interrupts once the destructors are
// applied to globals or statics.
Uninitialise();
#if defined(WINDOWS_PC)
ExitThread(n);
#else
exit (n);
#endif
}
// Print a message and exit if an argument is malformed.
void Usage(const char *message)
{
if (message)
printf("%s\n", message);
for (unsigned j = 0; j < sizeof(argTable)/sizeof(argTable[0]); j++)
{
printf("%s <%s>\n", argTable[j].argName, argTable[j].argHelp);
}
fflush(stdout);
#if defined(WINDOWS_PC)
if (useConsole)
{
MessageBox(hMainWindow, _T("Poly/ML has exited"), _T("Poly/ML"), MB_OK);
}
#endif
exit (1);
}
// Return a string containing the argument names. Can be printed out in response
// to a --help argument. It is up to the ML application to do that since it may well
// want to produce information about any arguments it chooses to process.
char *RTSArgHelp(void)
{
static char buff[2000];
char *p = buff;
for (unsigned j = 0; j < sizeof(argTable)/sizeof(argTable[0]); j++)
{
int spaces = sprintf(p, "%s <%s>\n", argTable[j].argName, argTable[j].argHelp);
p += spaces;
}
ASSERT((unsigned)(p - buff) < (unsigned)sizeof(buff));
return buff;
}
void InitHeaderFromExport(exportDescription *exports)
{
// Check the structure sizes stored in the export structure match the versions
// used in this library.
if (exports->structLength != sizeof(exportDescription) ||
exports->memTableSize != sizeof(memoryTableEntry) ||
exports->rtsVersion < FIRST_supported_version ||
exports->rtsVersion > LAST_supported_version)
{
#if (FIRST_supported_version == LAST_supported_version)
Exit("The exported object file has version %0.2f but this library supports %0.2f",
((float)exports->rtsVersion) / 100.0,
((float)FIRST_supported_version) / 100.0);
#else
Exit("The exported object file has version %0.2f but this library supports %0.2f-%0.2f",
((float)exports->rtsVersion) / 100.0,
((float)FIRST_supported_version) / 100.0,
((float)LAST_supported_version) / 100.0);
#endif
}
// We could also check the RTS version and the architecture.
exportTimeStamp = exports->timeStamp; // Needed for load and save.
memoryTableEntry *memTable = exports->memTable;
for (unsigned i = 0; i < exports->memTableEntries; i++)
{
// Construct a new space for each of the entries.
if (i == exports->ioIndex)
(void)gMem.InitIOSpace((PolyWord*)memTable[i].mtAddr, memTable[i].mtLength/sizeof(PolyWord));
else
(void)gMem.NewPermanentSpace((PolyWord*)memTable[i].mtAddr,
memTable[i].mtLength/sizeof(PolyWord), (memTable[i].mtFlags & MTF_WRITEABLE) != 0,
(memTable[i].mtFlags & MTF_NO_OVERWRITE) != 0, memTable[i].mtIndex);
}
}
|