Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/nio/fs/AbstractPoller.java
38918 views
/*1* Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.fs;2627import java.nio.file.*;28import java.security.AccessController;29import java.security.PrivilegedAction;30import java.io.IOException;31import java.util.*;3233/**34* Base implementation of background poller thread used in watch service35* implementations. A poller thread waits on events from the file system and36* also services "requests" from clients to register for new events or cancel37* existing registrations.38*/3940abstract class AbstractPoller implements Runnable {4142// list of requests pending to the poller thread43private final LinkedList<Request> requestList;4445// set to true when shutdown46private boolean shutdown;4748protected AbstractPoller() {49this.requestList = new LinkedList<Request>();50this.shutdown = false;51}5253/**54* Starts the poller thread55*/56public void start() {57final Runnable thisRunnable = this;58AccessController.doPrivileged(new PrivilegedAction<Object>() {59@Override60public Object run() {61Thread thr = new Thread(thisRunnable);62thr.setDaemon(true);63thr.start();64return null;65}66});67}6869/**70* Wakeup poller thread so that it can service pending requests71*/72abstract void wakeup() throws IOException;7374/**75* Executed by poller thread to register directory for changes76*/77abstract Object implRegister(Path path,78Set<? extends WatchEvent.Kind<?>> events,79WatchEvent.Modifier... modifiers);8081/**82* Executed by poller thread to cancel key83*/84abstract void implCancelKey(WatchKey key);8586/**87* Executed by poller thread to shutdown and cancel all keys88*/89abstract void implCloseAll();9091/**92* Requests, and waits on, poller thread to register given file.93*/94final WatchKey register(Path dir,95WatchEvent.Kind<?>[] events,96WatchEvent.Modifier... modifiers)97throws IOException98{99// validate arguments before request to poller100if (dir == null)101throw new NullPointerException();102Set<WatchEvent.Kind<?>> eventSet = new HashSet<>(events.length);103for (WatchEvent.Kind<?> event: events) {104// standard events105if (event == StandardWatchEventKinds.ENTRY_CREATE ||106event == StandardWatchEventKinds.ENTRY_MODIFY ||107event == StandardWatchEventKinds.ENTRY_DELETE)108{109eventSet.add(event);110continue;111}112113// OVERFLOW is ignored114if (event == StandardWatchEventKinds.OVERFLOW)115continue;116117// null/unsupported118if (event == null)119throw new NullPointerException("An element in event set is 'null'");120throw new UnsupportedOperationException(event.name());121}122if (eventSet.isEmpty())123throw new IllegalArgumentException("No events to register");124return (WatchKey)invoke(RequestType.REGISTER, dir, eventSet, modifiers);125}126127/**128* Cancels, and waits on, poller thread to cancel given key.129*/130final void cancel(WatchKey key) {131try {132invoke(RequestType.CANCEL, key);133} catch (IOException x) {134// should not happen135throw new AssertionError(x.getMessage());136}137}138139/**140* Shutdown poller thread141*/142final void close() throws IOException {143invoke(RequestType.CLOSE);144}145146/**147* Types of request that the poller thread must handle148*/149private static enum RequestType {150REGISTER,151CANCEL,152CLOSE;153}154155/**156* Encapsulates a request (command) to the poller thread.157*/158private static class Request {159private final RequestType type;160private final Object[] params;161162private boolean completed = false;163private Object result = null;164165Request(RequestType type, Object... params) {166this.type = type;167this.params = params;168}169170RequestType type() {171return type;172}173174Object[] parameters() {175return params;176}177178void release(Object result) {179synchronized (this) {180this.completed = true;181this.result = result;182notifyAll();183}184}185186/**187* Await completion of the request. The return value is the result of188* the request.189*/190Object awaitResult() {191boolean interrupted = false;192synchronized (this) {193while (!completed) {194try {195wait();196} catch (InterruptedException x) {197interrupted = true;198}199}200if (interrupted)201Thread.currentThread().interrupt();202return result;203}204}205}206207/**208* Enqueues request to poller thread and waits for result209*/210private Object invoke(RequestType type, Object... params) throws IOException {211// submit request212Request req = new Request(type, params);213synchronized (requestList) {214if (shutdown) {215throw new ClosedWatchServiceException();216}217requestList.add(req);218}219220// wakeup thread221wakeup();222223// wait for result224Object result = req.awaitResult();225226if (result instanceof RuntimeException)227throw (RuntimeException)result;228if (result instanceof IOException )229throw (IOException)result;230return result;231}232233/**234* Invoked by poller thread to process all pending requests235*236* @return true if poller thread should shutdown237*/238@SuppressWarnings("unchecked")239boolean processRequests() {240synchronized (requestList) {241Request req;242while ((req = requestList.poll()) != null) {243// if in process of shutdown then reject request244if (shutdown) {245req.release(new ClosedWatchServiceException());246}247248switch (req.type()) {249/**250* Register directory251*/252case REGISTER: {253Object[] params = req.parameters();254Path path = (Path)params[0];255Set<? extends WatchEvent.Kind<?>> events =256(Set<? extends WatchEvent.Kind<?>>)params[1];257WatchEvent.Modifier[] modifiers =258(WatchEvent.Modifier[])params[2];259req.release(implRegister(path, events, modifiers));260break;261}262/**263* Cancel existing key264*/265case CANCEL : {266Object[] params = req.parameters();267WatchKey key = (WatchKey)params[0];268implCancelKey(key);269req.release(null);270break;271}272/**273* Close watch service274*/275case CLOSE: {276implCloseAll();277req.release(null);278shutdown = true;279break;280}281282default:283req.release(new IOException("request not recognized"));284}285}286}287return shutdown;288}289}290291292