1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: dbcontrol.c
6  * Database system controller
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "database.h"
34 #include "tech.h"
35 #include "edialogs.h"
36 #include "usr.h"
37 
38 #ifdef INTERNATIONAL
39 #  ifdef MACOS
40 #    define PACKAGE x_("macelectric")
41 #    define LOCALEDIR x_("lib:international")
42 #  else
43 #    define PACKAGE x_("electric")
44 #    define LOCALEDIR x_("lib/international")
45 #  endif
46 #endif
47 
48 /*
49  * The current Electric version.
50  * Version numbering consists of 3 parts: the major number, the minor number,
51  * and the detail.  The detail part is optional lettering at the end which
52  * runs from "a" to "z", then "aa" to "az", then "ba" to "bz", etc.
53  * A released version has no detail, and is considered to be a HIGHER version
54  * than those with detail (which are prereleases).  For example:
55  *    version "6.04a"  has major=6, minor=4, detail=1 ("a")
56  *    version "6.05bc" has major=6, minor=5, detail=55 ("bc")
57  *    version "6.03"   has major=6, minor=3, and detail=1000
58  * The routine "io_getversion()" parses these version strings.
59  */
60 CHAR *el_version = x_("7.00");
61 
62        BOOLEAN db_multiprocessing;	/* true if multiprocessing */
63 
64 /* prototypes for local routines */
65 static void db_freeallmemory(void);
66 
67 /*
68  * the primary initialization of Electric
69  */
osprimaryosinit(void)70 void osprimaryosinit(void)
71 {
72 	REGISTER INTBIG i;
73 	REGISTER TECHNOLOGY *tech, *lasttech, *realtech;
74 	REGISTER CONSTRAINT *constr;
75 	REGISTER CLUSTER *clus;
76 	REGISTER LIBRARY *lib;
77 	CHAR libname[10], libfile[10];
78 	extern TECHNOLOGY el_technologylist[];
79 	REGISTER void *infstr;
80 
81 #ifdef INTERNATIONAL
82 #  if HAVE_SETLOCALE
83 	setlocale(LC_ALL, x_(""));
84 #  endif
85 	bindtextdomain(PACKAGE, LOCALEDIR);
86 	textdomain(PACKAGE);
87 
88 	/* a test */
89 	estrcpy(libname, gettext(x_("Redo")));
90 #endif
91 
92 	/* initialize the memory allocation system */
93 	db_multiprocessing = FALSE;
94 	db_initclusters();
95 
96 	/* internal initialization of the constraint solvers */
97 	el_curconstraint = &el_constraints[0];
98 	for(i=0; el_constraints[i].conname != 0; i++)
99 	{
100 		constr = &el_constraints[i];
101 		infstr = initinfstr();
102 		addstringtoinfstr(infstr, x_("constraint:"));
103 		addstringtoinfstr(infstr, constr->conname);
104 		constr->cluster = alloccluster(returninfstr(infstr));
105 		if (namesame(constr->conname, DEFCONSTR) == 0) el_curconstraint = constr;
106 	}
107 
108 	/* internal initialization of the tools */
109 	for(el_maxtools=0; el_tools[el_maxtools].toolname != 0; el_maxtools++)
110 	{
111 		infstr = initinfstr();
112 		addstringtoinfstr(infstr, x_("tool:"));
113 		addstringtoinfstr(infstr, el_tools[el_maxtools].toolname);
114 		el_tools[el_maxtools].cluster = alloccluster(returninfstr(infstr));
115 		el_tools[el_maxtools].toolindex = el_maxtools;
116 	}
117 
118 	/* initialize the database */
119 	db_initdatabase();
120 	db_initgeometry();
121 	db_initlanguages();
122 	db_inittechnologies();
123 
124 	/* internal initialization of the technologies */
125 	lasttech = NOTECHNOLOGY;
126 	for(el_maxtech=0; el_technologylist[el_maxtech].techname != 0; el_maxtech++)
127 	{
128 		tech = &el_technologylist[el_maxtech];
129 
130 		/* create the real technology object */
131 		infstr = initinfstr();
132 		addstringtoinfstr(infstr, x_("tech:"));
133 		addstringtoinfstr(infstr, tech->techname);
134 		clus = alloccluster(returninfstr(infstr));
135 		realtech = alloctechnology(clus);
136 		if (realtech == NOTECHNOLOGY) error(_("No memory for technologies"));
137 
138 		/* link it in */
139 		if (lasttech == NOTECHNOLOGY) el_technologies = realtech; else
140 			lasttech->nexttechnology = realtech;
141 		lasttech = realtech;
142 
143 		/* initialize the real technology object */
144 		(void)allocstring(&realtech->techname, tech->techname, clus);
145 		realtech->techindex = el_maxtech;
146 		realtech->deflambda = tech->deflambda;
147 		realtech->parse = tech->parse;
148 		realtech->cluster = clus;
149 		(void)allocstring(&realtech->techdescript, TRANSLATE(tech->techdescript), clus);
150 		realtech->layercount = tech->layercount;
151 		realtech->layers = tech->layers;
152 		realtech->arcprotocount = tech->arcprotocount;
153 		realtech->arcprotos = tech->arcprotos;
154 		realtech->nodeprotocount = tech->nodeprotocount;
155 		realtech->nodeprotos = tech->nodeprotos;
156 		realtech->variables = tech->variables;
157 		realtech->init = tech->init;
158 		realtech->term = tech->term;
159 		realtech->setmode = tech->setmode;
160 		realtech->request = tech->request;
161 		realtech->nodepolys = tech->nodepolys;
162 		realtech->nodeEpolys = tech->nodeEpolys;
163 		realtech->shapenodepoly = tech->shapenodepoly;
164 		realtech->shapeEnodepoly = tech->shapeEnodepoly;
165 		realtech->allnodepolys = tech->allnodepolys;
166 		realtech->allnodeEpolys = tech->allnodeEpolys;
167 		realtech->nodesizeoffset = tech->nodesizeoffset;
168 		realtech->shapeportpoly = tech->shapeportpoly;
169 		realtech->arcpolys = tech->arcpolys;
170 		realtech->shapearcpoly = tech->shapearcpoly;
171 		realtech->allarcpolys = tech->allarcpolys;
172 		realtech->arcwidthoffset = tech->arcwidthoffset;
173 		realtech->userbits = tech->userbits;
174 	}
175 
176 	/* select a current technology */
177 	el_curtech = el_technologies;
178 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
179 		if (namesame(tech->techname, DEFTECH) == 0) el_curtech = tech;
180 	el_curlayouttech = el_curtech;
181 
182 	/* setup a change batch for initialization work */
183 	/* db_preparenewbatch(&el_tools[0]); */
184 
185 	/* pass 1 initialization of the constraint solvers */
186 	for(i=0; el_constraints[i].conname != 0; i++)
187 		(*el_constraints[i].init)(&el_constraints[i]);
188 
189 	/* pass 1 initialization of technologies */
190 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
191 	{
192 		if (tech->init != 0)
193 		{
194 			if ((*tech->init)(tech, 0))
195 				error(_("User pass 1 error initializing %s technology"), tech->techname);
196 		}
197 		if (tech_doinitprocess(tech))
198 			error(_("Pass 1 error initializing %s technology"), tech->techname);
199 	}
200 
201 	/* pass 1 initialization of the tools */
202 	for(i=0; i<el_maxtools; i++)
203 		(*el_tools[i].init)(0, 0, &el_tools[i]);
204 
205 	/* create the first library */
206 	el_curlib = NOLIBRARY;
207 	estrcpy(libname, x_("noname"));
208 	estrcpy(libfile, x_("noname"));
209 	lib = newlibrary(libname, libfile);
210 	selectlibrary(lib, TRUE);
211 }
212 
213 /*
214  * the secondary initialization of Electric
215  */
ossecondaryinit(INTBIG argc,CHAR1 * argv[])216 void ossecondaryinit(INTBIG argc, CHAR1 *argv[])
217 {
218 	REGISTER INTBIG i;
219 	REGISTER TECHNOLOGY *tech;
220 
221 	/* pass 2 initialization of the constraint solvers */
222 	for(i=0; el_constraints[i].conname != 0; i++)
223 		(*el_constraints[i].init)(NOCONSTRAINT);
224 
225 	/* pass 2 initialization of technologies */
226 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
227 	{
228 		if (tech->init != 0)
229 		{
230 			if ((*tech->init)(tech, 1))
231 				error(_("User pass 2 error initializing %s technology"), tech->techname);
232 		}
233 		if (tech_doaddportsandvars(tech))
234 			error(_("Pass 2 error initializing %s technology"), tech->techname);
235 	}
236 
237 	/* pass 2 initialization of the tools */
238 	for(i=0; i<el_maxtools; i++) (*el_tools[i].init)(&argc, argv, NOTOOL);
239 
240 	/* pass 3 initialization of technologies */
241 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
242 	{
243 		if (tech->init != 0)
244 		{
245 			if ((*tech->init)(tech, 2))
246 				error(_("User pass 3 error initializing %s technology"), tech->techname);
247 		}
248 	}
249 
250 	/* register and initialize technology-variable caching functions */
251 	db_inittechcache();
252 
253 	/* pass 3 initialization of the tools */
254 	for(i=0; i<el_maxtools; i++) (*el_tools[i].init)(&argc, argv, 0);
255 
256 	/* delete initialization change batches so it is ready for real changes */
257 	noundoallowed();
258 
259 	/* make sure the integer sizes are correct */
260 	if (sizeof(INTHUGE) < 8)
261 		error(x_("INTHUGE must be 64 bits wide (fix 'global.h')\n"));
262 	if (sizeof(INTBIG) < 4)
263 		error(x_("INTBIG must be 32 bits wide (fix 'global.h')\n"));
264 	if (sizeof(INTSML) < 2)
265 		error(x_("INTSML must be 16 bits wide (fix 'global.h')\n"));
266 	if (sizeof(INTBIG) < sizeof(CHAR *))
267 		error(x_("INTBIG must be able to hold a pointer (%d bytes) bits wide (fix 'global.h')\n"),
268 			sizeof(CHAR *));
269 }
270 
271 /* the body of the main loop of Electric */
tooltimeslice(void)272 void tooltimeslice(void)
273 {
274 	REGISTER INTBIG s;
275 	REGISTER TOOL *tool;
276 
277 	for(s=0; s<el_maxtools; s++)
278 	{
279 		tool = &el_tools[s];
280 		if ((tool->toolstate & TOOLON) == 0) continue;
281 		if (tool->slice == 0) continue;
282 
283 		/* let the tool have a whack */
284 		db_setcurrenttool(tool);
285 		(*tool->slice)();
286 
287 		/* announce end of broadcast of changes */
288 		db_endbatch();
289 	}
290 }
291 
telltool(TOOL * tool,INTBIG count,CHAR * par[])292 void telltool(TOOL *tool, INTBIG count, CHAR *par[])
293 {
294 	if (tool->setmode == 0) return;
295 	(*tool->setmode)(count, par);
296 }
297 
asktool(TOOL * tool,CHAR * command,...)298 INTBIG asktool(TOOL *tool, CHAR *command, ...)
299 {
300 	va_list ap;
301 	INTBIG result;
302 
303 	if (tool->request == 0) return(0);
304 	var_start(ap, command);
305 	result = (*tool->request)(command, ap);
306 	va_end(ap);
307 	return(result);
308 }
309 
310 /*
311  * routine to turn tool "tool" back on.  The user interface will notice this change
312  * and inform the tool of each cell that changed while it was off (via "examinenodeproto").
313  */
toolturnon(TOOL * tool)314 void toolturnon(TOOL *tool)
315 {
316 	/* turn on the tool */
317 	(void)setval((INTBIG)tool, VTOOL, x_("toolstate"), tool->toolstate|TOOLON, VINTEGER);
318 }
319 
320 /*
321  * routine to turn tool "tool" off.  If "permanently" is true, this change
322  * will not be undoable
323  */
toolturnoff(TOOL * tool,BOOLEAN permanently)324 void toolturnoff(TOOL *tool, BOOLEAN permanently)
325 {
326 	/* turn off the tool */
327 	if (permanently) tool->toolstate &= ~TOOLON; else
328 		(void)setval((INTBIG)tool, VTOOL, x_("toolstate"), tool->toolstate & ~TOOLON, VINTEGER);
329 }
330 
331 /*
332  * shutdown the design tool
333  */
bringdown(void)334 void bringdown(void)
335 {
336 	REGISTER INTBIG i;
337 	REGISTER TECHNOLOGY *tech;
338 	REGISTER TOOL *tool;
339 	REGISTER CONSTRAINT *con;
340 
341 	/* go backwards through tools to shut down in proper order */
342 	for(i = el_maxtools-1; i >= 0; i--)
343 	{
344 		tool = &el_tools[i];
345 		if (tool->done != 0) (*tool->done)();
346 		if (tool->numvar != 0) db_freevars(&tool->firstvar, &tool->numvar);
347 	}
348 
349 	/* terminate technologies */
350 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
351 		if (tech->term != 0) (*tech->term)();
352 
353 	/* terminate any language interpreters */
354 	db_termlanguage();
355 
356 	/* shut down the constraint solvers */
357 	for(i=0; el_constraints[i].conname != 0; i++)
358 	{
359 		con = &el_constraints[i];
360 		(*con->term)();
361 		if (con->numvar != 0) db_freevars(&con->firstvar, &con->numvar);
362 	}
363 
364 	/* free up all memory */
365 	db_freeallmemory();
366 
367 	/* check that there were no leaks */
368 	db_checkallmemoryfree();
369 
370 	exitprogram();
371 }
372 
db_freeallmemory(void)373 void db_freeallmemory(void)
374 {
375 #ifdef DEBUGMEMORY
376 	REGISTER VIEW *v;
377 	REGISTER TECHNOLOGY *tech, *nexttech;
378 	REGISTER LIBRARY *lib;
379 
380 	noundoallowed();
381 
382 	/* free all views */
383 	while (el_views != NOVIEW)
384 	{
385 		v = el_views;
386 		el_views = el_views->nextview;
387 		efree((CHAR *)v->viewname);
388 		efree((CHAR *)v->sviewname);
389 		freeview(v);
390 	}
391 
392 	/* free all technologies */
393 	for (tech = el_technologies; tech != NOTECHNOLOGY; tech = nexttech)
394 	{
395 		nexttech = tech->nexttechnology;
396 		freetechnology(tech);
397 	}
398 
399 	/* free all libraries */
400 	while (el_curlib != NOLIBRARY)
401 	{
402 		lib = el_curlib;
403 		el_curlib = el_curlib->nextlibrary;
404 		eraselibrary(lib);
405 		efree(lib->libfile);
406 		efree(lib->libname);
407 		freelibrary(lib);
408 	}
409 
410 	/* free all database memory */
411 	db_freetechnologymemory();
412 	db_freechangememory();
413 	db_freevariablememory();
414 	db_freenoprotomemory();
415 	db_freemathmemory();
416 	db_freemergememory();
417 	db_freegeomemory();
418 	db_freeerrormemory();
419 	db_freetextmemory();
420 	initerrorlogging(x_(""));
421 #  if LANGTCL
422 	db_freetclmemory();
423 #  endif
424 #endif
425 }
426 
stopping(INTBIG reason)427 BOOLEAN stopping(INTBIG reason)
428 {
429 	extern CHAR *db_stoppingreason[];
430 	static UINTBIG lastchecktime = 0;
431 	REGISTER UINTBIG curtime;
432 
433 	if ((us_tool->toolstate&TERMNOINTERRUPT) != 0) return(FALSE);
434 
435 	/* only check once per second */
436 	curtime = ticktime();
437 	if (curtime - lastchecktime < 60) return(FALSE);
438 	lastchecktime = curtime;
439 
440 	checkforinterrupt();
441 	if (el_pleasestop == 1)
442 	{
443 		flushscreen();
444 		ttyputmsg(_("%s stopped"), db_stoppingreason[reason]);
445 		el_pleasestop = 2;
446 	}
447 	return(el_pleasestop != 0);
448 }
449 
450 /*
451  * Routine to enable multiprocessor locks in the database (if "on" is TRUE).
452  * Call this before firing-up threads so that database calls lock critical sections
453  * properly.  Turn it off when thread usage has stopped.
454  */
setmultiprocesslocks(BOOLEAN on)455 void setmultiprocesslocks(BOOLEAN on)
456 {
457 	static INTBIG threadcapability = 0;		/* 1: can  -1: can't */
458 
459 	if (on)
460 	{
461 		if (threadcapability == 0)
462 		{
463 			if (graphicshas(CANDOTHREADS)) threadcapability = 1; else
464 				threadcapability = -1;
465 		}
466 		if (threadcapability < 0) return;
467 	}
468 	db_multiprocessing = on;
469 }
470 
471 /*
472  * Checking routine to ensure that no multiprocessor code is running.
473  * Reports an error if so (because some non-reentrant code was called).
474  */
ensurenonparallel(CHAR * file,INTBIG line)475 void ensurenonparallel(CHAR *file, INTBIG line)
476 {
477 	if (db_multiprocessing)
478 	{
479 		ttyputerr(_("ERROR: non-reentrant code (line %ld of module %s) called by multiple processors"),
480 			line, file);
481 	}
482 }
483 
484 /*
485  * Routine to ensure that the mutual-exclusion lock at "mutex" is properly initialized
486  * and unlocked.  If "showerror" is TRUE and an error occurs, display the error.
487  * Returns TRUE on error.
488  */
ensurevalidmutex(void ** mutex,BOOLEAN showerror)489 BOOLEAN ensurevalidmutex(void **mutex, BOOLEAN showerror)
490 {
491 	if (*mutex == 0)
492 	{
493 		*mutex = emakemutex();
494 		if (*mutex == 0)
495 		{
496 			if (!graphicshas(CANDOTHREADS)) return(FALSE);
497 			if (showerror)
498 				ttyputmsg(_("Error creating mutual-exclusion lock"));
499 			return(TRUE);
500 		}
501 	}
502 	emutexunlock(*mutex);
503 	return(FALSE);
504 }
505