From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6559 invoked by alias); 24 May 2008 14:35:46 -0000 Received: (qmail 6524 invoked by uid 367); 24 May 2008 14:35:45 -0000 Date: Sat, 24 May 2008 14:35:00 -0000 Message-ID: <20080524143545.6509.qmail@sourceware.org> From: cagney@sourceware.org To: frysk-cvs@sourceware.org Subject: [SCM] master: Implement jni/Poll. X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: cdc94e24e1b9394f0f825280834a4d5fb6b0dd89 X-Git-Newrev: 91e7054ffd1505588013927d9b3e006676fd09d8 Mailing-List: contact frysk-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: frysk-cvs-owner@sourceware.org Reply-To: frysk@sourceware.org X-SW-Source: 2008-q2/txt/msg00279.txt.bz2 The branch, master has been updated via 91e7054ffd1505588013927d9b3e006676fd09d8 (commit) via fddda9b43b4a23c6020c78a12d74bd0b3977cb6d (commit) from cdc94e24e1b9394f0f825280834a4d5fb6b0dd89 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit 91e7054ffd1505588013927d9b3e006676fd09d8 Author: Andrew Cagney Date: Sat May 24 10:34:43 2008 -0400 Implement jni/Poll. frysk-sys/frysk/sys/ChangeLog 2008-05-24 Andrew Cagney * jni/Poll.cxx: Implement. commit fddda9b43b4a23c6020c78a12d74bd0b3977cb6d Author: Andrew Cagney Date: Sat May 24 09:48:55 2008 -0400 Elminate RawDataManaged from Poll. frysk-sys/frysk/sys/ChangeLog 2008-05-24 Andrew Cagney * Poll.java: Replace RawDataManaged with long. (Fds): Add malloc and free methods. * cni/Poll.cxx: Update. ----------------------------------------------------------------------- Summary of changes: frysk-sys/frysk/sys/ChangeLog | 8 ++ frysk-sys/frysk/sys/Poll.java | 24 +++-- frysk-sys/frysk/sys/cni/Poll.cxx | 66 +++++++------ frysk-sys/frysk/sys/jni/Poll.cxx | 201 +++++++++++++++++++++++++++++++++++++- 4 files changed, 258 insertions(+), 41 deletions(-) First 500 lines of diff: diff --git a/frysk-sys/frysk/sys/ChangeLog b/frysk-sys/frysk/sys/ChangeLog index 3515ed5..72edd33 100644 --- a/frysk-sys/frysk/sys/ChangeLog +++ b/frysk-sys/frysk/sys/ChangeLog @@ -1,3 +1,11 @@ +2008-05-24 Andrew Cagney + + * jni/Poll.cxx: Implement. + + * Poll.java: Replace RawDataManaged with long. + (Fds): Add malloc and free methods. + * cni/Poll.cxx: Update. + 2008-05-22 Andrew Cagney * jni/Exec.cxx: Delete. diff --git a/frysk-sys/frysk/sys/Poll.java b/frysk-sys/frysk/sys/Poll.java index 5946a00..8496fd8 100644 --- a/frysk-sys/frysk/sys/Poll.java +++ b/frysk-sys/frysk/sys/Poll.java @@ -1,6 +1,6 @@ // This file is part of the program FRYSK. // -// Copyright 2005, 2007, Red Hat Inc. +// Copyright 2005, 2007, 2008, Red Hat Inc. // // FRYSK is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by @@ -76,16 +76,20 @@ public final class Poll /** * Manage the file descriptors watched by the poll call. */ - public static final class Fds - { - gnu.gcj.RawDataManaged fds; - int numFds; - private native void init (); - public final native void addPollIn (int fd); - public Fds () - { - init (); + public static final class Fds { + long fds; + public Fds() { + fds = malloc(); + } + protected void finalize() { + free(fds); + } + private static native long malloc(); + private static native void free(long fds); + public void addPollIn(int fd) { + fds = addPollIn(fds, fd); } + private static native long addPollIn(long fds, int fd); } static protected Fds pollFds = new Fds (); diff --git a/frysk-sys/frysk/sys/cni/Poll.cxx b/frysk-sys/frysk/sys/cni/Poll.cxx index b5c7735..1cffb92 100644 --- a/frysk-sys/frysk/sys/cni/Poll.cxx +++ b/frysk-sys/frysk/sys/cni/Poll.cxx @@ -1,6 +1,6 @@ // This file is part of the program FRYSK. // -// Copyright 2005, 2006, 2007, Red Hat Inc. +// Copyright 2005, 2006, 2007, 2008, Red Hat Inc. // // FRYSK is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by @@ -121,47 +121,53 @@ frysk::sys::Poll::addSignalHandler (frysk::sys::Signal* sig) +jlong +frysk::sys::Poll$Fds::malloc() { + // Allocate a non-empty buffer, marked with a sentinel. + struct pollfd* fds = (struct pollfd*) JvMalloc(sizeof (struct pollfd)); + fds->fd = -1; // sentinel + return (jlong)(long) fds; +} + void -frysk::sys::Poll$Fds::init () -{ - // Allocate a non-empty buffer, makes life easier. - numFds = 0; - fds = (gnu::gcj::RawDataManaged*) JvAllocBytes (sizeof (struct pollfd)); +frysk::sys::Poll$Fds::free(jlong fds) { + JvFree((struct pollfd*)(long)fds); } -static void -addPollFd (gnu::gcj::RawDataManaged* &pollFds, jint &numPollFds, - int fd, short event) -{ +static jlong +addPollFd(jlong pollFds, int fd, short event) { struct pollfd* ufds = (struct pollfd*) pollFds; - // If the FD is alreay listed, just add the event. - for (int i = 0; i < numPollFds; i++) { - if (ufds[i].fd == fd) { - ufds[i].events |= event; - return; + // If the FD is alreay listed, just add the event; end up with a + // count of fds. + int numFds; + for (numFds = 0; ufds[numFds].fd >= 0; numFds++) { + if (ufds[numFds].fd == fd) { + ufds[numFds].events |= event; + return pollFds; } } - // Create space for, and then append a new poll fd. - struct pollfd* newFds = (struct pollfd*) JvAllocBytes ((numPollFds + 1) * sizeof (struct pollfd)); - memcpy (newFds, ufds, numPollFds * sizeof (struct pollfd)); - newFds[numPollFds].fd = fd; - newFds[numPollFds].events = event; - pollFds = (gnu::gcj::RawDataManaged*) newFds; - numPollFds++; + // Create space for the new fd (and retain space for the sentinel). + ufds = (struct pollfd*) JvRealloc(ufds, (numFds + 2) * sizeof (struct pollfd)); + ufds[numFds + 0].fd = fd; + ufds[numFds + 0].events = event; + ufds[numFds + 1].fd = -1; + return (jlong) (long) ufds; } -void -frysk::sys::Poll$Fds::addPollIn (jint fd) -{ - addPollFd (fds, numFds, fd, POLLIN); +jlong +frysk::sys::Poll$Fds::addPollIn(jlong fds, jint fd) { + return addPollFd(fds, fd, POLLIN); } void -frysk::sys::Poll::poll (frysk::sys::PollBuilder* pollObserver, - jlong timeout) -{ +frysk::sys::Poll::poll(frysk::sys::PollBuilder* pollObserver, jlong timeout) { + // Compute the current number of poll fds. + struct pollfd* fds = (struct pollfd*)pollFds->fds; + int numFds; + for (numFds = 0; fds[numFds].fd >= 0; numFds++); + // Set up a SIGSETJMP call that jumps back to here when any watched // signal is delivered. The signals are accumulated in a sigset, // and removed from the current of signals being unmasked, and the @@ -195,7 +201,7 @@ frysk::sys::Poll::poll (frysk::sys::PollBuilder* pollObserver, errno = ::pthread_sigmask (SIG_UNBLOCK, &mask, 0); if (errno != 0) throwErrno (errno, "pthread_sigmask.UNBLOCK"); - int status = ::poll ((struct pollfd*)pollFds->fds, pollFds->numFds, timeout); + int status = ::poll (fds, numFds, timeout); if (status < 0) status = -errno; // Save the errno across the next system call. errno = ::pthread_sigmask (SIG_BLOCK, &mask, NULL); diff --git a/frysk-sys/frysk/sys/jni/Poll.cxx b/frysk-sys/frysk/sys/jni/Poll.cxx index b358932..a0f0eaa 100644 --- a/frysk-sys/frysk/sys/jni/Poll.cxx +++ b/frysk-sys/frysk/sys/jni/Poll.cxx @@ -1,6 +1,6 @@ // This file is part of the program FRYSK. // -// Copyright 2008, Red Hat Inc. +// Copyright 2005, 2006, 2007, 2008, Red Hat Inc. // // FRYSK is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by @@ -37,4 +37,203 @@ // version and license this file solely under the GPL without // exception. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "jni.hxx" + +#include "jnixx/exceptions.hxx" +#include "frysk/sys/jni/SignalSet.hxx" + +using namespace java::lang; +using namespace frysk::sys; + +// If there's a signal abort the wait() function using a longjmp (and +// return the signal). Should the jmpbuf be per-thread? + +struct poll_jmpbuf { + pid_t tid; + sigjmp_buf buf; +}; +struct poll_jmpbuf poll_jmpbuf; + +static void +handler(int signum, siginfo_t *siginfo, void *context) { + // For what ever reason, the signal can come in on the wrong thread. + // When that occures, re-direct it (explicitly) to the thread that + // can handle the signal. + pid_t me = ::syscall(SYS_gettid); + if (poll_jmpbuf.tid == me) { +#if 0 + fprintf (stderr, "pid %d got signal %d (%s) from %d\n", + me, siginfo->si_signo, strsignal (siginfo->si_signo), + siginfo->si_pid); +#endif + siglongjmp (poll_jmpbuf.buf, signum); + } + else + // XXX: Want to edit this thread's mask so that from now on it + // blocks this signal, don't know a way to do it though. + ::syscall(SYS_tkill, poll_jmpbuf.tid, signum); +} + +void +Poll::addSignalHandler(jnixx::env env, Signal sig) { + int signum = sig.hashCode(env); + // Make certain that the signal is masked (this is ment to be + // process wide). + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, signum); + // XXX: In a multi-threaded environment this call is not well + // defined (although it does help reduce the number of signals + // directed to the wrong thread). + sigprocmask(SIG_BLOCK, &mask, NULL); + // Install the above signal handler (it long jumps back to the code + // that enabled the signal). To avoid potential recursion, all + // signals are masked while the handler is running. + struct sigaction sa; + memset(&sa, 0, sizeof (sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO; + sigfillset(&sa.sa_mask); + sigaction(signum, &sa, NULL); +} + + + +jlong +Poll$Fds::malloc(jnixx::env env) { + // Allocate a non-empty buffer, marked with a sentinel. + struct pollfd* fds = (struct pollfd*) ::malloc (sizeof (struct pollfd)); + fds->fd = -1; // sentinel + return (jlong)(long) fds; +} + +void +Poll$Fds::free(jnixx::env env, jlong fds) { + ::free((struct pollfd*)(long)fds); +} + +static jlong +addPollFd(jlong pollFds, int fd, short event) { + struct pollfd* ufds = (struct pollfd*) pollFds; + // If the FD is alreay listed, just add the event; end up with a + // count of fds. + int numFds; + for (numFds = 0; ufds[numFds].fd >= 0; numFds++) { + if (ufds[numFds].fd == fd) { + ufds[numFds].events |= event; + return pollFds; + } + } + // Create space for the new fd (and retain space for the sentinel). + ufds = (struct pollfd*) ::realloc(ufds, (numFds + 2) * sizeof (struct pollfd)); + ufds[numFds + 0].fd = fd; + ufds[numFds + 0].events = event; + ufds[numFds + 1].fd = -1; + return (jlong) (long) ufds; +} + +jlong +Poll$Fds::addPollIn(jnixx::env env, jlong fds, jint fd) { + return addPollFd(fds, fd, POLLIN); +} + + + +void +Poll::poll(jnixx::env env, PollBuilder pollObserver, jlong timeout) { + // Compute the current number of poll fds. + struct pollfd* fds = (struct pollfd*)GetPollFds(env).GetFds(env); + int numFds; + for (numFds = 0; fds[numFds].fd >= 0; numFds++); + + // Set up a SIGSETJMP call that jumps back to here when any watched + // signal is delivered. The signals are accumulated in a sigset, + // and removed from the current of signals being unmasked, and the + // timer is set to zero forcing a non-blocking poll. + + sigset_t signals; + sigemptyset(&signals); + sigset_t mask = *getRawSet(env, GetSignalSet(env)); + int signum = sigsetjmp(poll_jmpbuf.buf, 1); + if (signum > 0) { + // Remove the signal from the local copy of the signal-mask set, + // doing this allows other signals to get through (otherwize this + // code could be swamped by a single re-occuring signal). + sigdelset(&mask, signum); + // Add it to those that have fired. + sigaddset(&signals, signum); + // Make the poll non-blocking. Now that at least one event has + // been detected, this method should not block instead returning + // immediatly after the file descriptors have been polled. + timeout = 0; + } + + // Unblock signals, and then wait for an event. There is a window + // between the unmask and poll system calls during which a signal + // could be delivered that doesn't interrupt the poll call. Avoid + // this race by having the signal handler longjmp back to the above + // setjmp, re-starting this code, forcing the poll (even if it + // wasn't reached) to be canceled. + + poll_jmpbuf.tid = ::syscall(SYS_gettid); + errno = ::pthread_sigmask (SIG_UNBLOCK, &mask, 0); + if (errno != 0) + errnoException(env, errno, "pthread_sigmask.UNBLOCK"); + int status = ::poll (fds, numFds, timeout); + if (status < 0) + status = -errno; // Save the errno across the next system call. + errno = ::pthread_sigmask (SIG_BLOCK, &mask, NULL); + if (errno != 0) + errnoException(env, errno, "pthread_sigmask.BLOCK"); + + // Did something go wrong? + if (status < 0) { + switch (-status) { + case EINTR: + break; + default: + errnoException(env, -status, "poll"); + } + } + + // Deliver any signals received during the poll; XXX: Is there a + // more efficient way of doing this? + + for (int i = 1; i < 32; i++) { + if (sigismember (&signals, i)) { + // Find the signal object. + Signal sig = Signal::valueOf(env, i); + // Notify the client of the signal. + pollObserver.signal(env, sig); + } + } + + // Did a file descriptor fire, status when +ve, contains the number + // of file descriptors that fired one or more events. + + for (int i = 0; i < numFds; i++) { + if (status <= 0) + // bail early + break; + if (fds[i].revents != 0) { + if (fds[i].revents & POLLIN) + pollObserver.pollIn(env, fds[i].fd); + status--; + } + } +} hooks/post-receive -- frysk system monitor/debugger