1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 1989-2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * END LICENSE BLOCK */
22
23/*
24 * VERSION	$Id: init.c,v 1.9 2013/09/28 00:25:39 jschimpf Exp $
25 */
26
27/****************************************************************************
28 *
29 *	init.c
30 *	------
31 *
32 *	Initialisation routines for ECLiPSe
33 *
34 *
35 ***************************************************************************/
36
37#include 	"config.h"
38#include        "sepia.h"
39#include 	"types.h"
40#include	"embed.h"
41#include 	"error.h"
42#include 	"mem.h"
43#include 	"dict.h"
44#include	"module.h"
45#include	"os_support.h"
46#include	"ec_io.h"
47
48#include <errno.h>
49#include <stdio.h>	/* for sprintf() */
50#include <stdlib.h>	/* for exit() */
51
52#ifdef HAVE_STRING_H
53#include <string.h>
54#endif
55
56#ifdef HAVE_SYS_MMAN_H
57#include	<sys/mman.h>
58#endif
59
60
61
62/*
63 * EXTERN declarations
64 */
65
66extern int	io_init(int flags);
67
68
69extern void	bip_arith_init(int flags),
70		bip_array_init(int flags, char *installation_dir),
71		bip_comp_init(int flags),
72		bip_control_init(int flags),
73		bip_db_init(int flags),
74		bip_delay_init(int flags),
75		bip_domain_init(int flags),
76                bip_elipsys_fd_init(int flags),
77		bip_emu_init(int flags),
78		bip_gc_init(int flags),
79		bip_io_init(int flags),
80		bip_load_init(int flags),
81		bip_misc_init(int flags),
82		bip_module_init(int flags),
83		bip_op_init(int flags),
84		bip_parallel_init(),
85		bip_copy_init(int flags),
86		bip_serialize_init(int flags),
87		bip_record_init(int flags),
88		bip_store_init(int flags),
89		bip_shelf_init(int flags),
90		bip_bag_init(int flags),
91		bip_heapevent_init(int flags),
92		bip_strings_init(int flags),
93		bip_tconv_init(int flags),
94		code_init(int flags),
95		compiler_init(int flags),
96		dict_init(int flags),
97		emu_init(int flags, int vm_options),
98		error_init(int flags),
99		exit_mps(),
100		handlers_init(int flags),
101		handlers_fini(),
102		lex_init(int flags),
103		malloc_init(void),
104		megalog_boot_init(),
105		megalog_init(),
106		megalog_end(),
107		mem_init(int flags),
108		mem_fini(void),
109		module_init(int flags),
110		opaddr_init(void),
111		op_init(int flags),
112		parallel_init(),
113		msg_init(),
114		read_init(int flags),
115#ifdef SAVEDSTATES
116		save_res_init(),
117#endif
118		setup_mps(),
119		worker_init(),
120		write_init(int flags);
121
122extern void	kegi_init(),
123		user_init();
124
125extern void	short_sleep();
126
127extern void  default_panic(const char *what, const char *where);
128extern char * eclipsehome(void);
129
130/*
131 * GLOBAL function declarations
132 */
133
134void		ec_worker_cleanup(void);
135
136/*
137 * LOCAL function declarations
138 */
139
140static void	_make_error_message(int err, char *where, char *buf),
141		wait_for_flag(volatile int *pflag, int mask);
142
143static char * arg1 = "Embedded ECLiPSE";
144
145/*
146 * GLOBAL variable definitions
147 */
148
149/* added = {} initialisation (which does nothing) to work around MinGW bug
150   with gcc 4.2 so that entry for ec_ will be generated for eclipse.def
151   (Kish Shen 2010-09-24)
152*/
153t_eclipse_data	ec_ = {};
154
155/* TODO: move the following into ec_ on main branch */
156char *ec_eclipse_home;		/* canonical, hp_allocated */
157
158
159/*
160 * The ec_options structure is
161 * - statically initialised
162 * - can be overwritten by the embedding application before ec_init()
163 * - is pure input, i.e. must not be changed by eclipse itself
164 * - memory pointed to by members is owned by host application, not ECLiPSe
165 */
166
167t_eclipse_options ec_options =
168{
169	/* option_p */
170	0,
171
172	/* mapfile */
173	(char *) NULL,
174
175	/* parallel_worker */
176	0,
177
178	/* io_option */
179	SHARED_IO,
180
181	/* Argv,Argc */
182	(char **) &arg1,
183	1,
184
185	/* rl */
186#if defined(HAVE_READLINE)
187	 1,
188#else
189	 0,
190#endif
191
192	/* localsize globalsize */
193#if defined(HAVE_MMAP) || defined(_WIN32)
194	VIRTUAL_LOCAL_STACK_DEFAULT*MB*2*SIZEOF_WORD,
195	VIRTUAL_GLOBAL_STACK_DEFAULT*MB*2*SIZEOF_WORD,
196#else
197#define KB 1024
198#define DEFAULT_LOCAL		200*KB
199#define DEFAULT_GLOBAL		750*KB
200	DEFAULT_LOCAL,DEFAULT_GLOBAL,
201#endif
202	/* privatesize,sharedsize */
203	VIRTUAL_HEAP_DEFAULT*MB*2*SIZEOF_WORD,
204	VIRTUAL_SHARED_DEFAULT*MB*2*SIZEOF_WORD,
205
206	/* user_panic */
207	default_panic,
208
209	/* allocation */
210#if defined(HAVE_MMAP) || defined(_WIN32)
211#ifdef sun4_0
212	ALLOC_FIXED,
213#else
214	ALLOC_VIRTUAL,
215#endif
216#else
217	ALLOC_PRE,
218#endif
219
220	/* default_module */
221	"eclipse",
222
223	/* eclipse_home, input, non-canonical */
224	(char *) 0,
225
226	/* init_flags */
227	(INIT_SHARED|INIT_PRIVATE|INIT_ENGINE|INIT_PROCESS),
228
229	/* debug_level */
230	0,
231
232	/* default_language */
233	(char *) 0
234};
235
236
237/*----------------------------------------------------------------
238 * Initialisation
239 *
240 * init_flags indicates what parts of the system need to be
241 * initialised (bit-significant flags):
242 *
243 *	INIT_SHARED	shared/saveable heap
244 *	REINIT_SHARED	heap was restored, some info must be updated
245 *	INIT_PRIVATE	C variables, private heap
246 *	INIT_ENGINE	abstract machine
247 *	INIT_PROCESS	do initialisations that are needed once
248 *
249 * Initialisation is done in different situations:
250 *
251 * raw boot		INIT_SHARED|INIT_PRIVATE|INIT_ENGINE|INIT_PROCESS
252 * after -r		REINIT_SHARED|INIT_PROCESS|INIT_PRIVATE [|INIT_ENGINE]
253 * after -c		INIT_PROCESS|INIT_PRIVATE
254 * after restore/1	REINIT_SHARED|INIT_PRIVATE [|INIT_ENGINE]
255 * after reset	0 (maybe INIT_PRIVATE)
256 *----------------------------------------------------------------*/
257
258
259int
260eclipse_global_init(int init_flags)
261{
262    int err;
263
264    ec_os_init();
265
266    if (!(init_flags & (INIT_SHARED|REINIT_SHARED)))
267    {
268	/* if we attach to a heap, it must be fully initialised */
269	wait_for_flag(&GlobalFlags, HEAP_READY);
270    }
271
272    /*
273     * convert pathname to canonical representation
274     */
275    if (ec_options.eclipse_home)
276    {
277	char buf[MAX_PATH_LEN];
278	(void) canonical_filename(ec_options.eclipse_home, buf);
279	if (buf[0] != '/')
280	{
281	    /* This is mainly to enable the use of -D with relative path */
282	    char buf2[MAX_PATH_LEN];
283	    get_cwd(buf2, MAX_PATH_LEN);
284	    strcat(buf2, buf);
285	    ec_eclipse_home = strcpy((char*) hp_alloc(strlen(buf2)+1), buf2);
286	}
287	else
288	{
289	    ec_eclipse_home = strcpy((char*) hp_alloc(strlen(buf)+1), buf);
290	}
291    }
292    else
293    {
294	ec_eclipse_home = strcpy((char*) hp_alloc(strlen(eclipsehome())+1), eclipsehome());
295    }
296
297    dict_init(init_flags);
298    opaddr_init();
299    worker_init(init_flags);
300    op_init(init_flags);
301    module_init(init_flags);	/* creates modules */
302    if ((err = io_init(init_flags)) != PSUCCEED)
303    {
304	char msg[1024];
305	_make_error_message(err, "io_init", msg);
306	ec_bad_exit(msg);
307    }
308    bip_emu_init(init_flags);
309    bip_arith_init(init_flags);
310    bip_array_init(init_flags, ec_eclipse_home);
311    bip_comp_init(init_flags);
312    bip_control_init(init_flags);
313    bip_db_init(init_flags);
314    bip_delay_init(init_flags);
315    bip_domain_init(init_flags);
316    bip_elipsys_fd_init(init_flags);
317    bip_record_init(init_flags);
318    bip_store_init(init_flags);
319    bip_shelf_init(init_flags);
320    bip_bag_init(init_flags);
321    bip_heapevent_init(init_flags);
322    bip_parallel_init(init_flags);
323    bip_gc_init(init_flags);
324    bip_io_init(init_flags);
325    bip_op_init(init_flags);
326    bip_copy_init(init_flags);
327    bip_serialize_init(init_flags);
328    compiler_init(init_flags);
329    error_init(init_flags);
330    lex_init(init_flags);
331    read_init(init_flags);
332    write_init(init_flags);
333    bip_load_init(init_flags);
334    bip_strings_init(init_flags);
335    bip_tconv_init(init_flags);
336#ifdef SAVEDSTATES
337    save_res_init(init_flags);
338#endif
339    kegi_init(init_flags);
340    code_init(init_flags);
341    bip_module_init(init_flags);
342    if (init_flags & INIT_SHARED) megalog_boot_init();
343    user_init(init_flags);
344    bip_misc_init(init_flags);
345    handlers_init(init_flags);
346    msg_init(init_flags);
347    if (init_flags & INIT_PRIVATE)
348	megalog_init(ec_options.option_p);	/* create shared memory etc */
349
350    return 0;
351}
352
353int
354eclipse_boot(char *initfile)
355{
356    value	v1, v2;
357    type	t1, t2;
358    v1.did = enter_dict(initfile, 0);
359    t1.kernel = TDICT;
360    v2.did = d_.kernel_sepia;
361    t2.kernel = ModuleTag(d_.kernel_sepia);
362    return boot_emulc(v1, t1, v2, t2);
363}
364
365
366/*
367 * Preliminary I/O routines to be used while our own I/O is not initialised
368 */
369
370static void
371_make_error_message(int err, char *where, char *buf)
372{
373    extern char *ec_error_message[];
374    if (err == SYS_ERROR)
375	sprintf(buf, "ECLiPSe: %s (%s) in %s.", ec_error_message[err], strerror(errno), where);
376    else
377	sprintf(buf, "ECLiPSe: %s in %s.", ec_error_message[err], where);
378}
379
380
381/*----------------------------------------------------------------
382 * Shutdown code (see also p_exit(), exit/1 and halt/0)
383 *
384 * Shutdown can be requested either from Prolog (exit/1,halt/0) or
385 * from C (ec_cleanup()). In either case, we first do a cleanup at
386 * the Prolog level (running finalization goals etc), then the low
387 * level cleanup ec_cleanup1().
388 *
389 * The cleanup is to be done such that all dynamic resources are
390 * freed, and the system can either be reinitialised by ec_init(),
391 * or, in the embedded case, the eclipse.[so,dll] can be unloaded,
392 * freeing all ECLiPSe-related resources in the process.
393 * In particular, we must take care of:
394 * - closing all I/O
395 * - destroying threads
396 * - unloading shared libraries
397 * - deallocating the engine stacks
398 * - resetting signal handlers
399 * - freeing all heap spaces
400 * - resetting all static variables to their initial state
401 * Because we destroy our shared and private heaps indiscriminately
402 * at the end, we need not be too concerned about explicitly deallo-
403 * cating all data structures that were previously allocated there.
404 * However, we must then be sure that the embedding host does not
405 * retain pointers to such (hg/hp_allocated) data. In case ECLiPSe
406 * makes any allocations with the system malloc(), these must be
407 * freed explicitly otherwise they will constitute a memory leak.
408 *----------------------------------------------------------------*/
409
410int
411ec_cleanup1(int exit_code)
412{
413    /*
414     * Assume Prolog-level cleanup is already done,
415     * either in ec_cleanup() or in exit/1
416     */
417
418    if (ec_options.parallel_worker)
419    	halt_system(exit_code);
420
421    ec_worker_cleanup();
422    return PSUCCEED;
423}
424
425int Winapi
426ec_cleanup(void)
427{
428    int res;
429    pword goal, module;
430
431    /* Do Prolog-level cleanup code: call cleanup_before_exit/0 */
432    Make_Atom(&goal, enter_dict("cleanup_before_exit", 0));
433    module.val.did = d_.kernel_sepia;
434    module.tag.kernel = ModuleTag(d_.kernel_sepia);
435    res = main_emulc_noexit(goal.val, goal.tag, module.val, module.tag);
436    if (!(res == PSUCCEED || res == PFAIL))
437	return res;
438
439    return ec_cleanup1(0);
440}
441
442
443/*
444 * Cleanup one worker
445 */
446void
447ec_worker_cleanup(void)
448{
449    megalog_end();
450
451    handlers_fini();		/* undo signal handler settings */
452				/* (before shutting down emu and i/o) */
453
454    ec_emu_fini();		/* destroy the engine */
455    ec_embed_fini();
456
457    /* TODO: find handles stored in the heap, and free them */
458
459    bip_load_fini();		/* unload any shared libraries */
460
461    flush_and_close_io(1);	/* shut down I/O system */
462
463    ec_os_fini();		/* timers, threads, sockets */
464
465    if (ec_options.parallel_worker)
466	exit_mps();
467
468    /* disable interrupts because we cannot serve them properly when
469     * all streams are closed */
470    Disable_Int();
471
472    /* finally, release all heap memory */
473    mem_fini();
474}
475
476/*
477 * HALT signal handler
478 */
479int
480halt_session(void)
481{
482	ec_cleanup();
483	exit(0);
484}
485
486static void
487wait_for_flag(volatile int *pflag, int mask) /* volatile is important! */
488{
489    while (!(*pflag & mask))
490	short_sleep(10000);
491}
492
493