JDK-4345157 : JDK 1.3.0 alters thread signal mask
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 1.3.0
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_7
  • CPU: sparc
  • Submitted: 2000-06-13
  • Updated: 2001-07-02
  • Resolved: 2000-12-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other Other Other
1.3.0_02 02Fixed 1.3.1Fixed 1.4.0Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description

Name: rlT66838			Date: 06/13/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-beta)
Java HotSpot(TM) Client VM (build 1.3-beta, mixed mode)

I have a problem with signals on JDK 1.3.0 beta on Solaris 7 using
the Hostpot VM (both client and server). When a thread attaches to the JVM
it seems that its signal mask is changed. This did not happen with JDK
1.2.2 on Solaris nor does it happen with Sun JDK 1.3.0 beta on Linux or
IBM JDK 1.3.0 alpha on Linux. So, I consider this to be a bug in JDK 1.3.0
beta on Solaris.

        Please find attached a program to reproduce this. It will run a
long loop. Hitting Ctrl-C will interrupt the program. On Solaris JDK 1.3
this will happen abruptly, because a thread other than main will get the
signal. On any other JDK, the main thread will exit with a message.

        On the machine tested uname -a gives:

SunOS sunsite.pub.ro 5.7 Generic_106541-11 sun4u sparc SUNW,Ultra-Enterprise

Dummy Java class to call from native code:

public class Prog
{                                                                               
    public static void main(String args[])
    {
        for(int i=1; i<1000000; i++)
            System.out.println("Java class invoked: " + args[0] + " -> " + i);
    }
}                                                                               

C program:

#include <jni.h>
#include <dlfcn.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
                                                                                
void *handle;
char* error;
                                                                                
jint (JNICALL *jni_create_java_vm)(JavaVM **, JNIEnv **, void *) = NULL;
                                                                                
JavaVM *jvm;
                                                                                
void loadJVM()
{                                                                               
    handle = dlopen(JVM_SO, RTLD_NOW|RTLD_GLOBAL);
    if (!handle) {
        fputs (dlerror(), stderr);
        fputs (" : 2\n", stderr);
        exit(1);
    }
    fputs("Will load JVM...\n", stderr);
                                                                                
    jni_create_java_vm = dlsym(handle, "JNI_CreateJavaVM");
    if ((error = dlerror()) != NULL) {
        fputs(error, stderr);
        fputs (" : 3\n", stderr);
        exit(1);
    }
                                                                                
    fputs("JVM loaded okay.\n", stderr);
}                                                                               
                                                                                
JNIEnv* initJVM() /* The JDK1.2 way of doing it */
{                                                                               
    JNIEnv *env = NULL;
    JavaVMInitArgs vm_args;
    JavaVMOption options[1];
    jint res;
                                                                                
    options[0].optionString = "-Djava.class.path=.";   /* user classes */
                                                                                
    vm_args.version = JNI_VERSION_1_2;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = JNI_FALSE;
                                                                                
    fputs("Will create JVM...\n", stderr);
                                                                                
    res = (*jni_create_java_vm)(&jvm, &env, &vm_args);
    if (res < 0) {
        fprintf(stderr, "Can't create Java VM: %d\n", res);
        exit(1);
    }
                                                                                
    fputs("JVM created OK!\n", stderr);
    return env;
}                                                                               

void doStuff(JNIEnv *env)
{                                                                               
    jclass cls;
    jmethodID mid;
    jstring jstr;
    jobjectArray args;
                                                                                
    cls = (*env)->FindClass(env, "Prog");
    if (cls == 0) {
        fprintf(stderr, "Can't find Prog class\n");
        exit(1);
    }
                                                                                
    mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
    if (mid == 0) {
        fprintf(stderr, "Can't find Prog.main\n");
        exit(1);
    }
                                                                                
    jstr = (*env)->NewStringUTF(env, "from C!");
    if (jstr == 0) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    args = (*env)->NewObjectArray(env, 1,
                        (*env)->FindClass(env, "java/lang/String"), jstr);
    if (args == 0) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    (*env)->CallStaticVoidMethod(env, cls, mid, args);
                                                                                
}                                                                               

JNIEnv* atchJVM()
{                                                                               
    JNIEnv *env = NULL;
    int res;
    res = (*jvm)->AttachCurrentThread(jvm, (void**)&env, NULL);
    if (res < 0) {
       fprintf(stderr, "Thread attach failed\n");
       return NULL;
    }
    return env;
}                                                                               
                                                                                
void* somethr(void* x)
{                                                                               
    JNIEnv *env;
                                                                                
    fprintf(stderr, "Some thread will create JVM.\n");
    loadJVM();
    env = initJVM();
                                                                                
    fprintf(stderr, "Some thread will call Java.\n");
                                                                                
    doStuff(env);
                                                                                
    if((*jvm)->DetachCurrentThread(jvm) != 0)
        fputs("Error: thread not detached!\n", stderr);
    fprintf(stderr, "Some thread exiting.\n");
    return env;
}                     
int main()
{                                                                               
    JNIEnv *env;
    sigset_t set;
    pthread_t thr1;
    pthread_attr_t attr;
    int ss=0, sig;
                                                                                
    fprintf(stderr, "Main thread will set signal mask.\n");
                                                                                
    sigemptyset(&set);
    sigaddset(&set, SIGPIPE);
    sigaddset(&set, SIGTERM);
    sigaddset(&set, SIGHUP);
    sigaddset(&set, SIGINT);
    pthread_sigmask(SIG_BLOCK, &set, NULL);
                                                                                
    pthread_attr_init(&attr);
    ss = 1024 * 1024;
    pthread_attr_setstacksize(&attr, ss);
    pthread_attr_getstacksize(&attr, &ss);
    fprintf(stderr, "Stack size: %d\n", ss);
                                                                                
    pthread_create(&thr1,NULL,somethr,NULL);
                                                                                
    sigemptyset(&set);
    sigaddset(&set, SIGTERM);
    sigaddset(&set, SIGHUP);
    sigaddset(&set, SIGINT);
                                                          
    fprintf(stderr, "Main thread waiting for signal.\n");
                                                                                
    do {
        int err;
                                                                                
        sig = 0;
        err = sigwait(&set, &sig);
        if (err != 0 && err != EINTR) {
            fprintf(stderr, "main: sigwait() error:  %s\n", strerror(err));
        }
        else {
            fprintf(stderr, "main: sigwait() got:  %d\n", sig);
            exit(0);
        }
    } while (sig != SIGTERM && sig != SIGINT);
                                                                              	    
pthread_join(thr1,
NULL);

    dlclose(handle);
    fputs("Main thread exiting.\n", stderr);
}
(Review ID: 106080) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: ladybird FIXED IN: ladybird INTEGRATED IN: 1.3.0_02 ladybird-beta merlin-beta VERIFIED IN: 1.3.0_02
14-06-2004

EVALUATION y.s.ramakrishna@eng 2000-10-02: The change described in "Comments" fixed the problem that iWS was having (according to Krishna Ramachandran). An analogous change works for the program included in the "Description" section. We are working on evolving an interface to allow the proper sharing of signals between the JVM and an embedding program or native methods. The change will be officially put back soon. y.s.ramakrishna@eng 2000-11-06: Robert and Ken, whenever the change has been completed for Linux & Win32, the java -X message should be updated: src/share/vm/Xusage.txt with something along these lines: -Xrs reduce usage of OS signals by Java/VM By the way, at that time, placing the -X messages in alphabetic order may seem to be a good thing to do, as well? ---- Ported over Solaris changes by y.s.ramakrishna@eng to Linux. Win32 changes were done and closed under bug 4323062. kenneth.russell@eng 2000-12-04
11-06-2004

WORK AROUND Name: rlT66838 Date: 06/13/2000 None. ======================================================================
11-06-2004

SUGGESTED FIX Do not change the disposition of SIGINT and SIGTERM in java threads' signal masks. y.s.ramakrishna@eng 2000-10-23: The changes have been made on the Solaris side to resolve the apparent (new in JDK 1.3) conflict with Shutdown Hooks. Here's the putback message for the changes to the Solaris side. Transferring to Robert Lougher for Linux side changes (Robert, please coordinate with Ken/transfer to him/ for the Windows changes at the proopriate time. I will move the Solaris changes to main baseline today.) Date: Fri, 20 Oct 2000 16:48:08 -0700 (PDT) From: "Y. S. Ramakrishna" <###@###.###> To: ###@###.### Subject: Code Manager notification Mime-Version: 1.0 Event: putback-to Parent workspace: /net/jano/export/disk05/hotspot/ws/1.3.1/ladybird_baseline (jano:/export/disk05/hotspot/ws/1.3.1/ladybird_baseline) Child workspace: /net/jano.eng/export/disk05/hotspot/imgr/ws/20001020153810.ysr.ladybird (jano.eng:/export/disk05/hotspot/imgr/ws/20001020153810.ysr.ladybird) User: ysr Comment: Original workspace: neeraja:/net/jano/export/disk05/hotspot/users/ysr/ladybird Parent workspace: /net/jano/export/disk05/hotspot/ws/1.3.1/ladybird_baseline Original user: ysr 4345157 JDK 1.3.0 beta on Solaris alters thread signal mask webrev at http://analemma.eng/net/jano.eng/export/disk05/hotspot/users/ysr/ladybird/webrev/index.html This bug was filed against 1.3 beta but somehow slipped through the bug sieve. Recently, iPlanet WebServer ran into a problem which we traced to the alteration of thread signal masks by the VM. iWS uses SIGTERM and SIGINT for its own purposes, for which it blocks these two signals in all threads. It then runs a dedicated "catcher" thread which waits for SIGTERM and SIGINT (among others) using sigwait(). Because HotSpot unblocked SIGTERM and SIGINT on threads attaching to the VM, iWS's "catcher" thread would sometimes miss signals (which would go to the Java threads instead), causing incorrect behaviour. Although the JNI spec appears to be mum on the sharing of signals between the VM and native code, in this particular case, it appears unnecessary to unblock these two signals. Following a meeting between kbr, rlougher, mr, steffen and ysr, it seemed that it was best to make use of the -Xrs flag to resolve the conflict between native use of signals and their use by the Shutdown Hooks facility. Accordingly, when -Xrs is set the VM doesn't use SHUTDOWN{1,2,3}_SIGNAL and BREAK_SIGNAL in the usual way, allowing native code to make use of these signals as it sees fit. Indeed the disposition of these signals is not altered in any manner. Did some clean-up, restructuring and re-naming of scattered #defines related to signals. NOTE: Documentation should be upgraded to reflect the modification in the semantics of -Xrs. Filed bug # 4381444, to be completed. Ken and Robert will, respectively, affect analogous/similar changes to Linux and Windows code. In particular, the latter putback should rename SIGBREAK in os.cpp appropriately. Reviewed by: kbr, steffen, lewy; discussions and input also from mr, rlougher Ken & Robert pointed out the need for "signal chaining". That is a change independent of the current bug-fix and will be affected in a separate putback/bug-id RFE#4381843. Tests: Volano, iWS and the (Romanian) program in the bug report on sparc solaris; checked that -Xrs delivers on its (new) promises. imgr testing Note: no special tests after latest synch (which touched totally orthogonal files and code. Performance: i expect no change in performance due to this change. As expected, Volano and SPEC scores on my desktop don't change. passed linux i486 product1 SPECjvm98 GeoMean 47.86 50.98 passed linux i486 product SPECjvm98 GeoMean 36.31 57.16 passed solaris i486 product1 SPECjvm98 GeoMean 23.86 25.36 passed solaris i486 product SPECjvm98 GeoMean 22.28 34.75 passed solaris i486 productcore SPECjvm98 GeoMean 60.80 60.80 passed solaris sparc product1 SPECjvm98 GeoMean 9.43 10.88 passed solaris sparc product SPECjvm98 GeoMean 16.17 28.38 passed solaris sparc productcore SPECjvm98 GeoMean 35.03 35.03 passed win32 i486 compiler1 SPECjvm98 GeoMean 40.30 45.58 passed win32 i486 compiler2 SPECjvm98 GeoMean 33.34 52.30 passed win32 i486 core SPECjvm98 GeoMean 90.45 90.45 Files: update: src/os/solaris/vm/jvm_solaris.cpp update: src/os/solaris/vm/jvm_solaris.h update: src/os/solaris/vm/os_solaris.cpp update: src/share/vm/runtime/arguments.cpp update: src/share/vm/runtime/globals.hpp y.s.ramakrishna@eng 2000-10-24: changes above (for Solaris only so far) pushed into merlin (main/baseline) today.
24-10-2000