/[eiffelstudio]/branches/eth/eve/Src/C/run-time/misc.c
ViewVC logotype

Contents of /branches/eth/eve/Src/C/run-time/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 92964 - (show annotations)
Fri Sep 20 05:41:23 2013 UTC (6 years, 1 month ago) by jasonw
File MIME type: text/plain
File size: 18026 byte(s)
<<Merged from trunk#92963.>>
1 /*
2 description: "Miscellaneous Eiffel externals."
3 date: "$Date$"
4 revision: "$Revision$"
5 copyright: "Copyright (c) 1985-2012, Eiffel Software."
6 license: "GPL version 2 see http://www.eiffel.com/licensing/gpl.txt)"
7 licensing_options: "Commercial license is available at http://www.eiffel.com/licensing"
8 copying: "[
9 This file is part of Eiffel Software's Runtime.
10
11 Eiffel Software's Runtime is free software; you can
12 redistribute it and/or modify it under the terms of the
13 GNU General Public License as published by the Free
14 Software Foundation, version 2 of the License
15 (available at the URL listed under "license" above).
16
17 Eiffel Software's Runtime is distributed in the hope
18 that it will be useful, but WITHOUT ANY WARRANTY;
19 without even the implied warranty of MERCHANTABILITY
20 or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public
24 License along with Eiffel Software's Runtime; if not,
25 write to the Free Software Foundation, Inc.,
26 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 ]"
28 source: "[
29 Eiffel Software
30 5949 Hollister Ave., Goleta, CA 93117 USA
31 Telephone 805-685-1006, Fax 805-685-6869
32 Website http://www.eiffel.com
33 Customer support http://support.eiffel.com
34 ]"
35 */
36
37 /*
38 doc:<file name="misc.c" header="eif_misc.h" version="$Id$" summary="Miscellenaous eiffel externals">
39 */
40
41 #include "eif_portable.h"
42 #ifdef VXWORKS
43 #include <sysLib.h>
44 #include <taskLib.h> /* 'thread' operations */
45 #include <taskVarLib.h> /* 'thread' 'specific data' */
46 #include <envLib.h>
47 #endif
48 #ifdef EIF_WINDOWS
49 #define WIN32_LEAN_AND_MEAN
50 #include <windows.h>
51 #include <eif_file.h>
52 #endif
53
54 #include <signal.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #if defined(EIF_SGI) || defined(EIF_SOLARIS)
58 #include <strings.h> /* for index and rindex. */
59 #endif
60 #include "rt_assert.h"
61 #include "eif_misc.h"
62 #include "eif_malloc.h"
63 #include "rt_lmalloc.h" /* for eif_malloc() */
64 #include "rt_macros.h"
65 #include "rt_dir.h"
66 #include "rt_threads.h"
67 #include "rt_struct.h"
68 #include "rt_gen_types.h"
69 #include "eif_size.h"
70
71 #include <ctype.h> /* For toupper(), is_alpha(), ... */
72 #include <stdio.h>
73
74 /*
75 doc: <routine name="eif_pointer_identity" export="public">
76 doc: <summary>Because of a crash of VC6++ when directly assigning a function pointer to an array of function pointer in a loop, we create this identity function that cannot be inlined and thus prevents the bug to occur. As soon as VC6++ is not supported we can get rid of it. Read comments on ROUT_TABLE.generate_loop_initialization for details.</summary>
77 doc: <param name="p" type="void *">Pointer to return.</param>
78 doc: <thread_safety>Safe</thread_safety>
79 doc: <synchronization>None required</synchronization>
80 doc: </routine>
81 */
82
83 rt_public void * eif_pointer_identity (void * p)
84 {
85 return p;
86 }
87
88 rt_public EIF_INTEGER bointdiv(EIF_INTEGER n1, EIF_INTEGER n2)
89 {
90 /* Return the greatest integer less or equal to the
91 * integer division of `n1' by `n2'
92 */
93
94 return ((n1 >= 0) ^ (n2 > 0)) ? (n1 % n2 ? n1 / n2 - 1: n1 / n2) : n1 / n2;
95 }
96
97 rt_public EIF_INTEGER upintdiv(EIF_INTEGER n1, EIF_INTEGER n2)
98 {
99 /* Return the smallest integer greater or equal to the
100 * integer division of `n1' by `n2'
101 */
102
103 return ((n1 >= 0) ^ (n2 > 0)) ? n1 / n2: ((n1 % n2) ? n1 / n2 + 1: n1 / n2);
104 }
105
106 /*
107 doc: <routine name="init_scp_manager" export="public">
108 doc: <summary>Initialize ISE_SCOOP_MANAGER if available.</summary>
109 doc: <thread_safety>Unsafe</thread_safety>
110 doc: <synchronization>None required</synchronization>
111 doc: </routine>
112 */
113
114 rt_public void init_scp_manager (void)
115 /* Initialize ISE_SCOOP_MANAGER
116 */
117 {
118 if (egc_init_scoop_manager != NULL)
119 {
120 EIF_INTEGER pf_status = egc_prof_enabled;
121 EIF_BOOLEAN tr_status = eif_is_tracing_enabled();
122
123 /* No need to create the global instance, when it has already been created by one thread. */
124 scp_mnger = RTLNSMART(egc_scp_mngr_dtype);
125
126 #ifndef ENABLE_STEP_THROUGH
127 DISCARD_BREAKPOINTS; /* prevent the debugger from stopping in the following functions */
128 #endif
129 eif_disable_tracing(); /* Disable tracing to not clobber the output. */
130 egc_prof_enabled = 0; /* Disable profiling to be safe. */
131 (egc_init_scoop_manager)(scp_mnger);
132 egc_prof_enabled = pf_status; /* Resume profiling status. */
133 if (!tr_status) {
134 /* Resume tracing if it was previously enabled. */
135 eif_enable_tracing();
136 }
137 #ifndef ENABLE_STEP_THROUGH
138 UNDISCARD_BREAKPOINTS; /* prevent the debugger from stopping in the following functions */
139 #endif
140 }
141 }
142
143 /*
144 doc: <routine name="eif_sleep" export="public">
145 doc: <summary>Suspend execution of current thread by interval `nanoseconds'. It uses the most precise sleep function available for a given platform.</summary>
146 doc: <param name="nanoseconds" type="EIF_INTEGER_64">Number of nanoseconds to sleep.</param>
147 doc: <thread_safety>Safe</thread_safety>
148 doc: <synchronization>None required</synchronization>
149 doc: </routine>
150 */
151
152 rt_public void eif_sleep(EIF_INTEGER_64 nanoseconds)
153 {
154 /*
155 * Suspend thread execution for interval specified by `nanoseconds'.
156 * Use the most precise sleep function if possible.
157 */
158
159 #ifdef VXWORKS
160 int n = (int) (((EIF_NATURAL_64) nanoseconds * (EIF_NATURAL_64) sysClkRateGet())/1000000000);
161 taskDelay(n);
162 #else
163 #ifdef HAS_NANOSLEEP
164 struct timespec req;
165 struct timespec rem;
166 req.tv_sec = nanoseconds / 1000000000;
167 req.tv_nsec = nanoseconds % 1000000000;
168 while ((nanosleep (&req, &rem) == -1) && (errno == EINTR)) {
169 /* Function is interrupted by a signal. */
170 /* Let's call it again to complete pause. */
171 req = rem;
172 }
173 #else
174 # ifdef HAS_USLEEP
175 # define EIF_SLEEP_PRECISION 1000
176 # define EIF_SLEEP_TYPE unsigned long
177 # define EIF_SLEEP_FUNCTION usleep
178 # elif defined EIF_WINDOWS
179 # define EIF_SLEEP_PRECISION 1000000
180 # define EIF_SLEEP_TYPE DWORD
181 # define EIF_SLEEP_FUNCTION Sleep
182 # else
183 # define EIF_SLEEP_PRECISION 1000000000
184 # define EIF_SLEEP_TYPE unsigned int
185 # define EIF_SLEEP_FUNCTION sleep
186 # endif
187 /* Set total delay time */
188 if (nanoseconds > 1)
189 {
190 EIF_INTEGER_64 total_time = nanoseconds / EIF_SLEEP_PRECISION;
191 /* Set maximum timeout that can be handled by one API call */
192 EIF_SLEEP_TYPE timeout = ~((~ (EIF_SLEEP_TYPE) 0) << (sizeof timeout * 8 - 1));
193 if ((nanoseconds % EIF_SLEEP_PRECISION) > 0) {
194 /* Increase delay to handle underflow */
195 total_time++;
196 }
197 while (total_time > 0) {
198 /* Sleep for maximum timeout not exceeding time left */
199 if (timeout > total_time) {
200 timeout = (EIF_SLEEP_TYPE) total_time;
201 }
202 EIF_SLEEP_FUNCTION (timeout);
203 total_time -= timeout;
204 }
205 }
206 else
207 {
208 EIF_SLEEP_FUNCTION ((EIF_SLEEP_TYPE) nanoseconds);
209 }
210 # undef EIF_SLEEP_PRECISION
211 # undef EIF_SLEEP_TYPE
212 # undef EIF_SLEEP_FUNCTION
213 #endif
214 #endif
215 }
216
217 /*
218 * Protected call to system
219 */
220
221 /*
222 doc: <routine name="eif_system" return_type="EIF_INTEGER" export="public">
223 doc: <summary>Execute a command using system shell.</>
224 doc: <param name="s" type="EIF_NATIVE_CHAR *">Null-terminated path in UTF-16 encoding on Windows and a byte sequence otherwise.</param>
225 doc: <return>0 if it succeeds, -1 otherwise. Upon failure `errno' is set with the reason code.</return>
226 doc: <thread_safety>Re-entrant</thread_safety>
227 doc: </routine>
228 */
229 rt_public EIF_INTEGER eif_system (EIF_NATIVE_CHAR *s)
230 {
231 EIF_INTEGER result;
232
233 #ifdef EIF_VMS_V6_ONLY
234 /* if s contains any VMS filespec delimiters, prepend 'RUN ' command */
235 { /* if it contains a '[' before a space (ie. no verb), prepend "run " */
236 /* ***VMS FIXME*** revisit this for long filenames - may contain space in filename */
237 char *p = strchr (s, '[');
238 if ( (p) && p < strchr (s, ' ') ) {
239 char * run_cmd = eif_malloc (10 + strlen(s));
240 if ( (run_cmd) ) {
241 strcat (strcpy (run_cmd, "run "), s);
242 result = (EIF_INTEGER) system (run_cmd);
243 eif_free (run_cmd);
244 }
245 else result = -1;
246 }
247 else result = (EIF_INTEGER) system (s);
248 }
249
250 #elif defined EIF_VMS
251 result = eifrt_vms_spawn (s, EIFRT_VMS_SPAWN_FLAG_TRANSLATE); /* synchronous spawn */
252
253 #elif defined EIF_WINDOWS
254 result = (EIF_INTEGER) _wsystem (s);
255 #else
256 result = (EIF_INTEGER) system (s);
257 #endif
258
259 return result;
260 }
261
262 /*
263 doc: <routine name="eif_system_asynchronous" return_type="void" export="public">
264 doc: <summary>Execute a command using system shell.</>
265 doc: <param name="cmd" type="EIF_NATIVE_CHAR *">Null-terminated path in UTF-16 encoding on Windows and a byte sequence otherwise.</param>
266 doc: <thread_safety>Safe</thread_safety>
267 doc: </routine>
268 */
269 rt_public void eif_system_asynchronous (EIF_NATIVE_CHAR *cmd)
270 {
271 /* Run a command asynchronously, that is to say in background. The command
272 * is identified by the client via a "job number", which is inserted in
273 * the request itself.
274 * The daemon forks a copy of itself which will be in charge of running
275 * the command and sending the acknowledgment back, tagged with the command
276 * number.
277 */
278
279 #ifdef EIF_WINDOWS
280 STARTUPINFOW siStartInfo;
281 PROCESS_INFORMATION procinfo;
282 wchar_t *current_dir;
283 EIF_INTEGER result;
284 #else
285 int status; /* Command status, as returned by system() */
286 char *meltpath, *appname, *envstring; /* set MELT_PATH */
287 #endif
288
289 #ifdef EIF_WINDOWS
290 current_dir = (wchar_t *) _wgetcwd(NULL, PATH_MAX);
291
292 memset (&siStartInfo, 0, sizeof siStartInfo);
293 siStartInfo.cb = sizeof(STARTUPINFO);
294 siStartInfo.lpTitle = NULL;
295 siStartInfo.lpReserved = NULL;
296 siStartInfo.lpReserved2 = NULL;
297 siStartInfo.cbReserved2 = 0;
298 siStartInfo.lpDesktop = NULL;
299 siStartInfo.dwFlags = STARTF_FORCEONFEEDBACK;
300
301 /* We do not used DETACHED_PROCESS below because it won't work when
302 * launching interactive console application such as `cmd.exe'. */
303 result = CreateProcessW (
304 NULL,
305 cmd,
306 NULL,
307 NULL,
308 FALSE,
309 CREATE_NEW_CONSOLE,
310 NULL,
311 current_dir,
312 &siStartInfo,
313 &procinfo);
314 if (result) {
315 CloseHandle (procinfo.hProcess);
316 CloseHandle (procinfo.hThread);
317 }
318 _wchdir(current_dir);
319 free(current_dir);
320 #else /* (not) EIF_WINDOWS */
321
322 #if !defined(EIF_VMS) && !defined(VXWORKS) /* VMS needs a higher level abstraction for async system() */
323 switch (fork()) {
324 case -1: /* Cannot fork */
325 return;
326 case 0: /* Child is performing the command */
327 break;
328 default:
329 return; /* Parent returns immediately */
330 }
331 #endif /* not VMS/VXWORKS (skips fork/parent code if VMS/VXWORKS) */
332
333 /* child (except on VMS, where this code runs in the parent) */
334 meltpath = (char *) malloc (strlen(cmd) + 1);
335 meltpath = strcpy (meltpath, cmd);
336 if (!meltpath)
337 return;
338
339 #ifdef EIF_VMS_V6_ONLY
340 appname = rindex (meltpath, ']');
341 if (appname)
342 *appname = 0;
343 else
344 strcpy (meltpath, "[]");
345 #elif defined EIF_VMS
346 {
347 size_t siz = eifrt_vms_dirname_len (meltpath);
348 if (siz)
349 meltpath[siz] = '\0';
350 else
351 strcpy (meltpath, "[]");
352 }
353 #else
354 appname = rindex (meltpath, '/');
355 if (appname)
356 *appname = 0;
357 else
358 strcpy (meltpath, ".");
359 #endif
360 envstring = (char *)malloc (strlen (meltpath)
361 + strlen ("MELT_PATH=") + 1);
362 if (!envstring)
363 return;
364 sprintf (envstring, "MELT_PATH=%s", meltpath);
365 putenv (envstring);
366
367 #ifdef EIF_VMS
368 status = eifrt_vms_spawn (cmd, EIFRT_VMS_SPAWN_FLAG_ASYNC);
369 //??? putenv ("MELT_PATH=");
370 //??? free (meltpath); meltpath = NULL;
371 //??? free (envstring); envstring = NULL;
372 if (status) { /* command failed */
373 const char *pgmname = eifrt_vms_get_progname (NULL,0);
374 fprintf (stderr, "%s: %s: \n-- error from system() call: %d\n"
375 "-- failed cmd: \"%s\" -- %s\n",
376 pgmname, __FILE__, errno, cmd, strerror(errno));
377 }
378 return; /* skip send ack packet, Fred says not done anymore */
379
380 #else /* (not) VMS */
381 status = system(cmd); /* Run command via /bin/sh */
382
383 #ifdef VXWORKS
384 exit(0);
385 #else
386 _exit(0); /* Child is exiting properly */
387 #endif
388 #endif /* EIF_VMS */
389 #endif /* EIF_WINDOWS */
390 /* NOTREACHED */
391
392 }
393
394 extern union overhead *eif_header (EIF_REFERENCE);
395 rt_shared union overhead * eif_header (EIF_REFERENCE object) {
396 REQUIRE("object not null", object);
397
398 return HEADER(object);
399 }
400 /***************************************/
401
402 rt_public EIF_REFERENCE arycpy(EIF_REFERENCE area, EIF_INTEGER i, EIF_INTEGER k)
403 {
404 /* Reallocation of memory for an array's `area' for new count `i', keeping
405 * the old content.(starts at 0 and is `k' long).
406 */
407
408 char *new_area, *ref;
409 rt_uint_ptr elem_size; /* Size of each item within area */
410 EIF_INTEGER old_count;
411 EIF_TYPE_INDEX exp_dftype; /* Full dynamic type of the first expanded object */
412 EIF_INTEGER n; /* Counter for initialization of expanded */
413
414 REQUIRE ("Must be special", HEADER (area)->ov_flags & EO_SPEC);
415 REQUIRE ("Must not be TUPLE", !(HEADER (area)->ov_flags & EO_TUPLE));
416
417 old_count = RT_SPECIAL_COUNT(area);
418 elem_size = RT_SPECIAL_ELEM_SIZE(area);
419
420 #ifdef ARYCPY_DEBUG
421 printf ("ARYCPY: area 0x%x, new count %d, old count %d, start %d and %d long\n", area, i, old_count, k);
422 #endif /* ARYCPY_DEBUG */
423
424 /* Possible optimization: remembering process for special objects full of
425 * references can be discarded in this call to `sprealloc', since
426 * we will change the order of the indices. */
427
428 new_area = sprealloc(area, i); /* Reallocation of special object */
429
430 /* Move old contents to the right position and fill in empty parts with
431 * zeros. */
432 if (old_count == k) /* Is this the usual case. */
433 return new_area; /* All have been done in sprealloc () . */
434
435 /* If the new area is full of references and remembered,
436 * the information in the special table
437 * may be completely obsolete. Thus, we remove its entry
438 * and relaunch the remembering process. */
439
440 CHECK ("Must be special", HEADER (new_area)->ov_flags & EO_SPEC);
441 CHECK ("Must not be TUPLE", !(HEADER (new_area)->ov_flags & EO_TUPLE));
442 CHECK ("Proper size", i == RT_SPECIAL_COUNT(new_area));
443
444 if (!(HEADER(new_area)->ov_flags & EO_COMP))
445 return new_area; /* No expanded objects */
446
447 /* If there are some expanded objects, then we must initialize them by
448 * calling the initialization routine (which will set up intra references).
449 * The dynamic type of all the expanded object is the same, so we only
450 * compute the one of the first element. Note that the Dtype() macro needs
451 * a pointer to the object and not to the zone, hence the shifting by
452 * OVERHEAD bytes in the computation of 'dtype'--RAM.
453 */
454
455 exp_dftype = eif_gen_param_id (Dftype(new_area), 1);
456
457 #ifndef WORKBENCH
458 if (References(To_dtype(exp_dftype)) > 0) {
459 #endif
460 /* If there is a header for each expanded in the special, then update expanded
461 * offsets for k objects. */
462 for (
463 n = k - 1, ref = new_area + (n * elem_size);
464 n >= 0;
465 n--, ref -= elem_size)
466 {
467 CHECK("size nonnegative", (ref - new_area + OVERHEAD) >= 0);
468 CHECK("valid size", (ref - new_area + OVERHEAD) <= B_SIZE);
469 ((union overhead *) ref)->ov_size = (uint32) (ref - new_area + OVERHEAD);
470 }
471 #ifndef WORKBENCH
472 }
473 #endif
474
475 /* Intialize remaining objects from k to (i - 1) */
476 new_area = sp_init(new_area, exp_dftype, k, i - 1);
477
478 return new_area;
479 }
480
481
482
483 #ifdef EIF_WINDOWS
484
485 /* DLL declarations */
486
487 #define EIF_DLL_CHUNK 20
488
489 struct eif_dll_info {
490 char *dll_name;
491 HANDLE dll_module_ptr;
492 };
493
494 /*
495 doc: <attribute name="eif_dll_table" return_type="struct eif_dll_info *" export="private">
496 doc: <summary>Hold all shared libraries that have been already loaded. Used for `DLL' C externals.</summary>
497 doc: <access>Read/Write</access>
498 doc: <thread_safety>Not safe</thread_safety>
499 doc: <synchronization>None</synchronization>
500 doc: <fixme>We simply need a mutex to protect update access.</fixme>
501 doc: </attribute>
502 */
503 rt_private struct eif_dll_info *eif_dll_table = (struct eif_dll_info *) 0;
504
505 /*
506 doc: <attribute name="eif_dll_capacity" return_type="int" export="private">
507 doc: <summary>Capacity of `eif_dll_table'.</summary>
508 doc: <access>Read/Write</access>
509 doc: <thread_safety>Not safe</thread_safety>
510 doc: <synchronization>None</synchronization>
511 doc: <fixme>We simply need a mutex to protect update access.</fixme>
512 doc: </attribute>
513 */
514 rt_private int eif_dll_capacity = EIF_DLL_CHUNK;
515
516 /*
517 doc: <attribute name="eif_dll_count" return_type="int" export="private">
518 doc: <summary>Count of `eif_dll_table'.</summary>
519 doc: <access>Read/Write</access>
520 doc: <thread_safety>Not safe</thread_safety>
521 doc: <synchronization>None</synchronization>
522 doc: <fixme>We simply need a mutex to protect update access.</fixme>
523 doc: </attribute>
524 */
525 rt_private int eif_dll_count = 0;
526
527 rt_public HMODULE eif_load_dll(char *module_name)
528 {
529 HMODULE a_result;
530 char *m_name;
531 int i;
532
533 if (eif_dll_table == (struct eif_dll_info *) 0) {
534 eif_dll_table = eif_malloc(sizeof(struct eif_dll_info) * eif_dll_capacity);
535 if (eif_dll_table == (struct eif_dll_info *) 0)
536 enomem(MTC_NOARG);
537 }
538
539 for (i=0; i < eif_dll_count; i++) {
540 /* Case insensitive comparison */
541 if (strcmpi(eif_dll_table[i].dll_name, module_name) == 0)
542 return eif_dll_table[i].dll_module_ptr;
543 }
544
545 if (eif_dll_count == eif_dll_capacity) {
546 eif_dll_capacity += EIF_DLL_CHUNK;
547 eif_dll_table = eif_realloc(eif_dll_table, sizeof(struct eif_dll_info) * eif_dll_capacity);
548
549 if (eif_dll_table == (struct eif_dll_info *) 0)
550 enomem(MTC_NOARG);
551 }
552
553 if ((m_name = (char *) eif_malloc(strlen(module_name)+1)) == (char *) 0)
554 enomem(MTC_NOARG);
555 strcpy (m_name, module_name);
556
557 a_result = LoadLibrary(module_name);
558
559 eif_dll_table[eif_dll_count].dll_name = m_name;
560 eif_dll_table[eif_dll_count].dll_module_ptr = a_result;
561
562 eif_dll_count++;
563
564 return a_result;
565 }
566
567 rt_public void eif_free_dlls(void)
568 {
569 int i;
570 HINSTANCE module_ptr;
571
572 if (eif_dll_table) {
573 for (i=0; i< eif_dll_count; i++) {
574 eif_free(eif_dll_table[i].dll_name);
575
576 module_ptr = eif_dll_table[i].dll_module_ptr;
577 if (module_ptr != NULL)
578 (void) FreeLibrary(module_ptr);
579 }
580 eif_free(eif_dll_table);
581 }
582 }
583
584 #endif /* EIF_WINDOWS */
585
586 #ifndef EIF_WINDOWS
587 rt_public pid_t eiffel_fork(void) {
588 #ifdef VXWORKS
589 return 0;
590 #elif defined (EIF_THREADS)
591 return eif_thread_fork();
592 #else
593 return fork();
594 #endif
595 }
596 #endif
597
598 /*
599 doc:</file>
600 */

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.23