File: main.m

package info (click to toggle)
adun.app 0.8.2-1
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 6,824 kB
  • ctags: 713
  • sloc: objc: 49,683; ansic: 4,680; sh: 523; python: 79; makefile: 67; cpp: 33
file content (433 lines) | stat: -rwxr-xr-x 13,782 bytes parent folder | download
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
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
#define _GNU_SOURCE
#include <stdio.h>
#include <float.h>
#include <fenv.h>
#include <unistd.h>
#ifndef __FREEBSD__
#include <mcheck.h>
#endif
#include <stdlib.h>
#include <locale.h>
#include "AdunKernel/AdCoreAdditions.h"
#include "AdunKernel/AdunController.h"
#include "AdunKernel/AdunCore.h"
#include "AdunKernel/AdunIOManager.h"

/**
\defgroup Base AdunBase Library 
\ingroup Kernel
**/

/**

\defgroup Kernel Kernel

The Kernel part of Adun contains the AdunCore simulation program along with the AdunKernel framework and the AdunBase
library on which it is built. 
**/

//Indicates if we have begun to deallocate the core
BOOL coreDealloc;

void printHelp(void);

void printHelp(void)
{
	GSPrintf(stdout, @"\nUsage: AdunCore [options]\n\n");
	GSPrintf(stdout, @"All Options must be specified as option value pairs\n");
	GSPrintf(stdout, @"Invalid options are ignored\n\n");
	GSPrintf(stdout, @"Command Line Options\n\n");
	GSPrintf(stdout, @"  Required:\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-Template", @"A valid Adun template file"); 
	GSPrintf(stdout, @"\n  Optional:\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-ExternalObjects", @"A dictionary in plist format.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Its contents extend the externalObjects section of the template.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"If there are duplicate keys this dictionary takes precedence.\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-SimulationOutputDir", @"Directory where simulation data directory will be stored.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Default value: SimulationOutput\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-ControllerOutputDir", @"Directory where controller data will be stored.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Default value: ControllerOutput\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-CreateLogFiles", @"If YES log files are created. If NO they are not.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Default value: YES\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-LogFile", @"File where the program output will be written.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Default value: AdunCore.log\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-ErrorFile", @"File where program errors and warnings will be written.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Default value: AdunCore.errors\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-RedirectOutput", @"If YES the log files will be moved to the simulation output directory.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Default value: YES.\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-RunInteractive", @"If YES the simulation loop is spawned as a separate thread.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"The main thread then enters a run loop and can serve external requests.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"If NO then interaction is not possible with the simulation.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Default value: NO\n");
	GSPrintf(stdout, @"\t%-25@%-@\n", @"-ConnectToAdServer", @"If YES the simulation registers its existance with a local AdServer daemon.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"This allows the simulation to be viewed and controlled from the Adun GUI.");
	GSPrintf(stdout, @"\t%25@%-@\n", @"", @"Default value: NO\n");

}

//Wrapper around AdLogError adding some extra print outs
void logError(NSError*);

void logError(NSError* error)
{
	GSPrintf(stdout, @"Simulation exited due to an error. See the error log for more details\n");
	NSLog(@"Detected error at top level - Simulation exiting");
	NSLog(@"Error details follow\n");
	AdLogError(error);
}

void uncaughtExceptionHandler(NSException* exception);

void uncaughtExceptionHandler(NSException* exception)
{
	NSError* error;
	AdIOManager* ioManager;
	
	ioManager = [AdIOManager appIOManager];
	NSWarnLog(@"Caught an %@ exception at the top level", [exception name]);
	NSWarnLog(@"Reason %@", [exception reason]);
	NSWarnLog(@"User info %@", [exception userInfo]);

	error = AdCreateError(AdunCoreErrorDomain,
				AdCoreUnexpectedExceptionError,
				@"Caught unexpected exception",
				@"This is probably due to a programming error in the program or the AdunKernel library",
				@"Notify the adun developers supplying the log for the simulation run");
	NSWarnLog(@"Error information follows ...");			
	logError(error);
	NSWarnLog(@"Cleaning up core");	
	if([ioManager isConnected])
		[ioManager closeConnection: error];

	[ioManager release];
#ifdef GNUSTEP
	//Not really necessary but anyway ...
	[[NSAutoreleasePool currentPool] release];
#endif	
	exit([error code]);
}

//Logs the precision of the double type for the current processor
//Checks which floating point exceptions are enabled
//Clears floating point traps if any are set	

void floatingPointSettings(void);

void floatingPointSettings(void)
{
	GSPrintf(stdout, @"Floating Point Parameters for DOUBLE type.\n\n");
	GSPrintf(stdout, @"\tMantissa precision (base 2)  : %d.\n", DBL_MANT_DIG); 
	GSPrintf(stdout, @"\tMantissa precision (base 10) : %d.\n", DBL_DIG); 
	GSPrintf(stdout, @"\tMinumum exponent: %d -  Corresponds to %d in base 10.\n", DBL_MIN_EXP, DBL_MIN_10_EXP);
	GSPrintf(stdout, @"\tMaximum exponent: %d -  Corresponds to %d in base 10.\n", DBL_MAX_EXP, DBL_MAX_10_EXP);
	GSPrintf(stdout, @"\tMinumum floating point number %E\n", DBL_MIN);
	GSPrintf(stdout, @"\tMaximum floating point number %E\n", DBL_MAX);
	GSPrintf(stdout, @"\tEpsilon: %E.\n", DBL_EPSILON);
	GSPrintf(stdout, @"\tEpsilon is the smallest number such that '1.0 + epsilon != 1.0' is true.\n\n");

	AdFloatingPointExceptionMask = 0;

#ifdef FE_DIVBYZERO
		AdFloatingPointExceptionMask = AdFloatingPointExceptionMask | FE_DIVBYZERO;
		GSPrintf(stdout, @"FE_DIVBYZERO detection supported and enabled\n");
#else
		GSPrintf(stdout, @"FE_DIVBYZERO not supported by the processor\n");
#endif

#ifdef FE_OVERFLOW
		AdFloatingPointExceptionMask = AdFloatingPointExceptionMask | FE_OVERFLOW;
		GSPrintf(stdout, @"FE_OVERFLOW detection supported and enabled\n");
#else
		GSPrintf(stdout, @"FE_OVERFLOW not supported by the processor\n");
#endif

#ifdef FE_UNDERFLOW
		AdFloatingPointExceptionMask = AdFloatingPointExceptionMask | FE_UNDERFLOW;
		GSPrintf(stdout, @"FE_UNDERFLOW detection supported and enabled\n");
#else
		GSPrintf(stdout, @"FE_UNDERFLOW not supported by the processor\n");
#endif

#ifdef FE_INVALID
		AdFloatingPointExceptionMask = AdFloatingPointExceptionMask | FE_INVALID;
		GSPrintf(stdout, @"FE_INVALID detection supported and enabled\n");
#else
		GSPrintf(stdout, @"FE_INVALID not supported by the processor\n");
#endif

/*
 * Disabling exception trapping is not supported on Mac OSX.
 * This means any floating point exception will cause SIGFPE
 * rendering the checking useless - may be a way around this.
 */

#if NeXT_RUNTIME != 1
	//disable traping of the supported errors
	fedisableexcept(AdFloatingPointExceptionMask);
#endif	
	
}

void registerDefaults(void);

void registerDefaults(void)
{
	char *locale = "C";
	NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
	NSMutableSet* debugLevels;
	NSProcessInfo  *processInfo = [NSProcessInfo processInfo];

	setlocale(LC_ALL, locale);

	debugLevels = [processInfo debugSet];
	[debugLevels addObjectsFromArray: 
		[[NSUserDefaults standardUserDefaults] objectForKey: @"DebugLevels"]];
	[defaults setObject: [NSNumber numberWithBool: NO] forKey:@"OutputMemoryStatistics"];
	[defaults setObject: [NSNumber numberWithBool: NO] forKey:@"TraceMemory"];
	[defaults setObject: [NSNumber numberWithBool: NO] forKey: @"ConnectToAdServer"];
	[defaults setObject: [NSNumber numberWithBool: NO] forKey: @"RunInteractive"];
	[defaults setObject: @"Cell" forKey: @"ListManagementMethod"];
	[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
	[[NSUserDefaults standardUserDefaults] synchronize];
}

int main(int argc, char** argv)
{
	int errorCode;
	id pool = [[NSAutoreleasePool alloc] init];	
	NSError* error;
	NSUserDefaults* userDefaults;
	AdIOManager* ioManager = nil;
	AdCore* core;
	id results, fileName;
 	
	error = nil;
	NSSetUncaughtExceptionHandler(uncaughtExceptionHandler);
	//Turn stack trace on
#ifdef GNUSTEP	
	setenv("GNUSTEP_STACK_TRACE", "YES", 1);
#endif	
	registerDefaults();
	userDefaults = [NSUserDefaults standardUserDefaults];

	//setup tracing
	if([userDefaults boolForKey: @"TraceMemory"] == YES)
	{
#ifndef __FREEBSD__
		mtrace();
		mcheck(NULL);
#endif
	}

	ioManager = [AdIOManager appIOManager];
	
	GSPrintf(stdout, @"\nChecking program directory structure\n\n");
	if(![ioManager checkProgramDirectories: &error])
	{
		logError(error);
		errorCode = [error code];
		printHelp();
		[ioManager release];
		[pool release];
		exit(errorCode);
	}

	/*
	 * Process the command line and determine the run mode.
	 */
	GSPrintf(stdout, @"\nProcessing command line\n\n");
	if(![ioManager processCommandLine: &error])
	{
		logError(error);
		errorCode = [error code];
		printHelp();
		[ioManager release];
		[pool release];
		exit(errorCode);
	}

	GSPrintf(stdout, @"\nCreating log files\n\n");
	if(![ioManager createLogFiles: &error])
	{
		logError(error);
		errorCode = [error code];
		printHelp();
		[ioManager release];
		[pool release];
		exit(errorCode);
	}
	
	if([userDefaults boolForKey: @"ConnectToAdServer"])
	{
		GSPrintf(stdout, @"\nConnecting to AdServer ...\n");
		if(![ioManager connectToServer: &error])
		{
			logError(error);
			//Exit if we are in server run mode
			if([ioManager runMode] == AdCoreServerRunMode)
			{
				errorCode = [error code];
				printHelp();
				[ioManager release];
				[pool release];
				exit(errorCode);
			}	
			else
			{
				NSWarnLog(@"Continuing since program is in command line mode");
				GSPrintf(stdout, @"Unable to connect to an AdServer instance - Continuing\n");
				error = nil;
			}	
		}
		else
			GSPrintf(stdout, @"Connected\n");
	}

	GSPrintf(stdout, @"%@%@", divider, divider);
	GSPrintf(stdout,  @"Checking floating point accuracy and exception detection support\n\n");
	floatingPointSettings();
	GSPrintf(stdout, @"%@", divider);
	
	GSPrintf(stdout, @"%@", divider);
	GSPrintf(stdout, @"Loading program data\n");
	if(![ioManager loadData: &error])
	{
		logError(error);
		errorCode = [error code];
		if([ioManager isConnected])
			[ioManager closeConnection: error];

		printHelp();
		[ioManager release];
		[pool release];
		exit(errorCode);
	}
	GSPrintf(stdout, @"Program data loaded\n\n");
	GSPrintf(stdout, @"Creating simulation output directory\n\n");
	if(![ioManager createSimulationOutputDirectory: &error])
	{
		logError(error);
		errorCode = [error code];
		if([ioManager isConnected])
			[ioManager closeConnection: error];

		printHelp();
		[ioManager release];
		[pool release];
		exit(errorCode);
	}
	GSPrintf(stdout, @"\nDone\n");
	GSPrintf(stdout, @"%@", divider);
	
	fflush(stdout);
	core = [AdCore new];
	[ioManager setCore: core];
	if(![core setup: &error])
	{
		logError(error);
		errorCode = [error code];
		if([ioManager isConnected])
			[ioManager closeConnection: error];

		printHelp();
		[core release];
		[ioManager release];
		[pool release];
		exit(errorCode);
	}
	
	/*
	 * Exceptions during the call to main can only be due
	 * to core commands.
	 */
	NS_DURING
	{
		GSPrintf(stdout, @"%@", divider);
		GSPrintf(stdout, @"Beginning simulation\n\n");
		fflush(stdout);
		[core main: nil];
		GSPrintf(stdout, @"\nSimulation complete\n");
		error = [core terminationError];
		if(error != nil)
		{
			NSWarnLog(@"Simulation ended due to an error");
			logError(error);
		}	
	}
	NS_HANDLER
	{
		//main exited due to an exception
		//If the controller running the simulation was programmed properly
		//(Contollers should not let exceptions escape)
		//then this can only have been caused by an interactive command
		//End the controller thread without entering the normal end sequence.
		if([core simulationIsRunning])
			[[core controller] terminateSimulation: core];

		NSWarnLog(@"Caught an %@ exception", [localException name]);
		NSWarnLog(@"Reason %@", [localException reason]);
		NSWarnLog(@"User info %@", [localException userInfo]);
		error = AdCreateError(AdunCoreErrorDomain,
				AdCoreUnexpectedExceptionError,
				@"Caught unexpected exception",
				@"This is probably due to a programming error in the program or the AdunKernel library",
				@"Notify the adun developers supplying the log for the simulation run");
	}
	NS_ENDHANDLER
	GSPrintf(stdout, @"%@", divider);
	
	/*
	 * Begin clean up procedure -
	 * 1) Core clean up
	 *	   1) Write simulation energies
	 *	   2) Write controller results
	 * 2) If we are connected to a server -
	 *	   1) Send controller results to server
	 *	   2) Notify server of errors
	 *	   3) Close connections
	 * 3) Set exit code
	 */
	GSPrintf(stdout, @"%@", divider);
	GSPrintf(stdout, @"Beginning core clean up\n");
	[core cleanUp];
	
	if([ioManager isConnected])
	{
		GSPrintf(stdout, @"Sending controller results\n");
		[ioManager sendControllerResults: 
			[core controllerResults: nil]];
		GSPrintf(stdout, @"Notifying server of any errors and closing connection.\n");
		[ioManager closeConnection: error];
	}
	GSPrintf(stdout, @"Clean up complete\n");
	
	if(error != nil)
	{
		NSWarnLog(@"Logging termination error");
		logError(error);
		NSWarnLog(@"Done");
	 	errorCode = [error code];
	}	
	else
		errorCode = 0;
	
	fflush(stdout);
	NSWarnLog(@"Deallocing core");
	[core release];
	NSWarnLog(@"Deallocing manager");
	[ioManager release];
	NSWarnLog(@"Done");
	GSPrintf(stdout, @"Goodbye!\n");
#ifdef GNUSTEP
	//Trying to release this pool using cocoa
	//causes the program to hang. Its not really
	//necessary as I dont think the dealloc method
	//of any of the objects in it needs to be executed.
	//However we'll keep it on gnustep since it works there.	
	[pool release];
#endif	

	return errorCode;
}