jdk/src/solaris/classes/sun/nio/ch/KQueuePort.java
author michaelm
Tue, 06 Mar 2012 20:34:38 +0000
changeset 12047 320a714614e9
child 19607 bee007586d06
permissions -rw-r--r--
7113349: Initial changeset for Macosx port to jdk Reviewed-by: jjh, alanb, dholmes, anthony, ohrstrom, ksrini, jrose, weijun, smarks Contributed-by: Alan Bateman <alan.bateman@oracle.com>, Alexander Potochkin <alexander.potochkin@oracle.com>, Alexander Zuev <alexander.zuev@oracle.com>, Andrew Brygin <andrew.brygin@oracle.com>, Artem Ananiev <artem.ananiev@oracle.com>, Alex Strange <astrange@apple.com>, Bino George <bino@apple.com>, Christine Lu <christine.lu@oracle.com>, David Katleman <david.katleman@oracle.com>, David Durrence <david_durrence@apple.com>, Dmitry Cherepanov <dmitry.cherepanov@oracle.com>, Greg Lewis <glewis@eyesbeyond.com>, Kevin Miller <kevin_m_miller@apple.com>, Kurt Miller <kurt@intricatesoftware.com>, Landon Fuller <landonf@plausiblelabs.com>, Leonid Romanov <leonid.romanov@oracle.com>, Loefty Walkowiak <loefty@apple.com>, Mark Reinhold <mark.reinhold@oracle.com>, Naoto Sato <naoto.sato@oracle.com>, Philip Race <philip.race@oracle.com>, Roger Hoover <rhoover@apple.com>, Scott Kovatch <scott.kovatch@oracle.com>, Sergey ByloKhov <sergey.bylokhov@oracle.com>, Mike Swingler <swingler@apple.com>, Tomas Hurka <tomas.hurka@oracle.com>
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
12047
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     1
/*
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     2
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     4
 *
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    10
 *
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    15
 * accompanied this code).
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    16
 *
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    20
 *
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    23
 * questions.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    24
 */
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    25
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    26
package sun.nio.ch;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    27
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    28
import java.nio.channels.spi.AsynchronousChannelProvider;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    29
import java.io.IOException;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    30
import java.util.concurrent.ArrayBlockingQueue;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    31
import java.util.concurrent.RejectedExecutionException;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    32
import java.util.concurrent.atomic.AtomicInteger;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    33
import static sun.nio.ch.KQueue.*;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    34
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    35
/**
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    36
 * AsynchronousChannelGroup implementation based on the BSD kqueue facility.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    37
 */
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    38
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    39
final class KQueuePort
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    40
    extends Port
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    41
{
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    42
    // maximum number of events to poll at a time
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    43
    private static final int MAX_KEVENTS_TO_POLL = 512;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    44
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    45
    // kqueue file descriptor
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    46
    private final int kqfd;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    47
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    48
    // true if kqueue closed
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    49
    private boolean closed;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    50
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    51
    // socket pair used for wakeup
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    52
    private final int sp[];
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    53
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    54
    // number of wakeups pending
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    55
    private final AtomicInteger wakeupCount = new AtomicInteger();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    56
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    57
    // address of the poll array passed to kqueue_wait
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    58
    private final long address;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    59
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    60
    // encapsulates an event for a channel
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    61
    static class Event {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    62
        final PollableChannel channel;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    63
        final int events;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    64
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    65
        Event(PollableChannel channel, int events) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    66
            this.channel = channel;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    67
            this.events = events;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    68
        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    69
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    70
        PollableChannel channel()   { return channel; }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    71
        int events()                { return events; }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    72
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    73
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    74
    // queue of events for cases that a polling thread dequeues more than one
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    75
    // event
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    76
    private final ArrayBlockingQueue<Event> queue;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    77
    private final Event NEED_TO_POLL = new Event(null, 0);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    78
    private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    79
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    80
    KQueuePort(AsynchronousChannelProvider provider, ThreadPool pool)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    81
        throws IOException
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    82
    {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    83
        super(provider, pool);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    84
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    85
        // open kqueue
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    86
        this.kqfd = kqueue();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    87
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    88
        // create socket pair for wakeup mechanism
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    89
        int[] sv = new int[2];
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    90
        try {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    91
            socketpair(sv);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    92
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    93
            // register one end with kqueue
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    94
            keventRegister(kqfd, sv[0], EVFILT_READ, EV_ADD);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    95
        } catch (IOException x) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    96
            close0(kqfd);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    97
            throw x;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    98
        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
    99
        this.sp = sv;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   100
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   101
        // allocate the poll array
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   102
        this.address = allocatePollArray(MAX_KEVENTS_TO_POLL);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   103
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   104
        // create the queue and offer the special event to ensure that the first
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   105
        // threads polls
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   106
        this.queue = new ArrayBlockingQueue<Event>(MAX_KEVENTS_TO_POLL);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   107
        this.queue.offer(NEED_TO_POLL);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   108
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   109
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   110
    KQueuePort start() {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   111
        startThreads(new EventHandlerTask());
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   112
        return this;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   113
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   114
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   115
    /**
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   116
     * Release all resources
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   117
     */
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   118
    private void implClose() {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   119
        synchronized (this) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   120
            if (closed)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   121
                return;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   122
            closed = true;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   123
        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   124
        freePollArray(address);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   125
        close0(sp[0]);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   126
        close0(sp[1]);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   127
        close0(kqfd);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   128
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   129
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   130
    private void wakeup() {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   131
        if (wakeupCount.incrementAndGet() == 1) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   132
            // write byte to socketpair to force wakeup
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   133
            try {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   134
                interrupt(sp[1]);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   135
            } catch (IOException x) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   136
                throw new AssertionError(x);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   137
            }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   138
        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   139
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   140
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   141
    @Override
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   142
    void executeOnHandlerTask(Runnable task) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   143
        synchronized (this) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   144
            if (closed)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   145
                throw new RejectedExecutionException();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   146
            offerTask(task);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   147
            wakeup();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   148
        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   149
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   150
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   151
    @Override
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   152
    void shutdownHandlerTasks() {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   153
        /*
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   154
         * If no tasks are running then just release resources; otherwise
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   155
         * write to the one end of the socketpair to wakeup any polling threads.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   156
         */
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   157
        int nThreads = threadCount();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   158
        if (nThreads == 0) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   159
            implClose();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   160
        } else {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   161
            // send interrupt to each thread
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   162
            while (nThreads-- > 0) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   163
                wakeup();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   164
            }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   165
        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   166
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   167
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   168
    // invoked by clients to register a file descriptor
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   169
    @Override
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   170
    void startPoll(int fd, int events) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   171
        // We use a separate filter for read and write events.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   172
        // TBD: Measure cost of EV_ONESHOT vs. EV_CLEAR, either will do here.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   173
        int err = 0;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   174
        int flags = (EV_ADD|EV_ONESHOT);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   175
        if ((events & Port.POLLIN) > 0)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   176
            err = keventRegister(kqfd, fd, EVFILT_READ, flags);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   177
        if (err == 0 && (events & Port.POLLOUT) > 0)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   178
            err = keventRegister(kqfd, fd, EVFILT_WRITE, flags);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   179
        if (err != 0)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   180
            throw new InternalError("kevent failed: " + err);  // should not happen
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   181
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   182
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   183
    /*
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   184
     * Task to process events from kqueue and dispatch to the channel's
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   185
     * onEvent handler.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   186
     *
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   187
     * Events are retreived from kqueue in batch and offered to a BlockingQueue
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   188
     * where they are consumed by handler threads. A special "NEED_TO_POLL"
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   189
     * event is used to signal one consumer to re-poll when all events have
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   190
     * been consumed.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   191
     */
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   192
    private class EventHandlerTask implements Runnable {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   193
        private Event poll() throws IOException {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   194
            try {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   195
                for (;;) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   196
                    int n = keventPoll(kqfd, address, MAX_KEVENTS_TO_POLL);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   197
                    /*
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   198
                     * 'n' events have been read. Here we map them to their
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   199
                     * corresponding channel in batch and queue n-1 so that
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   200
                     * they can be handled by other handler threads. The last
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   201
                     * event is handled by this thread (and so is not queued).
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   202
                     */
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   203
                    fdToChannelLock.readLock().lock();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   204
                    try {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   205
                        while (n-- > 0) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   206
                            long keventAddress = getEvent(address, n);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   207
                            int fd = getDescriptor(keventAddress);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   208
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   209
                            // wakeup
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   210
                            if (fd == sp[0]) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   211
                                if (wakeupCount.decrementAndGet() == 0) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   212
                                    // no more wakeups so drain pipe
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   213
                                    drain1(sp[0]);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   214
                                }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   215
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   216
                                // queue special event if there are more events
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   217
                                // to handle.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   218
                                if (n > 0) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   219
                                    queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   220
                                    continue;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   221
                                }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   222
                                return EXECUTE_TASK_OR_SHUTDOWN;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   223
                            }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   224
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   225
                            PollableChannel channel = fdToChannel.get(fd);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   226
                            if (channel != null) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   227
                                int filter = getFilter(keventAddress);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   228
                                int events = 0;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   229
                                if (filter == EVFILT_READ)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   230
                                    events = Port.POLLIN;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   231
                                else if (filter == EVFILT_WRITE)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   232
                                    events = Port.POLLOUT;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   233
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   234
                                Event ev = new Event(channel, events);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   235
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   236
                                // n-1 events are queued; This thread handles
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   237
                                // the last one except for the wakeup
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   238
                                if (n > 0) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   239
                                    queue.offer(ev);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   240
                                } else {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   241
                                    return ev;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   242
                                }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   243
                            }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   244
                        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   245
                    } finally {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   246
                        fdToChannelLock.readLock().unlock();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   247
                    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   248
                }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   249
            } finally {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   250
                // to ensure that some thread will poll when all events have
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   251
                // been consumed
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   252
                queue.offer(NEED_TO_POLL);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   253
            }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   254
        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   255
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   256
        public void run() {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   257
            Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   258
                Invoker.getGroupAndInvokeCount();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   259
            final boolean isPooledThread = (myGroupAndInvokeCount != null);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   260
            boolean replaceMe = false;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   261
            Event ev;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   262
            try {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   263
                for (;;) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   264
                    // reset invoke count
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   265
                    if (isPooledThread)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   266
                        myGroupAndInvokeCount.resetInvokeCount();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   267
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   268
                    try {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   269
                        replaceMe = false;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   270
                        ev = queue.take();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   271
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   272
                        // no events and this thread has been "selected" to
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   273
                        // poll for more.
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   274
                        if (ev == NEED_TO_POLL) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   275
                            try {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   276
                                ev = poll();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   277
                            } catch (IOException x) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   278
                                x.printStackTrace();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   279
                                return;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   280
                            }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   281
                        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   282
                    } catch (InterruptedException x) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   283
                        continue;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   284
                    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   285
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   286
                    // handle wakeup to execute task or shutdown
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   287
                    if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   288
                        Runnable task = pollTask();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   289
                        if (task == null) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   290
                            // shutdown request
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   291
                            return;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   292
                        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   293
                        // run task (may throw error/exception)
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   294
                        replaceMe = true;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   295
                        task.run();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   296
                        continue;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   297
                    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   298
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   299
                    // process event
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   300
                    try {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   301
                        ev.channel().onEvent(ev.events(), isPooledThread);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   302
                    } catch (Error x) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   303
                        replaceMe = true; throw x;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   304
                    } catch (RuntimeException x) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   305
                        replaceMe = true; throw x;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   306
                    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   307
                }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   308
            } finally {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   309
                // last handler to exit when shutdown releases resources
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   310
                int remaining = threadExit(this, replaceMe);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   311
                if (remaining == 0 && isShutdown()) {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   312
                    implClose();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   313
                }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   314
            }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   315
        }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   316
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   317
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   318
    // -- Native methods --
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   319
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   320
    private static native void socketpair(int[] sv) throws IOException;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   321
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   322
    private static native void interrupt(int fd) throws IOException;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   323
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   324
    private static native void drain1(int fd) throws IOException;
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   325
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   326
    private static native void close0(int fd);
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   327
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   328
    static {
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   329
        Util.load();
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   330
    }
320a714614e9 7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
diff changeset
   331
}