Mercurial > hg > truffle
annotate src/os/posix/launcher/java_md.c @ 3095:d3d00c1ea071
IdealGraphVisualizer: Enhance text view so it can display arbitrary properties from the active graph's group. For diff graphs, it shows the textual difference between the property strings using the NetBeans Diff module.
author | Peter Hofer <peter.hofer@jku.at> |
---|---|
date | Wed, 29 Jun 2011 17:33:35 +0200 |
parents | e58d06a8037e |
children | f08d439fab8c |
rev | line source |
---|---|
1985 | 1 /* |
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 * | |
23 */ | |
24 | |
25 | |
26 #include "java.h" | |
27 #include <dirent.h> | |
28 #include <dlfcn.h> | |
29 #include <fcntl.h> | |
30 #include <inttypes.h> | |
31 #include <stdio.h> | |
32 #include <string.h> | |
33 #include <stdlib.h> | |
34 #include <limits.h> | |
35 #include <sys/stat.h> | |
36 #include <unistd.h> | |
37 #include <sys/types.h> | |
38 | |
39 #ifndef GAMMA | |
40 #include "manifest_info.h" | |
41 #include "version_comp.h" | |
42 #endif | |
43 | |
44 #ifdef __linux__ | |
45 #include <pthread.h> | |
46 #else | |
47 #include <thread.h> | |
48 #endif | |
49 | |
50 #define JVM_DLL "libjvm.so" | |
51 #define JAVA_DLL "libjava.so" | |
52 | |
53 #ifndef GAMMA /* launcher.make defines ARCH */ | |
54 /* | |
55 * If a processor / os combination has the ability to run binaries of | |
56 * two data models and cohabitation of jre/jdk bits with both data | |
57 * models is supported, then DUAL_MODE is defined. When DUAL_MODE is | |
58 * defined, the architecture names for the narrow and wide version of | |
59 * the architecture are defined in LIBARCH64NAME and LIBARCH32NAME. Currently | |
60 * only Solaris on sparc/sparcv9 and i586/amd64 is DUAL_MODE; linux | |
61 * i586/amd64 could be defined as DUAL_MODE but that is not the | |
62 * current policy. | |
63 */ | |
64 | |
65 #ifndef LIBARCHNAME | |
66 # error "The macro LIBARCHNAME was not defined on the compile line" | |
67 #endif | |
68 | |
69 #ifdef __sun | |
70 # define DUAL_MODE | |
71 # ifndef LIBARCH32NAME | |
72 # error "The macro LIBARCH32NAME was not defined on the compile line" | |
73 # endif | |
74 # ifndef LIBARCH64NAME | |
75 # error "The macro LIBARCH64NAME was not defined on the compile line" | |
76 # endif | |
77 # include <sys/systeminfo.h> | |
78 # include <sys/elf.h> | |
79 # include <stdio.h> | |
80 #endif | |
81 | |
82 #endif /* ifndef GAMMA */ | |
83 | |
84 /* pointer to environment */ | |
85 extern char **environ; | |
86 | |
87 #ifndef GAMMA | |
88 /* | |
89 * A collection of useful strings. One should think of these as #define | |
90 * entries, but actual strings can be more efficient (with many compilers). | |
91 */ | |
92 #ifdef __linux__ | |
93 static const char *system_dir = "/usr/java"; | |
94 static const char *user_dir = "/java"; | |
95 #else /* Solaris */ | |
96 static const char *system_dir = "/usr/jdk"; | |
97 static const char *user_dir = "/jdk"; | |
98 #endif | |
99 | |
100 #endif /* ifndef GAMMA */ | |
101 | |
102 /* | |
103 * Flowchart of launcher execs and options processing on unix | |
104 * | |
105 * The selection of the proper vm shared library to open depends on | |
106 * several classes of command line options, including vm "flavor" | |
107 * options (-client, -server) and the data model options, -d32 and | |
108 * -d64, as well as a version specification which may have come from | |
109 * the command line or from the manifest of an executable jar file. | |
110 * The vm selection options are not passed to the running | |
111 * virtual machine; they must be screened out by the launcher. | |
112 * | |
113 * The version specification (if any) is processed first by the | |
114 * platform independent routine SelectVersion. This may result in | |
115 * the exec of the specified launcher version. | |
116 * | |
117 * Typically, the launcher execs at least once to ensure a suitable | |
118 * LD_LIBRARY_PATH is in effect for the process. The first exec | |
119 * screens out all the data model options; leaving the choice of data | |
120 * model implicit in the binary selected to run. However, in case no | |
121 * exec is done, the data model options are screened out before the vm | |
122 * is invoked. | |
123 * | |
124 * incoming argv ------------------------------ | |
125 * | | | |
126 * \|/ | | |
127 * CheckJVMType | | |
128 * (removes -client, -server, etc.) | | |
129 * \|/ | |
130 * CreateExecutionEnvironment | |
131 * (removes -d32 and -d64, | |
132 * determines desired data model, | |
133 * sets up LD_LIBRARY_PATH, | |
134 * and exec's) | |
135 * | | |
136 * -------------------------------------------- | |
137 * | | |
138 * \|/ | |
139 * exec child 1 incoming argv ----------------- | |
140 * | | | |
141 * \|/ | | |
142 * CheckJVMType | | |
143 * (removes -client, -server, etc.) | | |
144 * | \|/ | |
145 * | CreateExecutionEnvironment | |
146 * | (verifies desired data model | |
147 * | is running and acceptable | |
148 * | LD_LIBRARY_PATH; | |
149 * | no-op in child) | |
150 * | | |
151 * \|/ | |
152 * TranslateDashJArgs... | |
153 * (Prepare to pass args to vm) | |
154 * | | |
155 * | | |
156 * | | |
157 * \|/ | |
158 * ParseArguments | |
159 * (ignores -d32 and -d64, | |
160 * processes version options, | |
161 * creates argument list for vm, | |
162 * etc.) | |
163 * | |
164 */ | |
165 | |
166 static char *SetExecname(char **argv); | |
167 static char * GetExecname(); | |
168 static jboolean GetJVMPath(const char *jrepath, const char *jvmtype, | |
169 char *jvmpath, jint jvmpathsize, char * arch); | |
170 static jboolean GetJREPath(char *path, jint pathsize, char * arch, jboolean speculative); | |
171 | |
172 #ifndef GAMMA | |
173 const char * | |
174 GetArch() | |
175 { | |
176 return LIBARCHNAME; | |
177 } | |
178 #endif /* ifndef GAMMA */ | |
179 | |
180 void | |
181 CreateExecutionEnvironment(int *_argcp, | |
182 char ***_argvp, | |
183 char jrepath[], | |
184 jint so_jrepath, | |
185 char jvmpath[], | |
186 jint so_jvmpath, | |
187 char **original_argv) { | |
188 /* | |
189 * First, determine if we are running the desired data model. If we | |
190 * are running the desired data model, all the error messages | |
191 * associated with calling GetJREPath, ReadKnownVMs, etc. should be | |
192 * output. However, if we are not running the desired data model, | |
193 * some of the errors should be suppressed since it is more | |
194 * informative to issue an error message based on whether or not the | |
195 * os/processor combination has dual mode capabilities. | |
196 */ | |
197 | |
198 char *execname = NULL; | |
199 int original_argc = *_argcp; | |
200 jboolean jvmpathExists; | |
201 | |
202 /* Compute the name of the executable */ | |
203 execname = SetExecname(*_argvp); | |
204 | |
205 #ifndef GAMMA | |
206 /* Set the LD_LIBRARY_PATH environment variable, check data model | |
207 flags, and exec process, if needed */ | |
208 { | |
209 char *arch = (char *)GetArch(); /* like sparc or sparcv9 */ | |
210 char * jvmtype = NULL; | |
211 int argc = *_argcp; | |
212 char **argv = original_argv; | |
213 | |
214 char *runpath = NULL; /* existing effective LD_LIBRARY_PATH | |
215 setting */ | |
216 | |
217 int running = /* What data model is being ILP32 => | |
218 32 bit vm; LP64 => 64 bit vm */ | |
219 #ifdef _LP64 | |
220 64; | |
221 #else | |
222 32; | |
223 #endif | |
224 | |
225 int wanted = running; /* What data mode is being | |
226 asked for? Current model is | |
227 fine unless another model | |
228 is asked for */ | |
229 | |
230 char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */ | |
231 char* newpath = NULL; /* path on new LD_LIBRARY_PATH */ | |
232 char* lastslash = NULL; | |
233 | |
234 char** newenvp = NULL; /* current environment */ | |
235 | |
236 char** newargv = NULL; | |
237 int newargc = 0; | |
238 #ifdef __sun | |
239 char* dmpath = NULL; /* data model specific LD_LIBRARY_PATH, | |
240 Solaris only */ | |
241 #endif | |
242 | |
243 /* | |
244 * Starting in 1.5, all unix platforms accept the -d32 and -d64 | |
245 * options. On platforms where only one data-model is supported | |
246 * (e.g. ia-64 Linux), using the flag for the other data model is | |
247 * an error and will terminate the program. | |
248 */ | |
249 | |
250 { /* open new scope to declare local variables */ | |
251 int i; | |
252 | |
253 newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(*newargv)); | |
254 newargv[newargc++] = argv[0]; | |
255 | |
256 /* scan for data model arguments and remove from argument list; | |
257 last occurrence determines desired data model */ | |
258 for (i=1; i < argc; i++) { | |
259 | |
260 if (strcmp(argv[i], "-J-d64") == 0 || strcmp(argv[i], "-d64") == 0) { | |
261 wanted = 64; | |
262 continue; | |
263 } | |
264 if (strcmp(argv[i], "-J-d32") == 0 || strcmp(argv[i], "-d32") == 0) { | |
265 wanted = 32; | |
266 continue; | |
267 } | |
268 newargv[newargc++] = argv[i]; | |
269 | |
270 #ifdef JAVA_ARGS | |
271 if (argv[i][0] != '-') | |
272 continue; | |
273 #else | |
274 if (strcmp(argv[i], "-classpath") == 0 || strcmp(argv[i], "-cp") == 0) { | |
275 i++; | |
276 if (i >= argc) break; | |
277 newargv[newargc++] = argv[i]; | |
278 continue; | |
279 } | |
280 if (argv[i][0] != '-') { i++; break; } | |
281 #endif | |
282 } | |
283 | |
284 /* copy rest of args [i .. argc) */ | |
285 while (i < argc) { | |
286 newargv[newargc++] = argv[i++]; | |
287 } | |
288 newargv[newargc] = NULL; | |
289 | |
290 /* | |
291 * newargv has all proper arguments here | |
292 */ | |
293 | |
294 argc = newargc; | |
295 argv = newargv; | |
296 } | |
297 | |
298 /* If the data model is not changing, it is an error if the | |
299 jvmpath does not exist */ | |
300 if (wanted == running) { | |
301 /* Find out where the JRE is that we will be using. */ | |
302 if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { | |
303 fprintf(stderr, "Error: could not find Java 2 Runtime Environment.\n"); | |
304 exit(2); | |
305 } | |
306 | |
307 /* Find the specified JVM type */ | |
308 if (ReadKnownVMs(jrepath, arch, JNI_FALSE) < 1) { | |
309 fprintf(stderr, "Error: no known VMs. (check for corrupt jvm.cfg file)\n"); | |
310 exit(1); | |
311 } | |
312 | |
313 jvmpath[0] = '\0'; | |
314 jvmtype = CheckJvmType(_argcp, _argvp, JNI_FALSE); | |
315 | |
316 if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch )) { | |
317 fprintf(stderr, "Error: no `%s' JVM at `%s'.\n", jvmtype, jvmpath); | |
318 exit(4); | |
319 } | |
320 } else { /* do the same speculatively or exit */ | |
321 #ifdef DUAL_MODE | |
322 if (running != wanted) { | |
323 /* Find out where the JRE is that we will be using. */ | |
324 if (!GetJREPath(jrepath, so_jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME), JNI_TRUE)) { | |
325 goto EndDataModelSpeculate; | |
326 } | |
327 | |
328 /* | |
329 * Read in jvm.cfg for target data model and process vm | |
330 * selection options. | |
331 */ | |
332 if (ReadKnownVMs(jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME), JNI_TRUE) < 1) { | |
333 goto EndDataModelSpeculate; | |
334 } | |
335 jvmpath[0] = '\0'; | |
336 jvmtype = CheckJvmType(_argcp, _argvp, JNI_TRUE); | |
337 /* exec child can do error checking on the existence of the path */ | |
338 jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, | |
339 ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME)); | |
340 | |
341 } | |
342 EndDataModelSpeculate: /* give up and let other code report error message */ | |
343 ; | |
344 #else | |
345 fprintf(stderr, "Running a %d-bit JVM is not supported on this platform.\n", wanted); | |
346 exit(1); | |
347 #endif | |
348 } | |
349 | |
350 /* | |
351 * We will set the LD_LIBRARY_PATH as follows: | |
352 * | |
353 * o $JVMPATH (directory portion only) | |
354 * o $JRE/lib/$LIBARCHNAME | |
355 * o $JRE/../lib/$LIBARCHNAME | |
356 * | |
357 * followed by the user's previous effective LD_LIBRARY_PATH, if | |
358 * any. | |
359 */ | |
360 | |
361 #ifdef __sun | |
362 /* | |
363 * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH | |
364 * variables: | |
365 * | |
366 * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if | |
367 * data-model specific variables are not set. | |
368 * | |
369 * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH | |
370 * for 64-bit binaries. | |
371 * | |
372 * 3. LD_LIBRARY_PATH_32 -- overrides and replaces LD_LIBRARY_PATH | |
373 * for 32-bit binaries. | |
374 * | |
375 * The vm uses LD_LIBRARY_PATH to set the java.library.path system | |
376 * property. To shield the vm from the complication of multiple | |
377 * LD_LIBRARY_PATH variables, if the appropriate data model | |
378 * specific variable is set, we will act as if LD_LIBRARY_PATH had | |
379 * the value of the data model specific variant and the data model | |
380 * specific variant will be unset. Note that the variable for the | |
381 * *wanted* data model must be used (if it is set), not simply the | |
382 * current running data model. | |
383 */ | |
384 | |
385 switch(wanted) { | |
386 case 0: | |
387 if(running == 32) { | |
388 dmpath = getenv("LD_LIBRARY_PATH_32"); | |
389 wanted = 32; | |
390 } | |
391 else { | |
392 dmpath = getenv("LD_LIBRARY_PATH_64"); | |
393 wanted = 64; | |
394 } | |
395 break; | |
396 | |
397 case 32: | |
398 dmpath = getenv("LD_LIBRARY_PATH_32"); | |
399 break; | |
400 | |
401 case 64: | |
402 dmpath = getenv("LD_LIBRARY_PATH_64"); | |
403 break; | |
404 | |
405 default: | |
406 fprintf(stderr, "Improper value at line %d.", __LINE__); | |
407 exit(1); /* unknown value in wanted */ | |
408 break; | |
409 } | |
410 | |
411 /* | |
412 * If dmpath is NULL, the relevant data model specific variable is | |
413 * not set and normal LD_LIBRARY_PATH should be used. | |
414 */ | |
415 if( dmpath == NULL) { | |
416 runpath = getenv("LD_LIBRARY_PATH"); | |
417 } | |
418 else { | |
419 runpath = dmpath; | |
420 } | |
421 #else | |
422 /* | |
423 * If not on Solaris, assume only a single LD_LIBRARY_PATH | |
424 * variable. | |
425 */ | |
426 runpath = getenv("LD_LIBRARY_PATH"); | |
427 #endif /* __sun */ | |
428 | |
429 #ifdef __linux | |
430 /* | |
431 * On linux, if a binary is running as sgid or suid, glibc sets | |
432 * LD_LIBRARY_PATH to the empty string for security purposes. (In | |
433 * contrast, on Solaris the LD_LIBRARY_PATH variable for a | |
434 * privileged binary does not lose its settings; but the dynamic | |
435 * linker does apply more scrutiny to the path.) The launcher uses | |
436 * the value of LD_LIBRARY_PATH to prevent an exec loop. | |
437 * Therefore, if we are running sgid or suid, this function's | |
438 * setting of LD_LIBRARY_PATH will be ineffective and we should | |
439 * return from the function now. Getting the right libraries to | |
440 * be found must be handled through other mechanisms. | |
441 */ | |
442 if((getgid() != getegid()) || (getuid() != geteuid()) ) { | |
443 return; | |
444 } | |
445 #endif | |
446 | |
447 /* runpath contains current effective LD_LIBRARY_PATH setting */ | |
448 | |
449 jvmpath = JLI_StringDup(jvmpath); | |
450 new_runpath = JLI_MemAlloc( ((runpath!=NULL)?strlen(runpath):0) + | |
451 2*strlen(jrepath) + 2*strlen(arch) + | |
452 strlen(jvmpath) + 52); | |
453 newpath = new_runpath + strlen("LD_LIBRARY_PATH="); | |
454 | |
455 | |
456 /* | |
457 * Create desired LD_LIBRARY_PATH value for target data model. | |
458 */ | |
459 { | |
460 /* remove the name of the .so from the JVM path */ | |
461 lastslash = strrchr(jvmpath, '/'); | |
462 if (lastslash) | |
463 *lastslash = '\0'; | |
464 | |
465 | |
466 /* jvmpath, ((running != wanted)?((wanted==64)?"/"LIBARCH64NAME:"/.."):""), */ | |
467 | |
468 sprintf(new_runpath, "LD_LIBRARY_PATH=" | |
469 "%s:" | |
470 "%s/lib/%s:" | |
471 "%s/../lib/%s", | |
472 jvmpath, | |
473 #ifdef DUAL_MODE | |
474 jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME), | |
475 jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME) | |
476 #else | |
477 jrepath, arch, | |
478 jrepath, arch | |
479 #endif | |
480 ); | |
481 | |
482 | |
483 /* | |
484 * Check to make sure that the prefix of the current path is the | |
485 * desired environment variable setting. | |
486 */ | |
487 if (runpath != NULL && | |
488 strncmp(newpath, runpath, strlen(newpath))==0 && | |
489 (runpath[strlen(newpath)] == 0 || runpath[strlen(newpath)] == ':') && | |
490 (running == wanted) /* data model does not have to be changed */ | |
491 #ifdef __sun | |
492 && (dmpath == NULL) /* data model specific variables not set */ | |
493 #endif | |
494 ) { | |
495 | |
496 return; | |
497 | |
498 } | |
499 } | |
500 | |
501 /* | |
502 * Place the desired environment setting onto the prefix of | |
503 * LD_LIBRARY_PATH. Note that this prevents any possible infinite | |
504 * loop of execv() because we test for the prefix, above. | |
505 */ | |
506 if (runpath != 0) { | |
507 strcat(new_runpath, ":"); | |
508 strcat(new_runpath, runpath); | |
509 } | |
510 | |
511 if( putenv(new_runpath) != 0) { | |
512 exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set | |
513 properly */ | |
514 } | |
515 | |
516 /* | |
517 * Unix systems document that they look at LD_LIBRARY_PATH only | |
518 * once at startup, so we have to re-exec the current executable | |
519 * to get the changed environment variable to have an effect. | |
520 */ | |
521 | |
522 #ifdef __sun | |
523 /* | |
524 * If dmpath is not NULL, remove the data model specific string | |
525 * in the environment for the exec'ed child. | |
526 */ | |
527 | |
528 if( dmpath != NULL) | |
529 (void)UnsetEnv((wanted==32)?"LD_LIBRARY_PATH_32":"LD_LIBRARY_PATH_64"); | |
530 #endif | |
531 | |
532 newenvp = environ; | |
533 | |
534 { | |
535 char *newexec = execname; | |
536 #ifdef DUAL_MODE | |
537 /* | |
538 * If the data model is being changed, the path to the | |
539 * executable must be updated accordingly; the executable name | |
540 * and directory the executable resides in are separate. In the | |
541 * case of 32 => 64, the new bits are assumed to reside in, e.g. | |
542 * "olddir/LIBARCH64NAME/execname"; in the case of 64 => 32, | |
543 * the bits are assumed to be in "olddir/../execname". For example, | |
544 * | |
545 * olddir/sparcv9/execname | |
546 * olddir/amd64/execname | |
547 * | |
548 * for Solaris SPARC and Linux amd64, respectively. | |
549 */ | |
550 | |
551 if (running != wanted) { | |
552 char *oldexec = strcpy(JLI_MemAlloc(strlen(execname) + 1), execname); | |
553 char *olddir = oldexec; | |
554 char *oldbase = strrchr(oldexec, '/'); | |
555 | |
556 | |
557 newexec = JLI_MemAlloc(strlen(execname) + 20); | |
558 *oldbase++ = 0; | |
559 sprintf(newexec, "%s/%s/%s", olddir, | |
560 ((wanted==64) ? LIBARCH64NAME : ".."), oldbase); | |
561 argv[0] = newexec; | |
562 } | |
563 #endif | |
564 | |
565 (void)fflush(stdout); | |
566 (void)fflush(stderr); | |
567 execve(newexec, argv, newenvp); | |
568 perror("execve()"); | |
569 | |
570 fprintf(stderr, "Error trying to exec %s.\n", newexec); | |
571 fprintf(stderr, "Check if file exists and permissions are set correctly.\n"); | |
572 | |
573 #ifdef DUAL_MODE | |
574 if (running != wanted) { | |
575 fprintf(stderr, "Failed to start a %d-bit JVM process from a %d-bit JVM.\n", | |
576 wanted, running); | |
577 # ifdef __sun | |
578 | |
579 # ifdef __sparc | |
580 fprintf(stderr, "Verify all necessary J2SE components have been installed.\n" ); | |
581 fprintf(stderr, | |
582 "(Solaris SPARC 64-bit components must be installed after 32-bit components.)\n" ); | |
583 # else | |
584 fprintf(stderr, "Either 64-bit processes are not supported by this platform\n"); | |
585 fprintf(stderr, "or the 64-bit components have not been installed.\n"); | |
586 # endif | |
587 } | |
588 # endif | |
589 #endif | |
590 | |
591 } | |
592 | |
593 exit(1); | |
594 } | |
595 | |
596 #else /* ifndef GAMMA */ | |
597 | |
598 /* | |
599 * gamma launcher is simpler in that it doesn't handle VM flavors, data | |
600 * model, LD_LIBRARY_PATH, etc. Assuming everything is set-up correctly | |
601 * all we need to do here is to return correct path names. See also | |
602 * GetJVMPath() and GetApplicationHome(). | |
603 */ | |
604 | |
605 { char *arch = (char *) ARCH; /* like sparc or sparcv9 */ | |
606 char *p; | |
607 | |
608 if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { | |
609 fprintf(stderr, "Error: could not find Java 2 Runtime Environment.\n"); | |
610 exit(2); | |
611 } | |
612 | |
613 if (!GetJVMPath(jrepath, NULL, jvmpath, so_jvmpath, arch )) { | |
614 fprintf(stderr, "Error: no JVM at `%s'.\n", jvmpath); | |
615 exit(4); | |
616 } | |
617 } | |
618 | |
619 #endif /* ifndef GAMMA */ | |
620 } | |
621 | |
622 | |
623 /* | |
624 * On Solaris VM choosing is done by the launcher (java.c). | |
625 */ | |
626 static jboolean | |
627 GetJVMPath(const char *jrepath, const char *jvmtype, | |
628 char *jvmpath, jint jvmpathsize, char * arch) | |
629 { | |
630 struct stat s; | |
631 | |
632 #ifndef GAMMA | |
633 if (strchr(jvmtype, '/')) { | |
634 sprintf(jvmpath, "%s/" JVM_DLL, jvmtype); | |
635 } else { | |
636 sprintf(jvmpath, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype); | |
637 } | |
638 #else | |
639 /* | |
640 * For gamma launcher, JVM is either built-in or in the same directory. | |
641 * Either way we return "<exe_path>/libjvm.so" where <exe_path> is the | |
642 * directory where gamma launcher is located. | |
643 */ | |
644 | |
645 char *p; | |
646 | |
647 snprintf(jvmpath, jvmpathsize, "%s", GetExecname()); | |
648 p = strrchr(jvmpath, '/'); | |
649 if (p) { | |
650 /* replace executable name with libjvm.so */ | |
651 snprintf(p + 1, jvmpathsize - (p + 1 - jvmpath), "%s", JVM_DLL); | |
652 } else { | |
653 /* this case shouldn't happen */ | |
654 snprintf(jvmpath, jvmpathsize, "%s", JVM_DLL); | |
655 } | |
656 #endif /* ifndef GAMMA */ | |
657 | |
658 if (_launcher_debug) | |
659 printf("Does `%s' exist ... ", jvmpath); | |
660 | |
661 if (stat(jvmpath, &s) == 0) { | |
662 if (_launcher_debug) | |
663 printf("yes.\n"); | |
664 return JNI_TRUE; | |
665 } else { | |
666 if (_launcher_debug) | |
667 printf("no.\n"); | |
668 return JNI_FALSE; | |
669 } | |
670 } | |
671 | |
672 /* | |
673 * Find path to JRE based on .exe's location or registry settings. | |
674 */ | |
675 static jboolean | |
676 GetJREPath(char *path, jint pathsize, char * arch, jboolean speculative) | |
677 { | |
678 char libjava[MAXPATHLEN]; | |
679 | |
680 if (GetApplicationHome(path, pathsize)) { | |
681 /* Is JRE co-located with the application? */ | |
682 sprintf(libjava, "%s/lib/%s/" JAVA_DLL, path, arch); | |
683 if (access(libjava, F_OK) == 0) { | |
684 goto found; | |
685 } | |
686 | |
687 /* Does the app ship a private JRE in <apphome>/jre directory? */ | |
688 sprintf(libjava, "%s/jre/lib/%s/" JAVA_DLL, path, arch); | |
689 if (access(libjava, F_OK) == 0) { | |
690 strcat(path, "/jre"); | |
691 goto found; | |
692 } | |
693 } | |
694 | |
695 if (!speculative) | |
696 fprintf(stderr, "Error: could not find " JAVA_DLL "\n"); | |
697 return JNI_FALSE; | |
698 | |
699 found: | |
700 if (_launcher_debug) | |
701 printf("JRE path is %s\n", path); | |
702 return JNI_TRUE; | |
703 } | |
704 | |
705 jboolean | |
706 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) | |
707 { | |
708 #ifdef GAMMA | |
709 /* JVM is directly linked with gamma launcher; no dlopen() */ | |
710 ifn->CreateJavaVM = JNI_CreateJavaVM; | |
711 ifn->GetDefaultJavaVMInitArgs = JNI_GetDefaultJavaVMInitArgs; | |
712 return JNI_TRUE; | |
713 #else | |
714 Dl_info dlinfo; | |
715 void *libjvm; | |
716 | |
717 if (_launcher_debug) { | |
718 printf("JVM path is %s\n", jvmpath); | |
719 } | |
720 | |
721 libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL); | |
722 if (libjvm == NULL) { | |
723 #if defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */ | |
724 FILE * fp; | |
725 Elf32_Ehdr elf_head; | |
726 int count; | |
727 int location; | |
728 | |
729 fp = fopen(jvmpath, "r"); | |
730 if(fp == NULL) | |
731 goto error; | |
732 | |
733 /* read in elf header */ | |
734 count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp); | |
735 fclose(fp); | |
736 if(count < 1) | |
737 goto error; | |
738 | |
739 /* | |
740 * Check for running a server vm (compiled with -xarch=v8plus) | |
741 * on a stock v8 processor. In this case, the machine type in | |
742 * the elf header would not be included the architecture list | |
743 * provided by the isalist command, which is turn is gotten from | |
744 * sysinfo. This case cannot occur on 64-bit hardware and thus | |
745 * does not have to be checked for in binaries with an LP64 data | |
746 * model. | |
747 */ | |
748 if(elf_head.e_machine == EM_SPARC32PLUS) { | |
749 char buf[257]; /* recommended buffer size from sysinfo man | |
750 page */ | |
751 long length; | |
752 char* location; | |
753 | |
754 length = sysinfo(SI_ISALIST, buf, 257); | |
755 if(length > 0) { | |
756 location = strstr(buf, "sparcv8plus "); | |
757 if(location == NULL) { | |
758 fprintf(stderr, "SPARC V8 processor detected; Server compiler requires V9 or better.\n"); | |
759 fprintf(stderr, "Use Client compiler on V8 processors.\n"); | |
760 fprintf(stderr, "Could not create the Java virtual machine.\n"); | |
761 return JNI_FALSE; | |
762 } | |
763 } | |
764 } | |
765 #endif | |
766 fprintf(stderr, "dl failure on line %d", __LINE__); | |
767 goto error; | |
768 } | |
769 | |
770 ifn->CreateJavaVM = (CreateJavaVM_t) | |
771 dlsym(libjvm, "JNI_CreateJavaVM"); | |
772 if (ifn->CreateJavaVM == NULL) | |
773 goto error; | |
774 | |
775 ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) | |
776 dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); | |
777 if (ifn->GetDefaultJavaVMInitArgs == NULL) | |
778 goto error; | |
779 | |
780 return JNI_TRUE; | |
781 | |
782 error: | |
783 fprintf(stderr, "Error: failed %s, because %s\n", jvmpath, dlerror()); | |
784 return JNI_FALSE; | |
785 #endif /* ifndef GAMMA */ | |
786 } | |
787 | |
788 /* | |
789 * If app is "/foo/bin/javac", or "/foo/bin/sparcv9/javac" then put | |
790 * "/foo" into buf. | |
791 */ | |
792 jboolean | |
793 GetApplicationHome(char *buf, jint bufsize) | |
794 { | |
795 #ifdef __linux__ | |
796 char *execname = GetExecname(); | |
797 if (execname) { | |
798 strncpy(buf, execname, bufsize-1); | |
799 buf[bufsize-1] = '\0'; | |
800 } else { | |
801 return JNI_FALSE; | |
802 } | |
803 #else | |
804 Dl_info dlinfo; | |
805 | |
806 dladdr((void *)GetApplicationHome, &dlinfo); | |
807 if (realpath(dlinfo.dli_fname, buf) == NULL) { | |
808 fprintf(stderr, "Error: realpath(`%s') failed.\n", dlinfo.dli_fname); | |
809 return JNI_FALSE; | |
810 } | |
811 #endif | |
812 | |
813 #ifdef GAMMA | |
814 { | |
2027
aa6e219afbf1
7006354: Updates to Visual Studio project creation and development launcher
sla
parents:
1985
diff
changeset
|
815 /* gamma launcher uses JAVA_HOME environment variable to find JDK/JRE */ |
aa6e219afbf1
7006354: Updates to Visual Studio project creation and development launcher
sla
parents:
1985
diff
changeset
|
816 char* java_home_var = getenv("JAVA_HOME"); |
1985 | 817 if (java_home_var == NULL) { |
2027
aa6e219afbf1
7006354: Updates to Visual Studio project creation and development launcher
sla
parents:
1985
diff
changeset
|
818 printf("JAVA_HOME must point to a valid JDK/JRE to run gamma\n"); |
1985 | 819 return JNI_FALSE; |
820 } | |
821 snprintf(buf, bufsize, "%s", java_home_var); | |
822 } | |
823 #else | |
824 if (strrchr(buf, '/') == 0) { | |
825 buf[0] = '\0'; | |
826 return JNI_FALSE; | |
827 } | |
828 *(strrchr(buf, '/')) = '\0'; /* executable file */ | |
829 if (strlen(buf) < 4 || strrchr(buf, '/') == 0) { | |
830 buf[0] = '\0'; | |
831 return JNI_FALSE; | |
832 } | |
833 if (strcmp("/bin", buf + strlen(buf) - 4) != 0) | |
834 *(strrchr(buf, '/')) = '\0'; /* sparcv9 or amd64 */ | |
835 if (strlen(buf) < 4 || strcmp("/bin", buf + strlen(buf) - 4) != 0) { | |
836 buf[0] = '\0'; | |
837 return JNI_FALSE; | |
838 } | |
839 *(strrchr(buf, '/')) = '\0'; /* bin */ | |
840 #endif /* ifndef GAMMA */ | |
841 | |
842 return JNI_TRUE; | |
843 } | |
844 | |
845 | |
846 /* | |
847 * Return true if the named program exists | |
848 */ | |
849 static int | |
850 ProgramExists(char *name) | |
851 { | |
852 struct stat sb; | |
853 if (stat(name, &sb) != 0) return 0; | |
854 if (S_ISDIR(sb.st_mode)) return 0; | |
855 return (sb.st_mode & S_IEXEC) != 0; | |
856 } | |
857 | |
858 | |
859 /* | |
860 * Find a command in a directory, returning the path. | |
861 */ | |
862 static char * | |
863 Resolve(char *indir, char *cmd) | |
864 { | |
865 char name[PATH_MAX + 2], *real; | |
866 | |
867 if ((strlen(indir) + strlen(cmd) + 1) > PATH_MAX) return 0; | |
868 sprintf(name, "%s%c%s", indir, FILE_SEPARATOR, cmd); | |
869 if (!ProgramExists(name)) return 0; | |
870 real = JLI_MemAlloc(PATH_MAX + 2); | |
871 if (!realpath(name, real)) | |
872 strcpy(real, name); | |
873 return real; | |
874 } | |
875 | |
876 | |
877 /* | |
878 * Find a path for the executable | |
879 */ | |
880 static char * | |
881 FindExecName(char *program) | |
882 { | |
883 char cwdbuf[PATH_MAX+2]; | |
884 char *path; | |
885 char *tmp_path; | |
886 char *f; | |
887 char *result = NULL; | |
888 | |
889 /* absolute path? */ | |
890 if (*program == FILE_SEPARATOR || | |
891 (FILE_SEPARATOR=='\\' && strrchr(program, ':'))) | |
892 return Resolve("", program+1); | |
893 | |
894 /* relative path? */ | |
895 if (strrchr(program, FILE_SEPARATOR) != 0) { | |
896 char buf[PATH_MAX+2]; | |
897 return Resolve(getcwd(cwdbuf, sizeof(cwdbuf)), program); | |
898 } | |
899 | |
900 /* from search path? */ | |
901 path = getenv("PATH"); | |
902 if (!path || !*path) path = "."; | |
903 tmp_path = JLI_MemAlloc(strlen(path) + 2); | |
904 strcpy(tmp_path, path); | |
905 | |
906 for (f=tmp_path; *f && result==0; ) { | |
907 char *s = f; | |
908 while (*f && (*f != PATH_SEPARATOR)) ++f; | |
909 if (*f) *f++ = 0; | |
910 if (*s == FILE_SEPARATOR) | |
911 result = Resolve(s, program); | |
912 else { | |
913 /* relative path element */ | |
914 char dir[2*PATH_MAX]; | |
915 sprintf(dir, "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)), | |
916 FILE_SEPARATOR, s); | |
917 result = Resolve(dir, program); | |
918 } | |
919 if (result != 0) break; | |
920 } | |
921 | |
922 JLI_MemFree(tmp_path); | |
923 return result; | |
924 } | |
925 | |
926 | |
927 /* Store the name of the executable once computed */ | |
928 static char *execname = NULL; | |
929 | |
930 /* | |
931 * Compute the name of the executable | |
932 * | |
933 * In order to re-exec securely we need the absolute path of the | |
934 * executable. On Solaris getexecname(3c) may not return an absolute | |
935 * path so we use dladdr to get the filename of the executable and | |
936 * then use realpath to derive an absolute path. From Solaris 9 | |
937 * onwards the filename returned in DL_info structure from dladdr is | |
938 * an absolute pathname so technically realpath isn't required. | |
939 * On Linux we read the executable name from /proc/self/exe. | |
940 * As a fallback, and for platforms other than Solaris and Linux, | |
941 * we use FindExecName to compute the executable name. | |
942 */ | |
943 static char * | |
944 SetExecname(char **argv) | |
945 { | |
946 char* exec_path = NULL; | |
947 | |
948 if (execname != NULL) /* Already determined */ | |
949 return (execname); | |
950 | |
951 #if defined(__sun) | |
952 { | |
953 Dl_info dlinfo; | |
954 if (dladdr((void*)&SetExecname, &dlinfo)) { | |
955 char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1); | |
956 if (resolved != NULL) { | |
957 exec_path = realpath(dlinfo.dli_fname, resolved); | |
958 if (exec_path == NULL) { | |
959 JLI_MemFree(resolved); | |
960 } | |
961 } | |
962 } | |
963 } | |
964 #elif defined(__linux__) | |
965 { | |
966 const char* self = "/proc/self/exe"; | |
967 char buf[PATH_MAX+1]; | |
968 int len = readlink(self, buf, PATH_MAX); | |
969 if (len >= 0) { | |
970 buf[len] = '\0'; /* readlink doesn't nul terminate */ | |
971 exec_path = JLI_StringDup(buf); | |
972 } | |
973 } | |
974 #else /* !__sun && !__linux */ | |
975 { | |
976 /* Not implemented */ | |
977 } | |
978 #endif | |
979 | |
980 if (exec_path == NULL) { | |
981 exec_path = FindExecName(argv[0]); | |
982 } | |
983 execname = exec_path; | |
984 return exec_path; | |
985 } | |
986 | |
987 /* | |
988 * Return the name of the executable. Used in java_md.c to find the JRE area. | |
989 */ | |
990 static char * | |
991 GetExecname() { | |
992 return execname; | |
993 } | |
994 | |
995 void ReportErrorMessage(char * message, jboolean always) { | |
996 if (always) { | |
997 fprintf(stderr, "%s\n", message); | |
998 } | |
999 } | |
1000 | |
1001 void ReportErrorMessage2(char * format, char * string, jboolean always) { | |
1002 if (always) { | |
1003 fprintf(stderr, format, string); | |
1004 fprintf(stderr, "\n"); | |
1005 } | |
1006 } | |
1007 | |
1008 void ReportExceptionDescription(JNIEnv * env) { | |
1009 (*env)->ExceptionDescribe(env); | |
1010 } | |
1011 | |
1012 /* | |
1013 * Return JNI_TRUE for an option string that has no effect but should | |
1014 * _not_ be passed on to the vm; return JNI_FALSE otherwise. On | |
1015 * Solaris SPARC, this screening needs to be done if: | |
1016 * 1) LD_LIBRARY_PATH does _not_ need to be reset and | |
1017 * 2) -d32 or -d64 is passed to a binary with a matching data model | |
1018 * (the exec in SetLibraryPath removes -d<n> options and points the | |
1019 * exec to the proper binary). When this exec is not done, these options | |
1020 * would end up getting passed onto the vm. | |
1021 */ | |
1022 jboolean RemovableMachineDependentOption(char * option) { | |
1023 /* | |
1024 * Unconditionally remove both -d32 and -d64 options since only | |
1025 * the last such options has an effect; e.g. | |
1026 * java -d32 -d64 -d32 -version | |
1027 * is equivalent to | |
1028 * java -d32 -version | |
1029 */ | |
1030 | |
1031 if( (strcmp(option, "-d32") == 0 ) || | |
1032 (strcmp(option, "-d64") == 0 )) | |
1033 return JNI_TRUE; | |
1034 else | |
1035 return JNI_FALSE; | |
1036 } | |
1037 | |
1038 void PrintMachineDependentOptions() { | |
1039 fprintf(stdout, | |
1040 " -d32 use a 32-bit data model if available\n" | |
1041 "\n" | |
1042 " -d64 use a 64-bit data model if available\n"); | |
1043 return; | |
1044 } | |
1045 | |
1046 #ifndef GAMMA | |
1047 /* | |
1048 * The following methods (down to ServerClassMachine()) answer | |
1049 * the question about whether a machine is a "server-class" | |
1050 * machine. A server-class machine is loosely defined as one | |
1051 * with 2 or more processors and 2 gigabytes or more physical | |
1052 * memory. The definition of a processor is a physical package, | |
1053 * not a hyperthreaded chip masquerading as a multi-processor. | |
1054 * The definition of memory is also somewhat fuzzy, since x86 | |
1055 * machines seem not to report all the memory in their DIMMs, we | |
1056 * think because of memory mapping of graphics cards, etc. | |
1057 * | |
1058 * This code is somewhat more confused with #ifdef's than we'd | |
1059 * like because this file is used by both Solaris and Linux | |
1060 * platforms, and so needs to be parameterized for SPARC and | |
1061 * i586 hardware. The other Linux platforms (amd64 and ia64) | |
1062 * don't even ask this question, because they only come with | |
1063 * server JVMs. */ | |
1064 | |
1065 # define KB (1024UL) | |
1066 # define MB (1024UL * KB) | |
1067 # define GB (1024UL * MB) | |
1068 | |
1069 /* Compute physical memory by asking the OS */ | |
1070 uint64_t | |
1071 physical_memory(void) { | |
1072 const uint64_t pages = (uint64_t) sysconf(_SC_PHYS_PAGES); | |
1073 const uint64_t page_size = (uint64_t) sysconf(_SC_PAGESIZE); | |
1074 const uint64_t result = pages * page_size; | |
1075 # define UINT64_FORMAT "%" PRIu64 | |
1076 | |
1077 if (_launcher_debug) { | |
1078 printf("pages: " UINT64_FORMAT | |
1079 " page_size: " UINT64_FORMAT | |
1080 " physical memory: " UINT64_FORMAT " (%.3fGB)\n", | |
1081 pages, page_size, result, result / (double) GB); | |
1082 } | |
1083 return result; | |
1084 } | |
1085 | |
1086 #if defined(__sun) && defined(__sparc) | |
1087 | |
1088 /* Methods for solaris-sparc: these are easy. */ | |
1089 | |
1090 /* Ask the OS how many processors there are. */ | |
1091 unsigned long | |
1092 physical_processors(void) { | |
1093 const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF); | |
1094 | |
1095 if (_launcher_debug) { | |
1096 printf("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors); | |
1097 } | |
1098 return sys_processors; | |
1099 } | |
1100 | |
1101 /* The solaris-sparc version of the "server-class" predicate. */ | |
1102 jboolean | |
1103 solaris_sparc_ServerClassMachine(void) { | |
1104 jboolean result = JNI_FALSE; | |
1105 /* How big is a server class machine? */ | |
1106 const unsigned long server_processors = 2UL; | |
1107 const uint64_t server_memory = 2UL * GB; | |
1108 const uint64_t actual_memory = physical_memory(); | |
1109 | |
1110 /* Is this a server class machine? */ | |
1111 if (actual_memory >= server_memory) { | |
1112 const unsigned long actual_processors = physical_processors(); | |
1113 if (actual_processors >= server_processors) { | |
1114 result = JNI_TRUE; | |
1115 } | |
1116 } | |
1117 if (_launcher_debug) { | |
1118 printf("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n", | |
1119 (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE")); | |
1120 } | |
1121 return result; | |
1122 } | |
1123 | |
1124 #endif /* __sun && __sparc */ | |
1125 | |
1126 #if defined(__sun) && defined(i586) | |
1127 | |
1128 /* | |
1129 * A utility method for asking the CPU about itself. | |
1130 * There's a corresponding version of linux-i586 | |
1131 * because the compilers are different. | |
1132 */ | |
1133 void | |
1134 get_cpuid(uint32_t arg, | |
1135 uint32_t* eaxp, | |
1136 uint32_t* ebxp, | |
1137 uint32_t* ecxp, | |
1138 uint32_t* edxp) { | |
1139 #ifdef _LP64 | |
1140 asm( | |
1141 /* rbx is a callee-saved register */ | |
1142 " movq %rbx, %r11 \n" | |
1143 /* rdx and rcx are 3rd and 4th argument registers */ | |
1144 " movq %rdx, %r10 \n" | |
1145 " movq %rcx, %r9 \n" | |
1146 " movl %edi, %eax \n" | |
1147 " cpuid \n" | |
1148 " movl %eax, (%rsi)\n" | |
1149 " movl %ebx, (%r10)\n" | |
1150 " movl %ecx, (%r9) \n" | |
1151 " movl %edx, (%r8) \n" | |
1152 /* Restore rbx */ | |
1153 " movq %r11, %rbx"); | |
1154 #else | |
1155 /* EBX is a callee-saved register */ | |
1156 asm(" pushl %ebx"); | |
1157 /* Need ESI for storing through arguments */ | |
1158 asm(" pushl %esi"); | |
1159 asm(" movl 8(%ebp), %eax \n" | |
1160 " cpuid \n" | |
1161 " movl 12(%ebp), %esi \n" | |
1162 " movl %eax, (%esi) \n" | |
1163 " movl 16(%ebp), %esi \n" | |
1164 " movl %ebx, (%esi) \n" | |
1165 " movl 20(%ebp), %esi \n" | |
1166 " movl %ecx, (%esi) \n" | |
1167 " movl 24(%ebp), %esi \n" | |
1168 " movl %edx, (%esi) "); | |
1169 /* Restore ESI and EBX */ | |
1170 asm(" popl %esi"); | |
1171 /* Restore EBX */ | |
1172 asm(" popl %ebx"); | |
1173 #endif | |
1174 } | |
1175 | |
1176 #endif /* __sun && i586 */ | |
1177 | |
1178 #if defined(__linux__) && defined(i586) | |
1179 | |
1180 /* | |
1181 * A utility method for asking the CPU about itself. | |
1182 * There's a corresponding version of solaris-i586 | |
1183 * because the compilers are different. | |
1184 */ | |
1185 void | |
1186 get_cpuid(uint32_t arg, | |
1187 uint32_t* eaxp, | |
1188 uint32_t* ebxp, | |
1189 uint32_t* ecxp, | |
1190 uint32_t* edxp) { | |
1191 #ifdef _LP64 | |
1192 __asm__ volatile (/* Instructions */ | |
1193 " movl %4, %%eax \n" | |
1194 " cpuid \n" | |
1195 " movl %%eax, (%0)\n" | |
1196 " movl %%ebx, (%1)\n" | |
1197 " movl %%ecx, (%2)\n" | |
1198 " movl %%edx, (%3)\n" | |
1199 : /* Outputs */ | |
1200 : /* Inputs */ | |
1201 "r" (eaxp), | |
1202 "r" (ebxp), | |
1203 "r" (ecxp), | |
1204 "r" (edxp), | |
1205 "r" (arg) | |
1206 : /* Clobbers */ | |
1207 "%rax", "%rbx", "%rcx", "%rdx", "memory" | |
1208 ); | |
1209 #else | |
1210 uint32_t value_of_eax = 0; | |
1211 uint32_t value_of_ebx = 0; | |
1212 uint32_t value_of_ecx = 0; | |
1213 uint32_t value_of_edx = 0; | |
1214 __asm__ volatile (/* Instructions */ | |
1215 /* ebx is callee-save, so push it */ | |
1216 " pushl %%ebx \n" | |
1217 " movl %4, %%eax \n" | |
1218 " cpuid \n" | |
1219 " movl %%eax, %0 \n" | |
1220 " movl %%ebx, %1 \n" | |
1221 " movl %%ecx, %2 \n" | |
1222 " movl %%edx, %3 \n" | |
1223 /* restore ebx */ | |
1224 " popl %%ebx \n" | |
1225 | |
1226 : /* Outputs */ | |
1227 "=m" (value_of_eax), | |
1228 "=m" (value_of_ebx), | |
1229 "=m" (value_of_ecx), | |
1230 "=m" (value_of_edx) | |
1231 : /* Inputs */ | |
1232 "m" (arg) | |
1233 : /* Clobbers */ | |
1234 "%eax", "%ecx", "%edx" | |
1235 ); | |
1236 *eaxp = value_of_eax; | |
1237 *ebxp = value_of_ebx; | |
1238 *ecxp = value_of_ecx; | |
1239 *edxp = value_of_edx; | |
1240 #endif | |
1241 } | |
1242 | |
1243 #endif /* __linux__ && i586 */ | |
1244 | |
1245 #ifdef i586 | |
1246 /* | |
1247 * Routines shared by solaris-i586 and linux-i586. | |
1248 */ | |
1249 | |
1250 enum HyperThreadingSupport_enum { | |
1251 hts_supported = 1, | |
1252 hts_too_soon_to_tell = 0, | |
1253 hts_not_supported = -1, | |
1254 hts_not_pentium4 = -2, | |
1255 hts_not_intel = -3 | |
1256 }; | |
1257 typedef enum HyperThreadingSupport_enum HyperThreadingSupport; | |
1258 | |
1259 /* Determine if hyperthreading is supported */ | |
1260 HyperThreadingSupport | |
1261 hyperthreading_support(void) { | |
1262 HyperThreadingSupport result = hts_too_soon_to_tell; | |
1263 /* Bits 11 through 8 is family processor id */ | |
1264 # define FAMILY_ID_SHIFT 8 | |
1265 # define FAMILY_ID_MASK 0xf | |
1266 /* Bits 23 through 20 is extended family processor id */ | |
1267 # define EXT_FAMILY_ID_SHIFT 20 | |
1268 # define EXT_FAMILY_ID_MASK 0xf | |
1269 /* Pentium 4 family processor id */ | |
1270 # define PENTIUM4_FAMILY_ID 0xf | |
1271 /* Bit 28 indicates Hyper-Threading Technology support */ | |
1272 # define HT_BIT_SHIFT 28 | |
1273 # define HT_BIT_MASK 1 | |
1274 uint32_t vendor_id[3] = { 0U, 0U, 0U }; | |
1275 uint32_t value_of_eax = 0U; | |
1276 uint32_t value_of_edx = 0U; | |
1277 uint32_t dummy = 0U; | |
1278 | |
1279 /* Yes, this is supposed to be [0], [2], [1] */ | |
1280 get_cpuid(0, &dummy, &vendor_id[0], &vendor_id[2], &vendor_id[1]); | |
1281 if (_launcher_debug) { | |
1282 printf("vendor: %c %c %c %c %c %c %c %c %c %c %c %c \n", | |
1283 ((vendor_id[0] >> 0) & 0xff), | |
1284 ((vendor_id[0] >> 8) & 0xff), | |
1285 ((vendor_id[0] >> 16) & 0xff), | |
1286 ((vendor_id[0] >> 24) & 0xff), | |
1287 ((vendor_id[1] >> 0) & 0xff), | |
1288 ((vendor_id[1] >> 8) & 0xff), | |
1289 ((vendor_id[1] >> 16) & 0xff), | |
1290 ((vendor_id[1] >> 24) & 0xff), | |
1291 ((vendor_id[2] >> 0) & 0xff), | |
1292 ((vendor_id[2] >> 8) & 0xff), | |
1293 ((vendor_id[2] >> 16) & 0xff), | |
1294 ((vendor_id[2] >> 24) & 0xff)); | |
1295 } | |
1296 get_cpuid(1, &value_of_eax, &dummy, &dummy, &value_of_edx); | |
1297 if (_launcher_debug) { | |
1298 printf("value_of_eax: 0x%x value_of_edx: 0x%x\n", | |
1299 value_of_eax, value_of_edx); | |
1300 } | |
1301 if ((((value_of_eax >> FAMILY_ID_SHIFT) & FAMILY_ID_MASK) == PENTIUM4_FAMILY_ID) || | |
1302 (((value_of_eax >> EXT_FAMILY_ID_SHIFT) & EXT_FAMILY_ID_MASK) != 0)) { | |
1303 if ((((vendor_id[0] >> 0) & 0xff) == 'G') && | |
1304 (((vendor_id[0] >> 8) & 0xff) == 'e') && | |
1305 (((vendor_id[0] >> 16) & 0xff) == 'n') && | |
1306 (((vendor_id[0] >> 24) & 0xff) == 'u') && | |
1307 (((vendor_id[1] >> 0) & 0xff) == 'i') && | |
1308 (((vendor_id[1] >> 8) & 0xff) == 'n') && | |
1309 (((vendor_id[1] >> 16) & 0xff) == 'e') && | |
1310 (((vendor_id[1] >> 24) & 0xff) == 'I') && | |
1311 (((vendor_id[2] >> 0) & 0xff) == 'n') && | |
1312 (((vendor_id[2] >> 8) & 0xff) == 't') && | |
1313 (((vendor_id[2] >> 16) & 0xff) == 'e') && | |
1314 (((vendor_id[2] >> 24) & 0xff) == 'l')) { | |
1315 if (((value_of_edx >> HT_BIT_SHIFT) & HT_BIT_MASK) == HT_BIT_MASK) { | |
1316 if (_launcher_debug) { | |
1317 printf("Hyperthreading supported\n"); | |
1318 } | |
1319 result = hts_supported; | |
1320 } else { | |
1321 if (_launcher_debug) { | |
1322 printf("Hyperthreading not supported\n"); | |
1323 } | |
1324 result = hts_not_supported; | |
1325 } | |
1326 } else { | |
1327 if (_launcher_debug) { | |
1328 printf("Not GenuineIntel\n"); | |
1329 } | |
1330 result = hts_not_intel; | |
1331 } | |
1332 } else { | |
1333 if (_launcher_debug) { | |
1334 printf("not Pentium 4 or extended\n"); | |
1335 } | |
1336 result = hts_not_pentium4; | |
1337 } | |
1338 return result; | |
1339 } | |
1340 | |
1341 /* Determine how many logical processors there are per CPU */ | |
1342 unsigned int | |
1343 logical_processors_per_package(void) { | |
1344 /* | |
1345 * After CPUID with EAX==1, register EBX bits 23 through 16 | |
1346 * indicate the number of logical processors per package | |
1347 */ | |
1348 # define NUM_LOGICAL_SHIFT 16 | |
1349 # define NUM_LOGICAL_MASK 0xff | |
1350 unsigned int result = 1U; | |
1351 const HyperThreadingSupport hyperthreading = hyperthreading_support(); | |
1352 | |
1353 if (hyperthreading == hts_supported) { | |
1354 uint32_t value_of_ebx = 0U; | |
1355 uint32_t dummy = 0U; | |
1356 | |
1357 get_cpuid(1, &dummy, &value_of_ebx, &dummy, &dummy); | |
1358 result = (value_of_ebx >> NUM_LOGICAL_SHIFT) & NUM_LOGICAL_MASK; | |
1359 if (_launcher_debug) { | |
1360 printf("logical processors per package: %u\n", result); | |
1361 } | |
1362 } | |
1363 return result; | |
1364 } | |
1365 | |
1366 /* Compute the number of physical processors, not logical processors */ | |
1367 unsigned long | |
1368 physical_processors(void) { | |
1369 const long sys_processors = sysconf(_SC_NPROCESSORS_CONF); | |
1370 unsigned long result = sys_processors; | |
1371 | |
1372 if (_launcher_debug) { | |
1373 printf("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors); | |
1374 } | |
1375 if (sys_processors > 1) { | |
1376 unsigned int logical_processors = logical_processors_per_package(); | |
1377 if (logical_processors > 1) { | |
1378 result = (unsigned long) sys_processors / logical_processors; | |
1379 } | |
1380 } | |
1381 if (_launcher_debug) { | |
1382 printf("physical processors: %lu\n", result); | |
1383 } | |
1384 return result; | |
1385 } | |
1386 | |
1387 #endif /* i586 */ | |
1388 | |
1389 #if defined(__sun) && defined(i586) | |
1390 | |
1391 /* The definition of a server-class machine for solaris-i586/amd64 */ | |
1392 jboolean | |
1393 solaris_i586_ServerClassMachine(void) { | |
1394 jboolean result = JNI_FALSE; | |
1395 /* How big is a server class machine? */ | |
1396 const unsigned long server_processors = 2UL; | |
1397 const uint64_t server_memory = 2UL * GB; | |
1398 /* | |
1399 * We seem not to get our full complement of memory. | |
1400 * We allow some part (1/8?) of the memory to be "missing", | |
1401 * based on the sizes of DIMMs, and maybe graphics cards. | |
1402 */ | |
1403 const uint64_t missing_memory = 256UL * MB; | |
1404 const uint64_t actual_memory = physical_memory(); | |
1405 | |
1406 /* Is this a server class machine? */ | |
1407 if (actual_memory >= (server_memory - missing_memory)) { | |
1408 const unsigned long actual_processors = physical_processors(); | |
1409 if (actual_processors >= server_processors) { | |
1410 result = JNI_TRUE; | |
1411 } | |
1412 } | |
1413 if (_launcher_debug) { | |
1414 printf("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n", | |
1415 (result == JNI_TRUE ? "true" : "false")); | |
1416 } | |
1417 return result; | |
1418 } | |
1419 | |
1420 #endif /* __sun && i586 */ | |
1421 | |
1422 #if defined(__linux__) && defined(i586) | |
1423 | |
1424 /* The definition of a server-class machine for linux-i586 */ | |
1425 jboolean | |
1426 linux_i586_ServerClassMachine(void) { | |
1427 jboolean result = JNI_FALSE; | |
1428 /* How big is a server class machine? */ | |
1429 const unsigned long server_processors = 2UL; | |
1430 const uint64_t server_memory = 2UL * GB; | |
1431 /* | |
1432 * We seem not to get our full complement of memory. | |
1433 * We allow some part (1/8?) of the memory to be "missing", | |
1434 * based on the sizes of DIMMs, and maybe graphics cards. | |
1435 */ | |
1436 const uint64_t missing_memory = 256UL * MB; | |
1437 const uint64_t actual_memory = physical_memory(); | |
1438 | |
1439 /* Is this a server class machine? */ | |
1440 if (actual_memory >= (server_memory - missing_memory)) { | |
1441 const unsigned long actual_processors = physical_processors(); | |
1442 if (actual_processors >= server_processors) { | |
1443 result = JNI_TRUE; | |
1444 } | |
1445 } | |
1446 if (_launcher_debug) { | |
1447 printf("linux_" LIBARCHNAME "_ServerClassMachine: %s\n", | |
1448 (result == JNI_TRUE ? "true" : "false")); | |
1449 } | |
1450 return result; | |
1451 } | |
1452 | |
1453 #endif /* __linux__ && i586 */ | |
1454 | |
1455 /* Dispatch to the platform-specific definition of "server-class" */ | |
1456 jboolean | |
1457 ServerClassMachine(void) { | |
1458 jboolean result = JNI_FALSE; | |
1459 #if defined(NEVER_ACT_AS_SERVER_CLASS_MACHINE) | |
1460 result = JNI_FALSE; | |
1461 #elif defined(ALWAYS_ACT_AS_SERVER_CLASS_MACHINE) | |
1462 result = JNI_TRUE; | |
1463 #elif defined(__sun) && defined(__sparc) | |
1464 result = solaris_sparc_ServerClassMachine(); | |
1465 #elif defined(__sun) && defined(i586) | |
1466 result = solaris_i586_ServerClassMachine(); | |
1467 #elif defined(__linux__) && defined(i586) | |
1468 result = linux_i586_ServerClassMachine(); | |
1469 #else | |
1470 if (_launcher_debug) { | |
1471 printf("ServerClassMachine: returns default value of %s\n", | |
1472 (result == JNI_TRUE ? "true" : "false")); | |
1473 } | |
1474 #endif | |
1475 return result; | |
1476 } | |
1477 | |
1478 /* | |
1479 * Since using the file system as a registry is a bit risky, perform | |
1480 * additional sanity checks on the identified directory to validate | |
1481 * it as a valid jre/sdk. | |
1482 * | |
1483 * Return 0 if the tests fail; otherwise return non-zero (true). | |
1484 * | |
1485 * Note that checking for anything more than the existence of an | |
1486 * executable object at bin/java relative to the path being checked | |
1487 * will break the regression tests. | |
1488 */ | |
1489 static int | |
1490 CheckSanity(char *path, char *dir) | |
1491 { | |
1492 char buffer[PATH_MAX]; | |
1493 | |
1494 if (strlen(path) + strlen(dir) + 11 > PATH_MAX) | |
1495 return (0); /* Silently reject "impossibly" long paths */ | |
1496 | |
1497 (void)strcat(strcat(strcat(strcpy(buffer, path), "/"), dir), "/bin/java"); | |
1498 return ((access(buffer, X_OK) == 0) ? 1 : 0); | |
1499 } | |
1500 | |
1501 /* | |
1502 * Determine if there is an acceptable JRE in the directory dirname. | |
1503 * Upon locating the "best" one, return a fully qualified path to | |
1504 * it. "Best" is defined as the most advanced JRE meeting the | |
1505 * constraints contained in the manifest_info. If no JRE in this | |
1506 * directory meets the constraints, return NULL. | |
1507 * | |
1508 * Note that we don't check for errors in reading the directory | |
1509 * (which would be done by checking errno). This is because it | |
1510 * doesn't matter if we get an error reading the directory, or | |
1511 * we just don't find anything interesting in the directory. We | |
1512 * just return NULL in either case. | |
1513 * | |
1514 * The historical names of j2sdk and j2re were changed to jdk and | |
1515 * jre respecively as part of the 1.5 rebranding effort. Since the | |
1516 * former names are legacy on Linux, they must be recognized for | |
1517 * all time. Fortunately, this is a minor cost. | |
1518 */ | |
1519 static char | |
1520 *ProcessDir(manifest_info *info, char *dirname) | |
1521 { | |
1522 DIR *dirp; | |
1523 struct dirent *dp; | |
1524 char *best = NULL; | |
1525 int offset; | |
1526 int best_offset = 0; | |
1527 char *ret_str = NULL; | |
1528 char buffer[PATH_MAX]; | |
1529 | |
1530 if ((dirp = opendir(dirname)) == NULL) | |
1531 return (NULL); | |
1532 | |
1533 do { | |
1534 if ((dp = readdir(dirp)) != NULL) { | |
1535 offset = 0; | |
1536 if ((strncmp(dp->d_name, "jre", 3) == 0) || | |
1537 (strncmp(dp->d_name, "jdk", 3) == 0)) | |
1538 offset = 3; | |
1539 else if (strncmp(dp->d_name, "j2re", 4) == 0) | |
1540 offset = 4; | |
1541 else if (strncmp(dp->d_name, "j2sdk", 5) == 0) | |
1542 offset = 5; | |
1543 if (offset > 0) { | |
1544 if ((JLI_AcceptableRelease(dp->d_name + offset, | |
1545 info->jre_version)) && CheckSanity(dirname, dp->d_name)) | |
1546 if ((best == NULL) || (JLI_ExactVersionId( | |
1547 dp->d_name + offset, best + best_offset) > 0)) { | |
1548 if (best != NULL) | |
1549 JLI_MemFree(best); | |
1550 best = JLI_StringDup(dp->d_name); | |
1551 best_offset = offset; | |
1552 } | |
1553 } | |
1554 } | |
1555 } while (dp != NULL); | |
1556 (void) closedir(dirp); | |
1557 if (best == NULL) | |
1558 return (NULL); | |
1559 else { | |
1560 ret_str = JLI_MemAlloc(strlen(dirname) + strlen(best) + 2); | |
1561 ret_str = strcat(strcat(strcpy(ret_str, dirname), "/"), best); | |
1562 JLI_MemFree(best); | |
1563 return (ret_str); | |
1564 } | |
1565 } | |
1566 | |
1567 /* | |
1568 * This is the global entry point. It examines the host for the optimal | |
1569 * JRE to be used by scanning a set of directories. The set of directories | |
1570 * is platform dependent and can be overridden by the environment | |
1571 * variable JAVA_VERSION_PATH. | |
1572 * | |
1573 * This routine itself simply determines the set of appropriate | |
1574 * directories before passing control onto ProcessDir(). | |
1575 */ | |
1576 char* | |
1577 LocateJRE(manifest_info* info) | |
1578 { | |
1579 char *path; | |
1580 char *home; | |
1581 char *target = NULL; | |
1582 char *dp; | |
1583 char *cp; | |
1584 | |
1585 /* | |
1586 * Start by getting JAVA_VERSION_PATH | |
1587 */ | |
1588 if (info->jre_restrict_search) | |
1589 path = JLI_StringDup(system_dir); | |
1590 else if ((path = getenv("JAVA_VERSION_PATH")) != NULL) | |
1591 path = JLI_StringDup(path); | |
1592 else | |
1593 if ((home = getenv("HOME")) != NULL) { | |
1594 path = (char *)JLI_MemAlloc(strlen(home) + strlen(system_dir) + | |
1595 strlen(user_dir) + 2); | |
1596 path = strcat(strcat(strcat(strcpy(path, home), | |
1597 user_dir), ":"), system_dir); | |
1598 } else | |
1599 path = JLI_StringDup(system_dir); | |
1600 | |
1601 /* | |
1602 * Step through each directory on the path. Terminate the scan with | |
1603 * the first directory with an acceptable JRE. | |
1604 */ | |
1605 cp = dp = path; | |
1606 while (dp != NULL) { | |
1607 cp = strchr(dp, (int)':'); | |
1608 if (cp != NULL) | |
1609 *cp = (char)NULL; | |
1610 if ((target = ProcessDir(info, dp)) != NULL) | |
1611 break; | |
1612 dp = cp; | |
1613 if (dp != NULL) | |
1614 dp++; | |
1615 } | |
1616 JLI_MemFree(path); | |
1617 return (target); | |
1618 } | |
1619 | |
1620 /* | |
1621 * Given a path to a jre to execute, this routine checks if this process | |
1622 * is indeed that jre. If not, it exec's that jre. | |
1623 * | |
1624 * We want to actually check the paths rather than just the version string | |
1625 * built into the executable, so that given version specification (and | |
1626 * JAVA_VERSION_PATH) will yield the exact same Java environment, regardless | |
1627 * of the version of the arbitrary launcher we start with. | |
1628 */ | |
1629 void | |
1630 ExecJRE(char *jre, char **argv) | |
1631 { | |
1632 char wanted[PATH_MAX]; | |
1633 char *execname; | |
1634 char *progname; | |
1635 | |
1636 /* | |
1637 * Resolve the real path to the directory containing the selected JRE. | |
1638 */ | |
1639 if (realpath(jre, wanted) == NULL) { | |
1640 fprintf(stderr, "Unable to resolve %s\n", jre); | |
1641 exit(1); | |
1642 } | |
1643 | |
1644 /* | |
1645 * Resolve the real path to the currently running launcher. | |
1646 */ | |
1647 execname = SetExecname(argv); | |
1648 if (execname == NULL) { | |
1649 fprintf(stderr, "Unable to resolve current executable\n"); | |
1650 exit(1); | |
1651 } | |
1652 | |
1653 /* | |
1654 * If the path to the selected JRE directory is a match to the initial | |
1655 * portion of the path to the currently executing JRE, we have a winner! | |
1656 * If so, just return. | |
1657 */ | |
1658 if (strncmp(wanted, execname, strlen(wanted)) == 0) | |
1659 return; /* I am the droid you were looking for */ | |
1660 | |
1661 /* | |
1662 * If this isn't the selected version, exec the selected version. | |
1663 */ | |
1664 #ifdef JAVA_ARGS /* javac, jar and friends. */ | |
1665 progname = "java"; | |
1666 #else /* java, oldjava, javaw and friends */ | |
1667 #ifdef PROGNAME | |
1668 progname = PROGNAME; | |
1669 #else | |
1670 progname = *argv; | |
1671 if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { | |
1672 progname = s + 1; | |
1673 } | |
1674 #endif /* PROGNAME */ | |
1675 #endif /* JAVA_ARGS */ | |
1676 | |
1677 /* | |
1678 * This should never happen (because of the selection code in SelectJRE), | |
1679 * but check for "impossibly" long path names just because buffer overruns | |
1680 * can be so deadly. | |
1681 */ | |
1682 if (strlen(wanted) + strlen(progname) + 6 > PATH_MAX) { | |
1683 fprintf(stderr, "Path length exceeds maximum length (PATH_MAX)\n"); | |
1684 exit(1); | |
1685 } | |
1686 | |
1687 /* | |
1688 * Construct the path and exec it. | |
1689 */ | |
1690 (void)strcat(strcat(wanted, "/bin/"), progname); | |
1691 argv[0] = progname; | |
1692 if (_launcher_debug) { | |
1693 int i; | |
1694 printf("ReExec Command: %s (%s)\n", wanted, argv[0]); | |
1695 printf("ReExec Args:"); | |
1696 for (i = 1; argv[i] != NULL; i++) | |
1697 printf(" %s", argv[i]); | |
1698 printf("\n"); | |
1699 } | |
1700 (void)fflush(stdout); | |
1701 (void)fflush(stderr); | |
1702 execv(wanted, argv); | |
1703 perror("execv()"); | |
1704 fprintf(stderr, "Exec of %s failed\n", wanted); | |
1705 exit(1); | |
1706 } | |
1707 #endif /* ifndef GAMMA */ | |
1708 | |
1709 /* | |
1710 * "Borrowed" from Solaris 10 where the unsetenv() function is being added | |
1711 * to libc thanks to SUSv3 (Standard Unix Specification, version 3). As | |
1712 * such, in the fullness of time this will appear in libc on all relevant | |
1713 * Solaris/Linux platforms and maybe even the Windows platform. At that | |
1714 * time, this stub can be removed. | |
1715 * | |
1716 * This implementation removes the environment locking for multithreaded | |
1717 * applications. (We don't have access to these mutexes within libc and | |
1718 * the launcher isn't multithreaded.) Note that what remains is platform | |
1719 * independent, because it only relies on attributes that a POSIX environment | |
1720 * defines. | |
1721 * | |
1722 * Returns 0 on success, -1 on failure. | |
1723 * | |
1724 * Also removed was the setting of errno. The only value of errno set | |
1725 * was EINVAL ("Invalid Argument"). | |
1726 */ | |
1727 | |
1728 /* | |
1729 * s1(environ) is name=value | |
1730 * s2(name) is name(not the form of name=value). | |
1731 * if names match, return value of 1, else return 0 | |
1732 */ | |
1733 static int | |
1734 match_noeq(const char *s1, const char *s2) | |
1735 { | |
1736 while (*s1 == *s2++) { | |
1737 if (*s1++ == '=') | |
1738 return (1); | |
1739 } | |
1740 if (*s1 == '=' && s2[-1] == '\0') | |
1741 return (1); | |
1742 return (0); | |
1743 } | |
1744 | |
1745 /* | |
1746 * added for SUSv3 standard | |
1747 * | |
1748 * Delete entry from environ. | |
1749 * Do not free() memory! Other threads may be using it. | |
1750 * Keep it around forever. | |
1751 */ | |
1752 static int | |
1753 borrowed_unsetenv(const char *name) | |
1754 { | |
1755 long idx; /* index into environ */ | |
1756 | |
1757 if (name == NULL || *name == '\0' || | |
1758 strchr(name, '=') != NULL) { | |
1759 return (-1); | |
1760 } | |
1761 | |
1762 for (idx = 0; environ[idx] != NULL; idx++) { | |
1763 if (match_noeq(environ[idx], name)) | |
1764 break; | |
1765 } | |
1766 if (environ[idx] == NULL) { | |
1767 /* name not found but still a success */ | |
1768 return (0); | |
1769 } | |
1770 /* squeeze up one entry */ | |
1771 do { | |
1772 environ[idx] = environ[idx+1]; | |
1773 } while (environ[++idx] != NULL); | |
1774 | |
1775 return (0); | |
1776 } | |
1777 /* --- End of "borrowed" code --- */ | |
1778 | |
1779 /* | |
1780 * Wrapper for unsetenv() function. | |
1781 */ | |
1782 int | |
1783 UnsetEnv(char *name) | |
1784 { | |
1785 return(borrowed_unsetenv(name)); | |
1786 } | |
1787 | |
1788 /* --- Splash Screen shared library support --- */ | |
1789 | |
1790 static const char* SPLASHSCREEN_SO = "libsplashscreen.so"; | |
1791 | |
1792 static void* hSplashLib = NULL; | |
1793 | |
1794 void* SplashProcAddress(const char* name) { | |
1795 if (!hSplashLib) { | |
1796 hSplashLib = dlopen(SPLASHSCREEN_SO, RTLD_LAZY | RTLD_GLOBAL); | |
1797 } | |
1798 if (hSplashLib) { | |
1799 void* sym = dlsym(hSplashLib, name); | |
1800 return sym; | |
1801 } else { | |
1802 return NULL; | |
1803 } | |
1804 } | |
1805 | |
1806 void SplashFreeLibrary() { | |
1807 if (hSplashLib) { | |
1808 dlclose(hSplashLib); | |
1809 hSplashLib = NULL; | |
1810 } | |
1811 } | |
1812 | |
1813 const char * | |
1814 jlong_format_specifier() { | |
1815 return "%lld"; | |
1816 } | |
1817 | |
1818 /* | |
1819 * Block current thread and continue execution in a new thread | |
1820 */ | |
1821 int | |
1822 ContinueInNewThread(int (JNICALL *continuation)(void *), jlong stack_size, void * args) { | |
1823 int rslt; | |
1824 #ifdef __linux__ | |
1825 pthread_t tid; | |
1826 pthread_attr_t attr; | |
1827 pthread_attr_init(&attr); | |
1828 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); | |
1829 | |
1830 if (stack_size > 0) { | |
1831 pthread_attr_setstacksize(&attr, stack_size); | |
1832 } | |
1833 | |
1834 if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) { | |
1835 void * tmp; | |
1836 pthread_join(tid, &tmp); | |
2027
aa6e219afbf1
7006354: Updates to Visual Studio project creation and development launcher
sla
parents:
1985
diff
changeset
|
1837 rslt = (int)(intptr_t)tmp; |
1985 | 1838 } else { |
1839 /* | |
1840 * Continue execution in current thread if for some reason (e.g. out of | |
1841 * memory/LWP) a new thread can't be created. This will likely fail | |
1842 * later in continuation as JNI_CreateJavaVM needs to create quite a | |
1843 * few new threads, anyway, just give it a try.. | |
1844 */ | |
1845 rslt = continuation(args); | |
1846 } | |
1847 | |
1848 pthread_attr_destroy(&attr); | |
1849 #else | |
1850 thread_t tid; | |
1851 long flags = 0; | |
1852 if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) { | |
1853 void * tmp; | |
1854 thr_join(tid, NULL, &tmp); | |
2027
aa6e219afbf1
7006354: Updates to Visual Studio project creation and development launcher
sla
parents:
1985
diff
changeset
|
1855 rslt = (int)(intptr_t)tmp; |
1985 | 1856 } else { |
1857 /* See above. Continue in current thread if thr_create() failed */ | |
1858 rslt = continuation(args); | |
1859 } | |
1860 #endif | |
1861 return rslt; | |
1862 } | |
1863 | |
1864 /* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */ | |
1865 #define MAX_PID_STR_SZ 20 | |
1866 | |
1867 void SetJavaLauncherPlatformProps() { | |
1868 /* Linux only */ | |
1869 #ifdef __linux__ | |
1870 const char *substr = "-Dsun.java.launcher.pid="; | |
1871 char *pid_prop_str = (char *)JLI_MemAlloc(strlen(substr) + MAX_PID_STR_SZ + 1); | |
1872 sprintf(pid_prop_str, "%s%d", substr, getpid()); | |
1873 AddOption(pid_prop_str, NULL); | |
1874 #endif | |
1875 } |