public inbox for frysk-cvs@sourceware.org
help / color / mirror / Atom feed
* [SCM]  master: Implement jni/Poll.
@ 2008-05-24 14:35 cagney
  0 siblings, 0 replies; only message in thread
From: cagney @ 2008-05-24 14:35 UTC (permalink / raw)
  To: frysk-cvs

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 <cagney@redhat.com>
Date:   Sat May 24 10:34:43 2008 -0400

    Implement jni/Poll.
    
    frysk-sys/frysk/sys/ChangeLog
    2008-05-24  Andrew Cagney  <cagney@redhat.com>
    
    	* jni/Poll.cxx: Implement.

commit fddda9b43b4a23c6020c78a12d74bd0b3977cb6d
Author: Andrew Cagney <cagney@redhat.com>
Date:   Sat May 24 09:48:55 2008 -0400

    Elminate RawDataManaged from Poll.
    
    frysk-sys/frysk/sys/ChangeLog
    2008-05-24  Andrew Cagney  <cagney@redhat.com>
    
    	* 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  <cagney@redhat.com>
+
+	* 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  <cagney@redhat.com>
 
 	* 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)
 
 \f
 
+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);
 }
 
 \f
 
 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 <malloc.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <alloca.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux.syscall.h>
+#include <sys/syscall.h>
+
 #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);
+}
+
+\f
+
+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);
+}
+
+\f
+
+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


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-05-24 14:35 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-05-24 14:35 [SCM] master: Implement jni/Poll cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).