OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [java/] [lang/] [natPosixProcess.cc] - Blame information for rev 775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 758 jeremybenn
// natPosixProcess.cc - Native side of POSIX process code.
2
 
3
/* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007
4
  Free Software Foundation
5
 
6
   This file is part of libgcj.
7
 
8
This software is copyrighted work licensed under the terms of the
9
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
10
details.  */
11
 
12
#include <config.h>
13
 
14
#ifdef HAVE_UNISTD_H
15
#include <unistd.h>
16
#endif
17
#include <errno.h>
18
#include <fcntl.h>
19
#include <sys/types.h>
20
#include <sys/wait.h>
21
#ifdef HAVE_SYS_TIME_H
22
#include <sys/time.h>
23
#endif
24
#ifdef HAVE_SYS_RESOURCE_H
25
#include <sys/resource.h>
26
#endif
27
#include <signal.h>
28
#include <string.h>
29
#include <stdlib.h>
30
#include <stdio.h>
31
#include <unistd.h>
32
#include <pthread.h>
33
 
34
#include <posix.h>
35
#include <posix-threads.h>
36
#include <jvm.h>
37
 
38
#include <java/lang/PosixProcess$ProcessManager.h>
39
#include <java/lang/PosixProcess.h>
40
#include <java/lang/IllegalThreadStateException.h>
41
#include <java/lang/InternalError.h>
42
#include <java/lang/InterruptedException.h>
43
#include <java/lang/NullPointerException.h>
44
#include <java/lang/Thread.h>
45
#include <java/io/File.h>
46
#include <java/io/FileDescriptor.h>
47
#include <gnu/java/nio/channels/FileChannelImpl.h>
48
#include <java/io/FileInputStream.h>
49
#include <java/io/FileOutputStream.h>
50
#include <java/io/IOException.h>
51
#include <java/lang/OutOfMemoryError.h>
52
#include <java/lang/PosixProcess$EOFInputStream.h>
53
 
54
using gnu::java::nio::channels::FileChannelImpl;
55
using namespace java::lang;
56
 
57
extern char **environ;
58
 
59
static char *
60
new_string (jstring string)
61
{
62
  jsize s = _Jv_GetStringUTFLength (string);
63
  char *buf = (char *) _Jv_Malloc (s + 1);
64
  _Jv_GetStringUTFRegion (string, 0, string->length(), buf);
65
  buf[s] = '\0';
66
  return buf;
67
}
68
 
69
static void
70
cleanup (char **args, char **env, char *path)
71
{
72
  if (args != NULL)
73
    {
74
      for (int i = 0; args[i] != NULL; ++i)
75
        _Jv_Free (args[i]);
76
      _Jv_Free (args);
77
    }
78
  if (env != NULL)
79
    {
80
      for (int i = 0; env[i] != NULL; ++i)
81
        _Jv_Free (env[i]);
82
      _Jv_Free (env);
83
    }
84
  if (path != NULL)
85
    _Jv_Free (path);
86
}
87
 
88
// This makes our error handling a bit simpler and it lets us avoid
89
// thread bugs where we close a possibly-reopened file descriptor for
90
// a second time.
91
static void
92
myclose (int &fd)
93
{
94
  if (fd != -1)
95
    close (fd);
96
  fd = -1;
97
}
98
 
99
namespace
100
{
101
  struct ProcessManagerInternal
102
  {
103
    int pipe_ends[2];
104
    struct sigaction old_sigaction;
105
  };
106
}
107
 
108
 
109
// There has to be a signal handler in order to be able to
110
// sigwait() on SIGCHLD.  The information passed is ignored as it
111
// will be recovered by the waitpid() call.
112
static void
113
#ifdef SA_SIGINFO
114
sigchld_handler (int sig, siginfo_t *si, void *third)
115
#else
116
sigchld_handler (int sig)
117
#endif
118
{
119
  if (PosixProcess$ProcessManager::nativeData != NULL)
120
    {
121
      ProcessManagerInternal *pmi =
122
        (ProcessManagerInternal *)PosixProcess$ProcessManager::nativeData;
123
      char c = 0;
124
      ::write(pmi->pipe_ends[1], &c, 1);
125
      if (pmi->old_sigaction.sa_handler != SIG_DFL
126
          && pmi->old_sigaction.sa_handler != SIG_IGN)
127
        {
128
#ifdef SA_SIGINFO
129
          if ((pmi->old_sigaction.sa_flags & SA_SIGINFO) != 0)
130
            pmi->old_sigaction.sa_sigaction(sig, si, third);
131
          else
132
#endif
133
            (*pmi->old_sigaction.sa_handler)(sig);
134
        }
135
    }
136
}
137
 
138
 
139
// Get ready to enter the main reaper thread loop.
140
void
141
java::lang::PosixProcess$ProcessManager::init ()
142
{
143
  // The nativeData is static to avoid races installing the signal
144
  // handler in the case that it is chained.
145
  if (nativeData == NULL )
146
    {
147
      ProcessManagerInternal *pmi =
148
        (ProcessManagerInternal *)JvAllocBytes(sizeof(ProcessManagerInternal));
149
 
150
      if (0 != ::pipe(pmi->pipe_ends))
151
        goto error;
152
 
153
      // Make writing non-blocking so that the signal handler will
154
      // never block.
155
      int fl = ::fcntl(pmi->pipe_ends[1], F_GETFL);
156
      ::fcntl(pmi->pipe_ends[1], F_SETFL, fl | O_NONBLOCK);
157
 
158
      nativeData = (::gnu::gcj::RawDataManaged *)pmi;
159
 
160
      // SIGCHLD is blocked in all threads in posix-threads.cc.
161
      // Setup the SIGCHLD handler.
162
      struct sigaction sa;
163
      memset (&sa, 0, sizeof (sa));
164
 
165
#ifdef SA_SIGINFO
166
      sa.sa_sigaction = sigchld_handler;
167
      // We only want signals when the things exit.
168
      sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
169
#else
170
      sa.sa_handler = sigchld_handler;
171
      // We only want signals when the things exit.
172
      sa.sa_flags = SA_NOCLDSTOP;
173
#endif
174
 
175
      if (-1 == sigaction (SIGCHLD, &sa, &pmi->old_sigaction))
176
        goto error;
177
    }
178
  // All OK.
179
  return;
180
 
181
error:
182
  throw new InternalError (JvNewStringUTF (strerror (errno)));
183
}
184
 
185
void
186
java::lang::PosixProcess$ProcessManager::waitForSignal ()
187
{
188
  // Wait for SIGCHLD
189
  _Jv_UnBlockSigchld();
190
  ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData;
191
 
192
  // Try to read multiple (64) notifications in one go.
193
  char c[64];
194
 ::read(pmi->pipe_ends[0], c, sizeof (c));
195
 
196
  _Jv_BlockSigchld();
197
 
198
  return;
199
}
200
 
201
jboolean java::lang::PosixProcess$ProcessManager::reap (PosixProcess *p)
202
{
203
  pid_t rv;
204
 
205
  // Try to get the return code from the child process.
206
  int status;
207
  rv = ::waitpid ((pid_t)p->pid, &status, WNOHANG);
208
  if (rv == -1)
209
    throw new InternalError (JvNewStringUTF (strerror (errno)));
210
 
211
  if (rv == 0)
212
    return false;   // No children to wait for.
213
 
214
  JvSynchronize sync (p);
215
  p->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1;
216
  p->state = PosixProcess::STATE_TERMINATED;
217
  p->processTerminationCleanup();
218
  p->notifyAll ();
219
  return true;
220
}
221
 
222
void
223
java::lang::PosixProcess$ProcessManager::signalReaper ()
224
{
225
  ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData;
226
  char c = 0;
227
  ::write(pmi->pipe_ends[1], &c, 1);
228
  // Ignore errors.  If EPIPE the reaper has already exited.
229
}
230
 
231
void
232
java::lang::PosixProcess::nativeDestroy ()
233
{
234
  int c = ::kill ((pid_t) pid, SIGKILL);
235
  if (c == 0)
236
    return;
237
  // kill() failed.
238
  throw new InternalError (JvNewStringUTF (strerror (errno)));
239
}
240
 
241
void
242
java::lang::PosixProcess::nativeSpawn ()
243
{
244
  using namespace java::io;
245
 
246
  // Initialize all locals here to make cleanup simpler.
247
  char **args = NULL;
248
  char **env = NULL;
249
  char *path = NULL;
250
  int inp[2], outp[2], errp[2], msgp[2];
251
  inp[0] = -1;
252
  inp[1] = -1;
253
  outp[0] = -1;
254
  outp[1] = -1;
255
  errp[0] = -1;
256
  errp[1] = -1;
257
  msgp[0] = -1;
258
  msgp[1] = -1;
259
  errorStream = NULL;
260
  inputStream = NULL;
261
  outputStream = NULL;
262
 
263
  try
264
    {
265
      // Transform arrays to native form.
266
      args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *));
267
 
268
      // Initialize so we can gracefully recover.
269
      jstring *elts = elements (progarray);
270
      for (int i = 0; i <= progarray->length; ++i)
271
        args[i] = NULL;
272
 
273
      for (int i = 0; i < progarray->length; ++i)
274
        args[i] = new_string (elts[i]);
275
      args[progarray->length] = NULL;
276
 
277
      if (envp)
278
        {
279
          bool need_path = true;
280
          bool need_ld_library_path = true;
281
          int i;
282
 
283
          // Preserve PATH and LD_LIBRARY_PATH unless specified
284
          // explicitly.  We need three extra slots.  Potentially PATH
285
          // and LD_LIBRARY_PATH will be added plus the NULL
286
          // termination.
287
          env = (char **) _Jv_Malloc ((envp->length + 3) * sizeof (char *));
288
          elts = elements (envp);
289
 
290
          // Initialize so we can gracefully recover.
291
          for (i = 0; i < envp->length + 3; ++i)
292
            env[i] = NULL;
293
 
294
          for (i = 0; i < envp->length; ++i)
295
            {
296
              env[i] = new_string (elts[i]);
297
              if (!strncmp (env[i], "PATH=", sizeof("PATH=")))
298
                need_path = false;
299
              if (!strncmp (env[i], "LD_LIBRARY_PATH=",
300
                            sizeof("LD_LIBRARY_PATH=")))
301
                need_ld_library_path = false;
302
            }
303
 
304
          if (need_path)
305
            {
306
              char *path_val = getenv ("PATH");
307
              if (path_val)
308
                {
309
                  env[i] = (char *) _Jv_Malloc (strlen (path_val) +
310
                                                sizeof("PATH=") + 1);
311
                  strcpy (env[i], "PATH=");
312
                  strcat (env[i], path_val);
313
                  i++;
314
                }
315
            }
316
          if (need_ld_library_path)
317
            {
318
              char *path_val = getenv ("LD_LIBRARY_PATH");
319
              if (path_val)
320
                {
321
                  env[i] =
322
                    (char *) _Jv_Malloc (strlen (path_val) +
323
                                         sizeof("LD_LIBRARY_PATH=") + 1);
324
                  strcpy (env[i], "LD_LIBRARY_PATH=");
325
                  strcat (env[i], path_val);
326
                  i++;
327
                }
328
            }
329
          env[i] = NULL;
330
        }
331
 
332
      // We allocate this here because we can't call malloc() after
333
      // the fork.
334
      if (dir != NULL)
335
        path = new_string (dir->getPath ());
336
 
337
      // Create pipes for I/O.  MSGP is for communicating exec()
338
      // status.  If redirecting stderr to stdout, we don't need to
339
      // create the ERRP pipe.
340
      if (pipe (inp) || pipe (outp) || pipe (msgp)
341
          || fcntl (msgp[1], F_SETFD, FD_CLOEXEC))
342
        throw new IOException (JvNewStringUTF (strerror (errno)));
343
      if (! redirect && pipe (errp))
344
        throw new IOException (JvNewStringUTF (strerror (errno)));
345
 
346
      // We create the streams before forking.  Otherwise if we had an
347
      // error while creating the streams we would have run the child
348
      // with no way to communicate with it.
349
      if (redirect)
350
        errorStream = PosixProcess$EOFInputStream::instance;
351
      else
352
        errorStream =
353
          new FileInputStream (new
354
                               FileChannelImpl (errp[0],
355
                                                FileChannelImpl::READ));
356
      inputStream =
357
        new FileInputStream (new
358
                             FileChannelImpl (inp[0], FileChannelImpl::READ));
359
      outputStream =
360
        new FileOutputStream (new FileChannelImpl (outp[1],
361
                                                   FileChannelImpl::WRITE));
362
 
363
      // We don't use vfork() because that would cause the local
364
      // environment to be set by the child.
365
 
366
    // Use temporary for fork result to avoid dirtying an extra page.
367
    pid_t pid_tmp;
368
    if ((pid_tmp = fork ()) == -1)
369
      throw new IOException (JvNewStringUTF (strerror (errno)));
370
 
371
    if (pid_tmp == 0)
372
        {
373
          // Child process, so remap descriptors, chdir and exec.
374
          if (envp)
375
            environ = env;
376
 
377
          // We ignore errors from dup2 because they should never occur.
378
          dup2 (outp[0], 0);
379
          dup2 (inp[1], 1);
380
          dup2 (redirect ? inp[1] : errp[1], 2);
381
 
382
          // Use close and not myclose -- we're in the child, and we
383
          // aren't worried about the possible race condition.
384
          close (inp[0]);
385
          close (inp[1]);
386
          if (! redirect)
387
            {
388
              close (errp[0]);
389
              close (errp[1]);
390
            }
391
          close (outp[0]);
392
          close (outp[1]);
393
          close (msgp[0]);
394
 
395
          // Change directory.
396
          if (path != NULL)
397
            {
398
              if (chdir (path) != 0)
399
                {
400
                  char c = errno;
401
                  write (msgp[1], &c, 1);
402
                  _exit (127);
403
                }
404
            }
405
          // Make sure all file descriptors are closed.  In
406
          // multi-threaded programs, there is a race between when a
407
          // descriptor is obtained, when we can set FD_CLOEXEC, and
408
          // fork().  If the fork occurs before FD_CLOEXEC is set, the
409
          // descriptor would leak to the execed process if we did not
410
          // manually close it.  So that is what we do.  Since we
411
          // close all the descriptors, it is redundant to set
412
          // FD_CLOEXEC on them elsewhere.
413
          int max_fd;
414
#ifdef HAVE_GETRLIMIT
415
          rlimit rl;
416
          int rv = getrlimit(RLIMIT_NOFILE, &rl);
417
          if (rv == 0)
418
            max_fd = rl.rlim_max - 1;
419
          else
420
            max_fd = 1024 - 1;
421
#else
422
          max_fd = 1024 - 1;
423
#endif
424
          while(max_fd > 2)
425
            {
426
              if (max_fd != msgp[1])
427
                close (max_fd);
428
              max_fd--;
429
            }
430
          // Make sure that SIGCHLD is unblocked for the new process.
431
          sigset_t mask;
432
          sigemptyset (&mask);
433
          sigaddset (&mask, SIGCHLD);
434
          sigprocmask (SIG_UNBLOCK, &mask, NULL);
435
 
436
          execvp (args[0], args);
437
 
438
          // Send the parent notification that the exec failed.
439
          char c = errno;
440
          write (msgp[1], &c, 1);
441
          _exit (127);
442
        }
443
 
444
      // Parent.  Close extra file descriptors and mark ours as
445
      // close-on-exec.
446
      pid = (jlong) pid_tmp;
447
 
448
      myclose (outp[0]);
449
      myclose (inp[1]);
450
      if (! redirect)
451
        myclose (errp[1]);
452
      myclose (msgp[1]);
453
 
454
      char c;
455
      int r = read (msgp[0], &c, 1);
456
      if (r == -1)
457
        throw new IOException (JvNewStringUTF (strerror (errno)));
458
      else if (r != 0)
459
        throw new IOException (JvNewStringUTF (strerror (c)));
460
    }
461
  catch (java::lang::Throwable *thrown)
462
    {
463
      // Do some cleanup we only do on failure.  If a stream object
464
      // has been created, we must close the stream itself (to avoid
465
      // duplicate closes when the stream object is collected).
466
      // Otherwise we simply close the underlying file descriptor.
467
      // We ignore errors here as they are uninteresting.
468
 
469
      try
470
        {
471
          if (inputStream != NULL)
472
            inputStream->close ();
473
          else
474
            myclose (inp[0]);
475
        }
476
      catch (java::lang::Throwable *ignore)
477
        {
478
        }
479
 
480
      try
481
        {
482
          if (outputStream != NULL)
483
            outputStream->close ();
484
          else
485
            myclose (outp[1]);
486
        }
487
      catch (java::lang::Throwable *ignore)
488
        {
489
        }
490
 
491
      try
492
        {
493
          if (errorStream != NULL)
494
            errorStream->close ();
495
          else if (! redirect)
496
            myclose (errp[0]);
497
        }
498
      catch (java::lang::Throwable *ignore)
499
        {
500
        }
501
 
502
      // These are potentially duplicate, but it doesn't matter due to
503
      // the use of myclose.
504
      myclose (outp[0]);
505
      myclose (inp[1]);
506
      if (! redirect)
507
        myclose (errp[1]);
508
      myclose (msgp[1]);
509
 
510
      exception = thrown;
511
    }
512
 
513
  myclose (msgp[0]);
514
  cleanup (args, env, path);
515
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.