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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [java/] [lang/] [natPosixProcess.cc] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
// natPosixProcess.cc - Native side of POSIX process code.
2
 
3
/* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006  Free Software Foundation
4
 
5
   This file is part of libgcj.
6
 
7
This software is copyrighted work licensed under the terms of the
8
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9
details.  */
10
 
11
#include <config.h>
12
 
13
#ifdef HAVE_UNISTD_H
14
#include <unistd.h>
15
#endif
16
#include <errno.h>
17
#include <fcntl.h>
18
#include <sys/types.h>
19
#include <sys/wait.h>
20
#include <signal.h>
21
#include <string.h>
22
#include <stdlib.h>
23
#include <stdio.h>
24
#include <unistd.h>
25
#include <pthread.h>
26
 
27
#include <gcj/cni.h>
28
#include <jvm.h>
29
 
30
#include <java/lang/ConcreteProcess$ProcessManager.h>
31
#include <java/lang/ConcreteProcess.h>
32
#include <java/lang/IllegalThreadStateException.h>
33
#include <java/lang/InternalError.h>
34
#include <java/lang/InterruptedException.h>
35
#include <java/lang/NullPointerException.h>
36
#include <java/lang/Thread.h>
37
#include <java/io/File.h>
38
#include <java/io/FileDescriptor.h>
39
#include <gnu/java/nio/channels/FileChannelImpl.h>
40
#include <java/io/FileInputStream.h>
41
#include <java/io/FileOutputStream.h>
42
#include <java/io/IOException.h>
43
#include <java/lang/OutOfMemoryError.h>
44
 
45
using gnu::java::nio::channels::FileChannelImpl;
46
 
47
extern char **environ;
48
 
49
static char *
50
new_string (jstring string)
51
{
52
  jsize s = _Jv_GetStringUTFLength (string);
53
  char *buf = (char *) _Jv_Malloc (s + 1);
54
  _Jv_GetStringUTFRegion (string, 0, string->length(), buf);
55
  buf[s] = '\0';
56
  return buf;
57
}
58
 
59
static void
60
cleanup (char **args, char **env, char *path)
61
{
62
  if (args != NULL)
63
    {
64
      for (int i = 0; args[i] != NULL; ++i)
65
        _Jv_Free (args[i]);
66
      _Jv_Free (args);
67
    }
68
  if (env != NULL)
69
    {
70
      for (int i = 0; env[i] != NULL; ++i)
71
        _Jv_Free (env[i]);
72
      _Jv_Free (env);
73
    }
74
  if (path != NULL)
75
    _Jv_Free (path);
76
}
77
 
78
// This makes our error handling a bit simpler and it lets us avoid
79
// thread bugs where we close a possibly-reopened file descriptor for
80
// a second time.
81
static void
82
myclose (int &fd)
83
{
84
  if (fd != -1)
85
    close (fd);
86
  fd = -1;
87
}
88
 
89
// There has to be a signal handler in order to be able to
90
// sigwait() on SIGCHLD.  The information passed is ignored as it
91
// will be recovered by the waitpid() call.
92
static void
93
sigchld_handler (int)
94
{
95
  // Ignore.
96
}
97
 
98
 
99
// Get ready to enter the main reaper thread loop.
100
void
101
java::lang::ConcreteProcess$ProcessManager::init ()
102
{
103
  using namespace java::lang;
104
  // Remenber our PID so other threads can kill us.
105
  reaperPID = (jlong) pthread_self ();
106
 
107
  // SIGCHLD is blocked in all threads in posix-threads.cc.
108
  // Setup the SIGCHLD handler.
109
  struct sigaction sa;
110
  memset (&sa, 0, sizeof (sa));
111
 
112
  sa.sa_handler = sigchld_handler;
113
  // We only want signals when the things exit.
114
  sa.sa_flags = SA_NOCLDSTOP;
115
 
116
  if (-1 == sigaction (SIGCHLD, &sa, NULL))
117
    goto error;
118
 
119
  // All OK.
120
  return;
121
 
122
error:
123
  throw new InternalError (JvNewStringUTF (strerror (errno)));
124
}
125
 
126
void
127
java::lang::ConcreteProcess$ProcessManager::waitForSignal ()
128
{
129
  // Wait for SIGCHLD
130
  sigset_t mask;
131
  pthread_sigmask (0, NULL, &mask);
132
  sigdelset (&mask, SIGCHLD);
133
 
134
  // Use sigsuspend() instead of sigwait() as sigwait() doesn't play
135
  // nicely with the GC's use of signals.
136
  sigsuspend (&mask);
137
 
138
  // Do not check sigsuspend return value.  The only legitimate return
139
  // is EINTR, but there is a known kernel bug affecting alpha-linux
140
  // wrt sigsuspend+handler+sigreturn that can result in a return value
141
  // of __NR_sigsuspend and errno unset.  Don't fail unnecessarily on
142
  // older kernel versions.
143
 
144
  // All OK.
145
  return;
146
}
147
 
148
jboolean java::lang::ConcreteProcess$ProcessManager::reap ()
149
{
150
  using namespace java::lang;
151
 
152
  pid_t pid;
153
 
154
  for (;;)
155
    {
156
      // Get the return code from a dead child process.
157
      int status;
158
      pid = waitpid ((pid_t) - 1, &status, WNOHANG);
159
      if (pid == -1)
160
        {
161
          if (errno == ECHILD)
162
            return false;
163
          else
164
            goto error;
165
        }
166
 
167
      if (pid == 0)
168
        return true;   // No children to wait for.
169
 
170
      // Look up the process in our pid map.
171
      ConcreteProcess * process = removeProcessFromMap ((jlong) pid);
172
 
173
      // Note that if process==NULL, then we have an unknown child.
174
      // This is not common, but can happen, and isn't an error.
175
      if (process)
176
        {
177
          JvSynchronize sync (process);
178
          process->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1;
179
          process->state = ConcreteProcess::STATE_TERMINATED;
180
          process->processTerminationCleanup();
181
          process->notifyAll ();
182
        }
183
    }
184
 
185
error:
186
  throw new InternalError (JvNewStringUTF (strerror (errno)));
187
}
188
 
189
void
190
java::lang::ConcreteProcess$ProcessManager::signalReaper ()
191
{
192
  int c = pthread_kill ((pthread_t) reaperPID, SIGCHLD);
193
  if (c == 0)
194
    return;
195
  // pthread_kill() failed.
196
  throw new InternalError (JvNewStringUTF (strerror (c)));
197
}
198
 
199
void
200
java::lang::ConcreteProcess::nativeDestroy ()
201
{
202
  int c = kill ((pid_t) pid, SIGKILL);
203
  if (c == 0)
204
    return;
205
  // kill() failed.
206
  throw new InternalError (JvNewStringUTF (strerror (errno)));
207
}
208
 
209
void
210
java::lang::ConcreteProcess::nativeSpawn ()
211
{
212
  using namespace java::io;
213
 
214
  // Initialize all locals here to make cleanup simpler.
215
  char **args = NULL;
216
  char **env = NULL;
217
  char *path = NULL;
218
  int inp[2], outp[2], errp[2], msgp[2];
219
  inp[0] = -1;
220
  inp[1] = -1;
221
  outp[0] = -1;
222
  outp[1] = -1;
223
  errp[0] = -1;
224
  errp[1] = -1;
225
  msgp[0] = -1;
226
  msgp[1] = -1;
227
  errorStream = NULL;
228
  inputStream = NULL;
229
  outputStream = NULL;
230
 
231
  try
232
    {
233
      // Transform arrays to native form.
234
    args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *));
235
 
236
      // Initialize so we can gracefully recover.
237
      jstring *elts = elements (progarray);
238
      for (int i = 0; i <= progarray->length; ++i)
239
        args[i] = NULL;
240
 
241
      for (int i = 0; i < progarray->length; ++i)
242
        args[i] = new_string (elts[i]);
243
      args[progarray->length] = NULL;
244
 
245
      if (envp)
246
        {
247
          env = (char **) _Jv_Malloc ((envp->length + 1) * sizeof (char *));
248
          elts = elements (envp);
249
 
250
          // Initialize so we can gracefully recover.
251
          for (int i = 0; i <= envp->length; ++i)
252
            env[i] = NULL;
253
 
254
          for (int i = 0; i < envp->length; ++i)
255
            env[i] = new_string (elts[i]);
256
          env[envp->length] = NULL;
257
        }
258
 
259
      // We allocate this here because we can't call malloc() after
260
      // the fork.
261
      if (dir != NULL)
262
        path = new_string (dir->getPath ());
263
 
264
      // Create pipes for I/O.  MSGP is for communicating exec()
265
      // status.
266
      if (pipe (inp) || pipe (outp) || pipe (errp) || pipe (msgp)
267
          || fcntl (msgp[1], F_SETFD, FD_CLOEXEC))
268
      throw new IOException (JvNewStringUTF (strerror (errno)));
269
 
270
      // We create the streams before forking.  Otherwise if we had an
271
      // error while creating the streams we would have run the child
272
      // with no way to communicate with it.
273
    errorStream =
274
      new FileInputStream (new
275
                           FileChannelImpl (errp[0], FileChannelImpl::READ));
276
    inputStream =
277
      new FileInputStream (new
278
                           FileChannelImpl (inp[0], FileChannelImpl::READ));
279
    outputStream =
280
      new FileOutputStream (new FileChannelImpl (outp[1],
281
                                             FileChannelImpl::WRITE));
282
 
283
      // We don't use vfork() because that would cause the local
284
      // environment to be set by the child.
285
 
286
    // Use temporary for fork result to avoid dirtying an extra page.
287
    pid_t pid_tmp;
288
    if ((pid_tmp = fork ()) == -1)
289
      throw new IOException (JvNewStringUTF (strerror (errno)));
290
 
291
    if (pid_tmp == 0)
292
        {
293
          // Child process, so remap descriptors, chdir and exec.
294
          if (envp)
295
            {
296
              // Preserve PATH and LD_LIBRARY_PATH unless specified
297
              // explicitly.
298
              char *path_val = getenv ("PATH");
299
              char *ld_path_val = getenv ("LD_LIBRARY_PATH");
300
              environ = env;
301
              if (path_val && getenv ("PATH") == NULL)
302
                {
303
                char *path_env =
304
                  (char *) _Jv_Malloc (strlen (path_val) + 5 + 1);
305
                  strcpy (path_env, "PATH=");
306
                  strcat (path_env, path_val);
307
                  putenv (path_env);
308
                }
309
              if (ld_path_val && getenv ("LD_LIBRARY_PATH") == NULL)
310
                {
311
                char *ld_path_env =
312
                  (char *) _Jv_Malloc (strlen (ld_path_val) + 16 + 1);
313
                  strcpy (ld_path_env, "LD_LIBRARY_PATH=");
314
                  strcat (ld_path_env, ld_path_val);
315
                  putenv (ld_path_env);
316
                }
317
            }
318
 
319
          // We ignore errors from dup2 because they should never occur.
320
          dup2 (outp[0], 0);
321
          dup2 (inp[1], 1);
322
          dup2 (errp[1], 2);
323
 
324
          // Use close and not myclose -- we're in the child, and we
325
          // aren't worried about the possible race condition.
326
          close (inp[0]);
327
          close (inp[1]);
328
          close (errp[0]);
329
          close (errp[1]);
330
          close (outp[0]);
331
          close (outp[1]);
332
          close (msgp[0]);
333
 
334
          // Change directory.
335
          if (path != NULL)
336
            {
337
              if (chdir (path) != 0)
338
                {
339
                  char c = errno;
340
                  write (msgp[1], &c, 1);
341
                  _exit (127);
342
                }
343
            }
344
 
345
          // Make sure that SIGCHLD is unblocked for the new process.
346
          sigset_t mask;
347
          sigemptyset (&mask);
348
          sigaddset (&mask, SIGCHLD);
349
          sigprocmask (SIG_UNBLOCK, &mask, NULL);
350
 
351
          execvp (args[0], args);
352
 
353
          // Send the parent notification that the exec failed.
354
          char c = errno;
355
          write (msgp[1], &c, 1);
356
          _exit (127);
357
        }
358
 
359
      // Parent.  Close extra file descriptors and mark ours as
360
      // close-on-exec.
361
      pid = (jlong) pid_tmp;
362
 
363
      myclose (outp[0]);
364
      myclose (inp[1]);
365
      myclose (errp[1]);
366
      myclose (msgp[1]);
367
 
368
      char c;
369
      int r = read (msgp[0], &c, 1);
370
      if (r == -1)
371
      throw new IOException (JvNewStringUTF (strerror (errno)));
372
      else if (r != 0)
373
      throw new IOException (JvNewStringUTF (strerror (c)));
374
    }
375
  catch (java::lang::Throwable *thrown)
376
    {
377
      // Do some cleanup we only do on failure.  If a stream object
378
      // has been created, we must close the stream itself (to avoid
379
      // duplicate closes when the stream object is collected).
380
      // Otherwise we simply close the underlying file descriptor.
381
      // We ignore errors here as they are uninteresting.
382
 
383
      try
384
        {
385
          if (inputStream != NULL)
386
            inputStream->close ();
387
          else
388
            myclose (inp[0]);
389
        }
390
      catch (java::lang::Throwable *ignore)
391
        {
392
        }
393
 
394
      try
395
        {
396
          if (outputStream != NULL)
397
            outputStream->close ();
398
          else
399
            myclose (outp[1]);
400
        }
401
      catch (java::lang::Throwable *ignore)
402
        {
403
        }
404
 
405
      try
406
        {
407
          if (errorStream != NULL)
408
            errorStream->close ();
409
          else
410
            myclose (errp[0]);
411
        }
412
      catch (java::lang::Throwable *ignore)
413
        {
414
        }
415
 
416
      // These are potentially duplicate, but it doesn't matter due to
417
      // the use of myclose.
418
      myclose (outp[0]);
419
      myclose (inp[1]);
420
      myclose (errp[1]);
421
      myclose (msgp[1]);
422
 
423
    exception = thrown;
424
    }
425
 
426
  myclose (msgp[0]);
427
  cleanup (args, env, path);
428
 
429
  if (exception == NULL)
430
    {
431
      fcntl (outp[1], F_SETFD, FD_CLOEXEC);
432
      fcntl (inp[0], F_SETFD, FD_CLOEXEC);
433
      fcntl (errp[0], F_SETFD, FD_CLOEXEC);
434
    }
435
}

powered by: WebSVN 2.1.0

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