From 8c0dbf3490bd297d601118bc95a2a8640aa73a39 Mon Sep 17 00:00:00 2001 From: David Daney Date: Sat, 12 May 2007 17:37:55 +0000 Subject: [PATCH] re PR libgcj/29324 (add wait handling hook) PR libgcj/29324 * include/posix-threads.h (_Jv_BlockSigchld): Declare. (_Jv_UnBlockSigchld): Same. * posix-threads.cc: Include posix-threads.h. (block_sigchld) Rename to... (_Jv_BlockSigchld) ... this. (_Jv_UnBlockSigchld): New function. (_Jv_InitThreads): Call _Jv_BlockSigchld in place of block_sigchld. (_Jv_ThreadStart): Same. * java/lang/PosixProcess$ProcessManager.h: Regenerate. * java/lang/PosixProcess.java: Clean up imports. (ProcessManager): Make final. (ProcessManager.queue): Genericise and make private. (ProcessManager.pidToProcess): Remove. (ProcessManager.liveProcesses): New field. (ProcessManager.reaperPID): Remove. (ProcessManager.nativeData): New field. (ProcessManager.removeProcessFromMap): Remove. (ProcessManager.addProcessToMap):Remove. (ProcessManager.addToLiveProcesses): New method. (ProcessManager.run): Rewritten. (ProcessManager.reap): Change method signature, (getErrorStream): Correct formatting. (getInputStream): Same. (spawn): Add process to liveProcesses list. (pid): Make package private. * java/lang/PosixProcess.h: Regenerate. * java/lang/natPosixProcess.cc: Include posix.h and posix-threads.h. Add useing namespace java::lang. (ProcessManagerInternal): New struct. (sigchld_handler): Rewritten. (init): Rewritten. (waitForSignal): Same. (reap): Same. (signalReaper): Same. (nativeDestroy): Call kill as ::kill. (nativeSpawn): Correct formatting. * classpath/lib/java/lang/PosixProcess$EOFInputStream.class: Regenerate. * classpath/lib/java/lang/PosixProcess.class: Same. * classpath/lib/java/lang/PosixProcess$ProcessManager.class: Same. From-SVN: r124638 --- libjava/ChangeLog | 43 +++++ .../lang/PosixProcess$EOFInputStream.class | Bin 567 -> 567 bytes .../lang/PosixProcess$ProcessManager.class | Bin 2645 -> 2656 bytes .../lib/java/lang/PosixProcess.class | Bin 4197 -> 4098 bytes libjava/include/posix-threads.h | 8 + .../java/lang/PosixProcess$ProcessManager.h | 32 ++-- libjava/java/lang/PosixProcess.h | 7 +- libjava/java/lang/PosixProcess.java | 149 +++++++++-------- libjava/java/lang/natPosixProcess.cc | 151 ++++++++++-------- libjava/posix-threads.cc | 22 ++- 10 files changed, 244 insertions(+), 168 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 385e26d8cdd..dce155806cf 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,46 @@ +2007-05-12 David Daney + + PR libgcj/29324 + * include/posix-threads.h (_Jv_BlockSigchld): Declare. + (_Jv_UnBlockSigchld): Same. + * posix-threads.cc: Include posix-threads.h. + (block_sigchld) Rename to... + (_Jv_BlockSigchld) ... this. + (_Jv_UnBlockSigchld): New function. + (_Jv_InitThreads): Call _Jv_BlockSigchld in place of block_sigchld. + (_Jv_ThreadStart): Same. + * java/lang/PosixProcess$ProcessManager.h: Regenerate. + * java/lang/PosixProcess.java: Clean up imports. + (ProcessManager): Make final. + (ProcessManager.queue): Genericise and make private. + (ProcessManager.pidToProcess): Remove. + (ProcessManager.liveProcesses): New field. + (ProcessManager.reaperPID): Remove. + (ProcessManager.nativeData): New field. + (ProcessManager.removeProcessFromMap): Remove. + (ProcessManager.addProcessToMap):Remove. + (ProcessManager.addToLiveProcesses): New method. + (ProcessManager.run): Rewritten. + (ProcessManager.reap): Change method signature, + (getErrorStream): Correct formatting. + (getInputStream): Same. + (spawn): Add process to liveProcesses list. + (pid): Make package private. + * java/lang/PosixProcess.h: Regenerate. + * java/lang/natPosixProcess.cc: Include posix.h and posix-threads.h. + Add useing namespace java::lang. + (ProcessManagerInternal): New struct. + (sigchld_handler): Rewritten. + (init): Rewritten. + (waitForSignal): Same. + (reap): Same. + (signalReaper): Same. + (nativeDestroy): Call kill as ::kill. + (nativeSpawn): Correct formatting. + * classpath/lib/java/lang/PosixProcess$EOFInputStream.class: Regenerate. + * classpath/lib/java/lang/PosixProcess.class: Same. + * classpath/lib/java/lang/PosixProcess$ProcessManager.class: Same. + 2007-05-07 Ian Lance Taylor PR java/31842 diff --git a/libjava/classpath/lib/java/lang/PosixProcess$EOFInputStream.class b/libjava/classpath/lib/java/lang/PosixProcess$EOFInputStream.class index a7103f81a1ca094f14da705c8ed6187705c13341..c4cc6c37ccbe1361ccaee911c67eaae572e71d86 100644 GIT binary patch delta 31 mcmdnavYlnaOh(oV3|x%oCeLFu0+JUQEhk@Kl03XLtLEmWXsT1Y7`qN$a4EvBWmrP!$8k}T<#bQ5+rZ39$% zS9D~?8D|t`7#)W(esju5iaMhXeDk9}!B6}IKUtre7WFjPBZQmJ=UrT)U|{}6-+XudY7&uT>|n#FiB zY*s)-1$^|&-D9e)3N%F$MkbVqO@~I+Ik{8-9;c7me%;XR0ReZQYeK+tG!@tC&>-+s zb&fu`u}Q&GXkkvwfUGjm=u$JO&mlGYGO#nj}4YU=X4xahH` zbh6P|0rCmOBL@v?JU*U^RFm0KnPjDXxNAb@)2*NfyT}`j1sW^0Po1CEVs^NTWe{n} zez`TO9Fb(pR!#f(ycT0~7zrQxu+NLVqvFi;*Rd2NgVr zbpnbddn`GsscFshA&eKi=&x$mf{}s&sa|iSZ2dy^a571BbE~CrUYphAQdGg~ctgNDrCP)E>Ku-!gnU-PIlM*RmVTM-$1^in!*Rhs_ajM9T++i0 zPvE5Nl0GC9OhGSKY>z;&vQ;Yk;jyVw?6Zp!AB)i#7+kf|eJ~WHWQ-astd#;g~as^X7jEnAyWFo${O!}2jwp`r9tXoN@G<^k8#nXnI+an*|} z0vpQ}FO^xr0^a5cO&2WG*u`;Ejgg6_Vz!TYbB=SmFilqq$!0D@t}eb)8a6LanM)(c zB0Og#mg4gi`>SU`HoYJVB?pUUoO<~$MIJ6%^}CVIw)96Smqes*v@C06LBw}JJ5ig*oaQFBEUhqpKk}a3PyB%bGMUU zjDoIW+#~ej;)*Z$6Sj2c5j<1&>~nSw5$R#ai@%^*^5Vm8gdESkC4ZNxBl+mKk3Ew^ z59oEX<2AU1XStNe^F0r9sO@?9`yw@K(L($(hpmn*WVD&@^gwAji8y|+b~*z zqoahQqlDwd5}#RmmwB}ZCnFDX@CNfZL@;ePm;cGZbEaE@=$0VdEL{T{ag?%&aKK-y zBP;2Ra`!ALKF1QCrMAj>5GCXb74)_j0SO#mfg%2K`~!EH{|N~t=#dp94J!yFPh2MZ zc?=Ha&=TzV8AAeppl=DI1Fbhv&jnt9d`=47TK>DB`{ph5OLp_%TOYk_f|^IHwA3!{ z<3jhtMW(ta7u|VG)93Im2A?Tv-ClmQ0)zO{x#dix`!1|Jvbp7H-pO^O-cLsSWJbz! zm_?RMwPPN)`JKg8M=s!&BX8pyM>cam$B`lTrCh)rN4lMcHL-=ZGh{Ty2$y&mOl;tL zGxghPu@hI=rV9w-8V=$e^y6I))&<@d?-RkNoT;DD;&WoTL5nZw|4Z)P#C4*$fv@m2 zSHHz~jCcn>;CuXtj8mn3JfN&Zu}Ynce2v~+jNxO1HLTQiYRHy$)6R?c7*F5>+Q{Qm p(EpJC7`o(D22gU&I+9n8BYEdi+l7yu=g0VjQr=2}mq7!X{sZx~U-19{ literal 2645 zcmaJ@ZBr9h6n<_J2!!k!PfBg-> z9^CcABd~2;omAUXYI?N2H)HBky+$UXnP!V)yVbNhsu_Ox1lAT^<70-VCIw0^<+Pl} zS26ot&eBuuG2OHx0!mg-#xqVBfi*6VZZ%7X5*Z>dAch3Wxz1`vZ}bHJ?h+_HtfzJB zsDL*Z>KE{JWRhALDg{=rlCa)wLoof3Bt~$&ocD%Xk;kV??r;ex&btxUV1et@S{wwHY+GcAi&jD1ufXdBuvdZ zp=uMEG#Lj8Ewk3s+L_$Mux7;7;S`msie(aNs$Vs9`M0y_v&M8&V23M#|0xEwt2PKT zsX1bF8kq@_6le%`gS+PS1e&HlO7GA4ee5a-I8%vsJ{YxvCof}1XdL_U}y#V zae!r6f)&{A*1BhSTuWFHH?p(k$063Gi0Mv>g(l-QYBK3$5zja|yeNZEe*gz@M8Q$K zDo~~->_#Q^1~(fwMkLfFGdiZ=I6Bx&*_J)}*I1Zti`J2WKw@2rAzSj`(} z>Z55jb4Do}5Z(Sxc8q?=^C1N$6b#s(n;mV!4q}kOZ6GC$G7EsfT3J zqYB2LbKBIf@Gb9pw1lIHKiyDfbG5-Fmo-@yzIo$gVyOQ?@Xx zUlWWzrvwsXQo&`3QDSD*%XS`l1y^JqtE2>-8KckEw;We--H&T4leRw$DV9 zGiL3WI;nMM46S2KPbCeFh45%o1$=uP763Rq0)3gBk zdetq5ZGD8pjNH0_*Sr`gG7s2pG1Q{l6}+wxypF+7*x)A%!LRa+OL3x$g18B3T{;bk*a*$_U|69#-X*>;Ic zBTFY6z=v_JE~0|A1{0KJ1dT9UMQm~i3DR^LN967Jz+LA5j-(Ry$sVB$%M7Ga+@8nq zk&O>(7{;!;P86d+hEqtYZq`Q*YaSta2}PZbA>HxZjID+s2Wz?G&en++WZ4H~A~y zOB?5ukakI|Av;!{Voej_8gI~bR&bi9ZZq;7{%i3Od;cDe;B!Rr1u?&5q_1!m_ZjJ1 z4C6bD;%k`npT_r$`vY#_M|^@Cw$New=H7LLZXuUD%*DfVC3X*Z>Fp=R#}L9J=Qcpg exo2CBZQJq-hM9O6RepYo&uHaj7aW|GDEkj63`~ar diff --git a/libjava/classpath/lib/java/lang/PosixProcess.class b/libjava/classpath/lib/java/lang/PosixProcess.class index 0227add131e85b5fccde4022088939d131d1aafb..0241ae74f9eeb271438dda06633a028746098277 100644 GIT binary patch delta 516 zcmXw$Pe{{Y7{@=~rQ7_u<=W=5)U}ma{=u|7bjXbA5aGaJ5!J;pC+Q$-i|CIeSRF;` zJyejlAnH)r>f#{?0wY6$sGv^LABaxf!+Hw3ywCG~KHr!3f#+*#D&@UenSTcK@MO+g zu8u`>!^7F}fzh*t!P0oXP%anB?suTM(%}EDRq?HD?z!SM!Cd~YYUy#=;8o#11}C-J z9jocCUc{r(&D2b#m+-(ruzvcGWfBly0qfvWZdw67B#>^l=WeMvrQ5_+n z3`rfW+zap1ZaV68@N*fG*7vPCE9(kXgXVzbOU5QN&1KCnt!vEcI(Ox`uN%zkCNFf01$%vp_EcOLQB_AzX=LhujaGiz}G delta 581 zcmYk3&r6eW9LL}9CpVwx*|Q#-PK~KeHnshrwi+Rn9c)p|1|@aq2i4f@pww(DYEX!Z zNCz)|qdKSuFM*)7WL5W0MRykDPR@EP&1`OS|TOK$$M zf`#9x$2wZ@M~#_NVG<^Hz(oU1bRj?s5!#5-i!L@G$wr)_4{7dEJ+6#5fNBO|u^qMS zKr=&VV?-?ri3y1dIVdC{Xy6SwHjh>gqJu^3<835(2S<5V4lW_Z z`#2-|MGoUCN0H??`uP9@5*I|f$4QLxAtv|;(|nAle1bVnVTsdt#~HlmEMoG!lc*N^ z0Y}tfI~{Fthread; } +// +// Signal helpers. +// + +void _Jv_BlockSigchld(); +void _Jv_UnBlockSigchld(); + + // // Condition variables. // diff --git a/libjava/java/lang/PosixProcess$ProcessManager.h b/libjava/java/lang/PosixProcess$ProcessManager.h index d8d0d594232..4b3b62e13dd 100644 --- a/libjava/java/lang/PosixProcess$ProcessManager.h +++ b/libjava/java/lang/PosixProcess$ProcessManager.h @@ -7,31 +7,37 @@ #pragma interface #include +extern "Java" +{ + namespace gnu + { + namespace gcj + { + class RawDataManaged; + } + } +} class java::lang::PosixProcess$ProcessManager : public ::java::lang::Thread { public: // actually package-private PosixProcess$ProcessManager(); -private: - ::java::lang::PosixProcess * removeProcessFromMap(jlong); -public: // actually package-private - virtual void addProcessToMap(::java::lang::PosixProcess *); - virtual void startExecuting(::java::lang::PosixProcess *); - virtual void waitUntilReady(); + void addToLiveProcesses(::java::lang::PosixProcess *); + void startExecuting(::java::lang::PosixProcess *); + void waitUntilReady(); public: - virtual void run(); + void run(); private: void init(); void waitForSignal(); - jboolean reap(); + jboolean reap(::java::lang::PosixProcess *); void signalReaper(); -public: // actually package-private - ::java::util::List * __attribute__((aligned(__alignof__( ::java::lang::Thread)))) queue; -private: - ::java::util::Map * pidToProcess; + ::java::util::LinkedList * __attribute__((aligned(__alignof__( ::java::lang::Thread)))) queue; + ::java::util::LinkedList * liveProcesses; jboolean ready; - jlong reaperPID; +public: // actually package-private + static ::gnu::gcj::RawDataManaged * nativeData; public: static ::java::lang::Class class$; }; diff --git a/libjava/java/lang/PosixProcess.h b/libjava/java/lang/PosixProcess.h index a43fa0739d5..3254f5224ce 100644 --- a/libjava/java/lang/PosixProcess.h +++ b/libjava/java/lang/PosixProcess.h @@ -32,17 +32,16 @@ private: void nativeSpawn(); public: // actually package-private PosixProcess(JArray< ::java::lang::String * > *, JArray< ::java::lang::String * > *, ::java::io::File *, jboolean); - static jlong access$0(::java::lang::PosixProcess *); - static ::java::lang::Object * access$1(); - static void access$2(::java::lang::PosixProcess$ProcessManager *); + static ::java::lang::Object * access$0(); + static void access$1(::java::lang::PosixProcess$ProcessManager *); private: JArray< ::java::lang::String * > * __attribute__((aligned(__alignof__( ::java::lang::Process)))) progarray; JArray< ::java::lang::String * > * envp; ::java::io::File * dir; jboolean redirect; ::java::lang::Throwable * exception; - jlong pid; public: // actually package-private + jlong pid; static const jint STATE_WAITING_TO_START = 0; static const jint STATE_RUNNING = 1; static const jint STATE_TERMINATED = 2; diff --git a/libjava/java/lang/PosixProcess.java b/libjava/java/lang/PosixProcess.java index 6b1496426dd..dd59e7b93a1 100644 --- a/libjava/java/lang/PosixProcess.java +++ b/libjava/java/lang/PosixProcess.java @@ -13,11 +13,10 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import gnu.gcj.RawDataManaged; /** * @author Tom Tromey @@ -27,7 +26,7 @@ import java.util.Map; */ final class PosixProcess extends Process { - static class ProcessManager extends Thread + static final class ProcessManager extends Thread { /** * A list of {@link PosixProcess PosixProcesses} to be @@ -35,10 +34,12 @@ final class PosixProcess extends Process * for all process related operations. To avoid dead lock * ensure queueLock is obtained before PosixProcess. */ - List queue = new LinkedList(); - private Map pidToProcess = new HashMap(); + private LinkedList queue = new LinkedList(); + private LinkedList liveProcesses = + new LinkedList(); private boolean ready = false; - private long reaperPID; + + static RawDataManaged nativeData; ProcessManager() { @@ -53,27 +54,14 @@ final class PosixProcess extends Process } /** - * Get the PosixProcess object with the given pid and - * remove it from the map. This method is called from the - * native code for {@link #reap()). The mapping is removed so - * the PosixProcesses can be GCed after they terminate. - * - * @param p The pid of the process. - */ - private PosixProcess removeProcessFromMap(long p) - { - return (PosixProcess) pidToProcess.remove(new Long(p)); - } - - /** - * Put the given PosixProcess in the map using the Long - * value of its pid as the key. + * Add a process to the list of running processes. This must only + * be called with the queueLock held. * * @param p The PosixProcess. */ - void addProcessToMap(PosixProcess p) + void addToLiveProcesses(PosixProcess p) { - pidToProcess.put(new Long(p.pid), p); + liveProcesses.add(p); } /** @@ -122,61 +110,66 @@ final class PosixProcess extends Process // Now ready to accept requests. synchronized (this) { - ready = true; - this.notifyAll(); + ready = true; + this.notifyAll(); } for (;;) { - try - { - synchronized (queueLock) - { - boolean haveMoreChildren = reap(); - if (! haveMoreChildren && queue.size() == 0) - { - // This reaper thread could exit, but we - // keep it alive for a while in case - // someone wants to start more Processes. - try - { - queueLock.wait(1000L); - if (queue.size() == 0) - { - processManager = null; - return; // Timed out. - } - } - catch (InterruptedException ie) - { - // Ignore and exit the thread. - return; - } - } - while (queue.size() > 0) - { - PosixProcess p = (PosixProcess) queue.remove(0); - p.spawn(this); - } - } + try + { + synchronized (queueLock) + { + Iterator processIterator = + liveProcesses.iterator(); + while (processIterator.hasNext()) + { + boolean reaped = reap(processIterator.next()); + if (reaped) + processIterator.remove(); + } + if (liveProcesses.size() == 0 && queue.size() == 0) + { + // This reaper thread could exit, but we keep it + // alive for a while in case someone wants to + // start more Processes. + try + { + queueLock.wait(1000L); + if (queue.size() == 0) + { + processManager = null; + return; // Timed out. + } + } + catch (InterruptedException ie) + { + // Ignore and exit the thread. + return; + } + } + while (queue.size() > 0) + { + PosixProcess p = queue.remove(0); + p.spawn(this); + } + } - // Wait for a SIGCHLD from either an exiting - // process or the startExecuting() method. This - // is done outside of the synchronized block to - // allow other threads to enter and submit more - // jobs. - waitForSignal(); - } - catch (Exception ex) - { - ex.printStackTrace(System.err); - } + // Wait for a SIGCHLD from either an exiting process or + // the startExecuting() method. This is done outside of + // the synchronized block to allow other threads to + // enter and submit more jobs. + waitForSignal(); + } + catch (Exception ex) + { + ex.printStackTrace(System.err); + } } } /** * Setup native signal handlers and other housekeeping things. - * */ private native void init(); @@ -187,12 +180,14 @@ final class PosixProcess extends Process private native void waitForSignal(); /** - * Try to reap as many children as possible without blocking. + * Try to reap the specified child without blocking. * - * @return true if more live children exist. + * @param p the process to try to reap. + * + * @return true if the process terminated. * */ - private native boolean reap(); + private native boolean reap(PosixProcess p); /** * Send SIGCHLD to the reaper thread. @@ -295,7 +290,7 @@ final class PosixProcess extends Process returnedErrorStream = EOFInputStream.instance; else returnedErrorStream = errorStream; - + return returnedErrorStream; } @@ -308,7 +303,7 @@ final class PosixProcess extends Process returnedInputStream = EOFInputStream.instance; else returnedInputStream = inputStream; - + return returnedInputStream; } @@ -329,7 +324,7 @@ final class PosixProcess extends Process /** * Start this process running. This should only be called by the - * ProcessManager. + * ProcessManager with the queueLock held. * * @param pm The ProcessManager that made the call. */ @@ -342,7 +337,7 @@ final class PosixProcess extends Process // There is no race with reap() in the pidToProcess map // because this is always called from the same thread // doing the reaping. - pm.addProcessToMap(this); + pm.addToLiveProcesses(this); state = STATE_RUNNING; // Notify anybody waiting on state change. this.notifyAll(); @@ -426,7 +421,7 @@ final class PosixProcess extends Process private Throwable exception; /** The process id. This is cast to a pid_t on the native side. */ - private long pid; + long pid; // FIXME: Why doesn't the friend declaration in PosixProcess.h // allow PosixProcess$ProcessManager native code access these diff --git a/libjava/java/lang/natPosixProcess.cc b/libjava/java/lang/natPosixProcess.cc index 252da6e80ab..c7b8b6e5eb0 100644 --- a/libjava/java/lang/natPosixProcess.cc +++ b/libjava/java/lang/natPosixProcess.cc @@ -30,6 +30,8 @@ details. */ #include #include +#include +#include #include #include @@ -48,6 +50,7 @@ details. */ #include using gnu::java::nio::channels::FileChannelImpl; +using namespace java::lang; extern char **environ; @@ -91,13 +94,37 @@ myclose (int &fd) fd = -1; } +namespace +{ + struct ProcessManagerInternal + { + int pipe_ends[2]; + struct sigaction old_sigaction; + }; +} + + // There has to be a signal handler in order to be able to // sigwait() on SIGCHLD. The information passed is ignored as it // will be recovered by the waitpid() call. static void -sigchld_handler (int) +sigchld_handler (int sig, siginfo_t *si, void *third) { - // Ignore. + if (PosixProcess$ProcessManager::nativeData != NULL) + { + ProcessManagerInternal *pmi = + (ProcessManagerInternal *)PosixProcess$ProcessManager::nativeData; + char c = 0; + ::write(pmi->pipe_ends[1], &c, 1); + if (pmi->old_sigaction.sa_handler != SIG_DFL + && pmi->old_sigaction.sa_handler != SIG_IGN) + { + if ((pmi->old_sigaction.sa_flags & SA_SIGINFO) != 0) + pmi->old_sigaction.sa_sigaction(sig, si, third); + else + (*pmi->old_sigaction.sa_handler)(sig); + } + } } @@ -105,22 +132,35 @@ sigchld_handler (int) void java::lang::PosixProcess$ProcessManager::init () { - using namespace java::lang; - // Remenber our PID so other threads can kill us. - reaperPID = (jlong) pthread_self (); + // The nativeData is static to avoid races installing the signal + // handler in the case that it is chained. + if (nativeData == NULL ) + { + ProcessManagerInternal *pmi = + (ProcessManagerInternal *)JvAllocBytes(sizeof(ProcessManagerInternal)); - // SIGCHLD is blocked in all threads in posix-threads.cc. - // Setup the SIGCHLD handler. - struct sigaction sa; - memset (&sa, 0, sizeof (sa)); + if (0 != ::pipe(pmi->pipe_ends)) + goto error; - sa.sa_handler = sigchld_handler; - // We only want signals when the things exit. - sa.sa_flags = SA_NOCLDSTOP; + // Make writing non-blocking so that the signal handler will + // never block. + int fl = ::fcntl(pmi->pipe_ends[1], F_GETFL); + ::fcntl(pmi->pipe_ends[1], F_SETFL, fl | O_NONBLOCK); - if (-1 == sigaction (SIGCHLD, &sa, NULL)) - goto error; + nativeData = (::gnu::gcj::RawDataManaged *)pmi; + // SIGCHLD is blocked in all threads in posix-threads.cc. + // Setup the SIGCHLD handler. + struct sigaction sa; + memset (&sa, 0, sizeof (sa)); + + sa.sa_sigaction = sigchld_handler; + // We only want signals when the things exit. + sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; + + if (-1 == sigaction (SIGCHLD, &sa, &pmi->old_sigaction)) + goto error; + } // All OK. return; @@ -132,79 +172,52 @@ void java::lang::PosixProcess$ProcessManager::waitForSignal () { // Wait for SIGCHLD - sigset_t mask; - pthread_sigmask (0, NULL, &mask); - sigdelset (&mask, SIGCHLD); + _Jv_UnBlockSigchld(); + ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData; - // Use sigsuspend() instead of sigwait() as sigwait() doesn't play - // nicely with the GC's use of signals. - sigsuspend (&mask); + // Try to read multiple (64) notifications in one go. + char c[64]; + ::read(pmi->pipe_ends[0], c, sizeof (c)); - // Do not check sigsuspend return value. The only legitimate return - // is EINTR, but there is a known kernel bug affecting alpha-linux - // wrt sigsuspend+handler+sigreturn that can result in a return value - // of __NR_sigsuspend and errno unset. Don't fail unnecessarily on - // older kernel versions. + _Jv_BlockSigchld(); - // All OK. return; } -jboolean java::lang::PosixProcess$ProcessManager::reap () +jboolean java::lang::PosixProcess$ProcessManager::reap (PosixProcess *p) { - using namespace java::lang; + pid_t rv; - pid_t pid; + // Try to get the return code from the child process. + int status; + rv = ::waitpid ((pid_t)p->pid, &status, WNOHANG); + if (rv == -1) + throw new InternalError (JvNewStringUTF (strerror (errno))); - for (;;) - { - // Get the return code from a dead child process. - int status; - pid = waitpid ((pid_t) - 1, &status, WNOHANG); - if (pid == -1) - { - if (errno == ECHILD) - return false; - else - goto error; - } + if (rv == 0) + return false; // No children to wait for. - if (pid == 0) - return true; // No children to wait for. - - // Look up the process in our pid map. - PosixProcess * process = removeProcessFromMap ((jlong) pid); - - // Note that if process==NULL, then we have an unknown child. - // This is not common, but can happen, and isn't an error. - if (process) - { - JvSynchronize sync (process); - process->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1; - process->state = PosixProcess::STATE_TERMINATED; - process->processTerminationCleanup(); - process->notifyAll (); - } - } - -error: - throw new InternalError (JvNewStringUTF (strerror (errno))); + JvSynchronize sync (p); + p->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1; + p->state = PosixProcess::STATE_TERMINATED; + p->processTerminationCleanup(); + p->notifyAll (); + return true; } void java::lang::PosixProcess$ProcessManager::signalReaper () { - int c = pthread_kill ((pthread_t) reaperPID, SIGCHLD); - if (c == 0) - return; - // pthread_kill() failed. - throw new InternalError (JvNewStringUTF (strerror (c))); + ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData; + char c = 0; + ::write(pmi->pipe_ends[1], &c, 1); + // Ignore errors. If EPIPE the reaper has already exited. } void java::lang::PosixProcess::nativeDestroy () { - int c = kill ((pid_t) pid, SIGKILL); + int c = ::kill ((pid_t) pid, SIGKILL); if (c == 0) return; // kill() failed. @@ -427,9 +440,9 @@ java::lang::PosixProcess::nativeSpawn () char c; int r = read (msgp[0], &c, 1); if (r == -1) - throw new IOException (JvNewStringUTF (strerror (errno))); + throw new IOException (JvNewStringUTF (strerror (errno))); else if (r != 0) - throw new IOException (JvNewStringUTF (strerror (c))); + throw new IOException (JvNewStringUTF (strerror (c))); } catch (java::lang::Throwable *thrown) { diff --git a/libjava/posix-threads.cc b/libjava/posix-threads.cc index 6ea724b3be8..287d6b79a6f 100644 --- a/libjava/posix-threads.cc +++ b/libjava/posix-threads.cc @@ -14,6 +14,7 @@ details. */ #include #include "posix.h" +#include "posix-threads.h" // If we're using the Boehm GC, then we need to override some of the // thread primitives. This is fairly gross. @@ -472,8 +473,8 @@ handle_intr (int) // Do nothing. } -static void -block_sigchld() +void +_Jv_BlockSigchld() { sigset_t mask; sigemptyset (&mask); @@ -483,6 +484,17 @@ block_sigchld() JvFail (strerror (c)); } +void +_Jv_UnBlockSigchld() +{ + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + int c = pthread_sigmask (SIG_UNBLOCK, &mask, NULL); + if (c != 0) + JvFail (strerror (c)); +} + void _Jv_InitThreads (void) { @@ -501,7 +513,7 @@ _Jv_InitThreads (void) // Block SIGCHLD here to ensure that any non-Java threads inherit the new // signal mask. - block_sigchld(); + _Jv_BlockSigchld(); // Check/set the thread stack size. size_t min_ss = 32 * 1024; @@ -581,7 +593,7 @@ _Jv_ThreadRegister (_Jv_Thread_t *data) } # endif // Block SIGCHLD which is used in natPosixProcess.cc. - block_sigchld(); + _Jv_BlockSigchld(); } void @@ -629,7 +641,7 @@ _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, // Block SIGCHLD which is used in natPosixProcess.cc. // The current mask is inherited by the child thread. - block_sigchld(); + _Jv_BlockSigchld(); param.sched_priority = thread->getPriority();