Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java
32288 views
1
/*
2
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.nio.fs;
27
28
import java.nio.file.*;
29
import java.security.AccessController;
30
import java.security.PrivilegedAction;
31
import java.util.*;
32
import java.io.IOException;
33
import sun.misc.Unsafe;
34
35
import static sun.nio.fs.UnixConstants.*;
36
37
/**
38
* Solaris implementation of WatchService based on file events notification
39
* facility.
40
*/
41
42
class SolarisWatchService
43
extends AbstractWatchService
44
{
45
private static final Unsafe unsafe = Unsafe.getUnsafe();
46
private static int addressSize = unsafe.addressSize();
47
48
private static int dependsArch(int value32, int value64) {
49
return (addressSize == 4) ? value32 : value64;
50
}
51
52
/*
53
* typedef struct port_event {
54
* int portev_events;
55
* ushort_t portev_source;
56
* ushort_t portev_pad;
57
* uintptr_t portev_object;
58
* void *portev_user;
59
* } port_event_t;
60
*/
61
private static final int SIZEOF_PORT_EVENT = dependsArch(16, 24);
62
private static final int OFFSETOF_EVENTS = 0;
63
private static final int OFFSETOF_SOURCE = 4;
64
private static final int OFFSETOF_OBJECT = 8;
65
66
/*
67
* typedef struct file_obj {
68
* timestruc_t fo_atime;
69
* timestruc_t fo_mtime;
70
* timestruc_t fo_ctime;
71
* uintptr_t fo_pad[3];
72
* char *fo_name;
73
* } file_obj_t;
74
*/
75
private static final int SIZEOF_FILEOBJ = dependsArch(40, 80);
76
private static final int OFFSET_FO_NAME = dependsArch(36, 72);
77
78
// port sources
79
private static final short PORT_SOURCE_USER = 3;
80
private static final short PORT_SOURCE_FILE = 7;
81
82
// user-watchable events
83
private static final int FILE_MODIFIED = 0x00000002;
84
private static final int FILE_ATTRIB = 0x00000004;
85
private static final int FILE_NOFOLLOW = 0x10000000;
86
87
// exception events
88
private static final int FILE_DELETE = 0x00000010;
89
private static final int FILE_RENAME_TO = 0x00000020;
90
private static final int FILE_RENAME_FROM = 0x00000040;
91
private static final int UNMOUNTED = 0x20000000;
92
private static final int MOUNTEDOVER = 0x40000000;
93
94
// background thread to read change events
95
private final Poller poller;
96
97
SolarisWatchService(UnixFileSystem fs) throws IOException {
98
int port = -1;
99
try {
100
port = portCreate();
101
} catch (UnixException x) {
102
throw new IOException(x.errorString());
103
}
104
105
this.poller = new Poller(fs, this, port);
106
this.poller.start();
107
}
108
109
@Override
110
WatchKey register(Path dir,
111
WatchEvent.Kind<?>[] events,
112
WatchEvent.Modifier... modifiers)
113
throws IOException
114
{
115
// delegate to poller
116
return poller.register(dir, events, modifiers);
117
}
118
119
@Override
120
void implClose() throws IOException {
121
// delegate to poller
122
poller.close();
123
}
124
125
/**
126
* WatchKey implementation
127
*/
128
private class SolarisWatchKey extends AbstractWatchKey
129
implements DirectoryNode
130
{
131
private final UnixFileKey fileKey;
132
133
// pointer to native file_obj object
134
private final long object;
135
136
// events (may be changed). set to null when watch key is invalid
137
private volatile Set<? extends WatchEvent.Kind<?>> events;
138
139
// map of entries in directory; created lazily; accessed only by
140
// poller thread.
141
private Map<Path,EntryNode> children = new HashMap<>();
142
143
SolarisWatchKey(SolarisWatchService watcher,
144
UnixPath dir,
145
UnixFileKey fileKey,
146
long object,
147
Set<? extends WatchEvent.Kind<?>> events)
148
{
149
super(dir, watcher);
150
this.fileKey = fileKey;
151
this.object = object;
152
this.events = events;
153
}
154
155
UnixPath getDirectory() {
156
return (UnixPath)watchable();
157
}
158
159
UnixFileKey getFileKey() {
160
return fileKey;
161
}
162
163
@Override
164
public long object() {
165
return object;
166
}
167
168
void invalidate() {
169
events = null;
170
}
171
172
Set<? extends WatchEvent.Kind<?>> events() {
173
return events;
174
}
175
176
void setEvents(Set<? extends WatchEvent.Kind<?>> events) {
177
this.events = events;
178
}
179
180
Map<Path,EntryNode> children() {
181
return children;
182
}
183
184
@Override
185
public boolean isValid() {
186
return events != null;
187
}
188
189
@Override
190
public void cancel() {
191
if (isValid()) {
192
// delegate to poller
193
poller.cancel(this);
194
}
195
}
196
197
@Override
198
public void addChild(Path name, EntryNode node) {
199
children.put(name, node);
200
}
201
202
@Override
203
public void removeChild(Path name) {
204
children.remove(name);
205
}
206
207
@Override
208
public EntryNode getChild(Path name) {
209
return children.get(name);
210
}
211
}
212
213
/**
214
* Background thread to read from port
215
*/
216
private class Poller extends AbstractPoller {
217
218
// maximum number of events to read per call to port_getn
219
private static final int MAX_EVENT_COUNT = 128;
220
221
// events that map to ENTRY_DELETE
222
private static final int FILE_REMOVED =
223
(FILE_DELETE|FILE_RENAME_TO|FILE_RENAME_FROM);
224
225
// events that tell us not to re-associate the object
226
private static final int FILE_EXCEPTION =
227
(FILE_REMOVED|UNMOUNTED|MOUNTEDOVER);
228
229
// address of event buffers (used to receive events with port_getn)
230
private final long bufferAddress;
231
232
private final SolarisWatchService watcher;
233
234
// the I/O port
235
private final int port;
236
237
// maps file key (dev/inode) to WatchKey
238
private final Map<UnixFileKey,SolarisWatchKey> fileKey2WatchKey;
239
240
// maps file_obj object to Node
241
private final Map<Long,Node> object2Node;
242
243
/**
244
* Create a new instance
245
*/
246
Poller(UnixFileSystem fs, SolarisWatchService watcher, int port) {
247
this.watcher = watcher;
248
this.port = port;
249
this.bufferAddress =
250
unsafe.allocateMemory(SIZEOF_PORT_EVENT * MAX_EVENT_COUNT);
251
this.fileKey2WatchKey = new HashMap<UnixFileKey,SolarisWatchKey>();
252
this.object2Node = new HashMap<Long,Node>();
253
}
254
255
@Override
256
void wakeup() throws IOException {
257
// write to port to wakeup polling thread
258
try {
259
portSend(port, 0);
260
} catch (UnixException x) {
261
throw new IOException(x.errorString());
262
}
263
}
264
265
@Override
266
Object implRegister(Path obj,
267
Set<? extends WatchEvent.Kind<?>> events,
268
WatchEvent.Modifier... modifiers)
269
{
270
// no modifiers supported at this time
271
if (modifiers.length > 0) {
272
for (WatchEvent.Modifier modifier: modifiers) {
273
if (modifier == null)
274
return new NullPointerException();
275
if (modifier instanceof com.sun.nio.file.SensitivityWatchEventModifier)
276
continue; // ignore
277
return new UnsupportedOperationException("Modifier not supported");
278
}
279
}
280
281
UnixPath dir = (UnixPath)obj;
282
283
// check file is directory
284
UnixFileAttributes attrs = null;
285
try {
286
attrs = UnixFileAttributes.get(dir, true);
287
} catch (UnixException x) {
288
return x.asIOException(dir);
289
}
290
if (!attrs.isDirectory()) {
291
return new NotDirectoryException(dir.getPathForExceptionMessage());
292
}
293
294
// if already registered then update the events and return existing key
295
UnixFileKey fileKey = attrs.fileKey();
296
SolarisWatchKey watchKey = fileKey2WatchKey.get(fileKey);
297
if (watchKey != null) {
298
try {
299
updateEvents(watchKey, events);
300
} catch (UnixException x) {
301
return x.asIOException(dir);
302
}
303
return watchKey;
304
}
305
306
// register directory
307
long object = 0L;
308
try {
309
object = registerImpl(dir, (FILE_MODIFIED | FILE_ATTRIB));
310
} catch (UnixException x) {
311
return x.asIOException(dir);
312
}
313
314
// create watch key and insert it into maps
315
watchKey = new SolarisWatchKey(watcher, dir, fileKey, object, events);
316
object2Node.put(object, watchKey);
317
fileKey2WatchKey.put(fileKey, watchKey);
318
319
// register all entries in directory
320
registerChildren(dir, watchKey, false, false);
321
322
return watchKey;
323
}
324
325
// release resources for single entry
326
void releaseChild(EntryNode node) {
327
long object = node.object();
328
if (object != 0L) {
329
object2Node.remove(object);
330
releaseObject(object, true);
331
node.setObject(0L);
332
}
333
}
334
335
// release resources for entries in directory
336
void releaseChildren(SolarisWatchKey key) {
337
for (EntryNode node: key.children().values()) {
338
releaseChild(node);
339
}
340
}
341
342
// cancel single key
343
@Override
344
void implCancelKey(WatchKey obj) {
345
SolarisWatchKey key = (SolarisWatchKey)obj;
346
if (key.isValid()) {
347
fileKey2WatchKey.remove(key.getFileKey());
348
349
// release resources for entries
350
releaseChildren(key);
351
352
// release resources for directory
353
long object = key.object();
354
object2Node.remove(object);
355
releaseObject(object, true);
356
357
// and finally invalidate the key
358
key.invalidate();
359
}
360
}
361
362
// close watch service
363
@Override
364
void implCloseAll() {
365
// release all native resources
366
for (Long object: object2Node.keySet()) {
367
releaseObject(object, true);
368
}
369
370
// invalidate all keys
371
for (Map.Entry<UnixFileKey,SolarisWatchKey> entry: fileKey2WatchKey.entrySet()) {
372
entry.getValue().invalidate();
373
}
374
375
// clean-up
376
object2Node.clear();
377
fileKey2WatchKey.clear();
378
379
// free global resources
380
unsafe.freeMemory(bufferAddress);
381
UnixNativeDispatcher.close(port);
382
}
383
384
/**
385
* Poller main loop. Blocks on port_getn waiting for events and then
386
* processes them.
387
*/
388
@Override
389
public void run() {
390
try {
391
for (;;) {
392
int n = portGetn(port, bufferAddress, MAX_EVENT_COUNT);
393
assert n > 0;
394
395
long address = bufferAddress;
396
for (int i=0; i<n; i++) {
397
boolean shutdown = processEvent(address);
398
if (shutdown)
399
return;
400
address += SIZEOF_PORT_EVENT;
401
}
402
}
403
} catch (UnixException x) {
404
x.printStackTrace();
405
}
406
}
407
408
/**
409
* Process a single port_event
410
*
411
* Returns true if poller thread is requested to shutdown.
412
*/
413
boolean processEvent(long address) {
414
// pe->portev_source
415
short source = unsafe.getShort(address + OFFSETOF_SOURCE);
416
// pe->portev_object
417
long object = unsafe.getAddress(address + OFFSETOF_OBJECT);
418
// pe->portev_events
419
int events = unsafe.getInt(address + OFFSETOF_EVENTS);
420
421
// user event is trigger to process pending requests
422
if (source != PORT_SOURCE_FILE) {
423
if (source == PORT_SOURCE_USER) {
424
// process any pending requests
425
boolean shutdown = processRequests();
426
if (shutdown)
427
return true;
428
}
429
return false;
430
}
431
432
// lookup object to get Node
433
Node node = object2Node.get(object);
434
if (node == null) {
435
// should not happen
436
return false;
437
}
438
439
// As a workaround for 6642290 and 6636438/6636412 we don't use
440
// FILE_EXCEPTION events to tell use not to register the file.
441
// boolean reregister = (events & FILE_EXCEPTION) == 0;
442
boolean reregister = true;
443
444
// If node is EntryNode then event relates to entry in directory
445
// If node is a SolarisWatchKey (DirectoryNode) then event relates
446
// to a watched directory.
447
boolean isDirectory = (node instanceof SolarisWatchKey);
448
if (isDirectory) {
449
processDirectoryEvents((SolarisWatchKey)node, events);
450
} else {
451
boolean ignore = processEntryEvents((EntryNode)node, events);
452
if (ignore)
453
reregister = false;
454
}
455
456
// need to re-associate to get further events
457
if (reregister) {
458
try {
459
events = FILE_MODIFIED | FILE_ATTRIB;
460
if (!isDirectory) events |= FILE_NOFOLLOW;
461
portAssociate(port,
462
PORT_SOURCE_FILE,
463
object,
464
events);
465
} catch (UnixException x) {
466
// unable to re-register
467
reregister = false;
468
}
469
}
470
471
// object is not re-registered so release resources. If
472
// object is a watched directory then signal key
473
if (!reregister) {
474
// release resources
475
object2Node.remove(object);
476
releaseObject(object, false);
477
478
// if watch key then signal it
479
if (isDirectory) {
480
SolarisWatchKey key = (SolarisWatchKey)node;
481
fileKey2WatchKey.remove( key.getFileKey() );
482
key.invalidate();
483
key.signal();
484
} else {
485
// if entry then remove it from parent
486
EntryNode entry = (EntryNode)node;
487
SolarisWatchKey key = (SolarisWatchKey)entry.parent();
488
key.removeChild(entry.name());
489
}
490
}
491
492
return false;
493
}
494
495
/**
496
* Process directory events. If directory is modified then re-scan
497
* directory to register any new entries
498
*/
499
void processDirectoryEvents(SolarisWatchKey key, int mask) {
500
if ((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) {
501
registerChildren(key.getDirectory(), key,
502
key.events().contains(StandardWatchEventKinds.ENTRY_CREATE),
503
key.events().contains(StandardWatchEventKinds.ENTRY_DELETE));
504
}
505
}
506
507
/**
508
* Process events for entries in registered directories. Returns {@code
509
* true} if events are ignored because the watch key has been cancelled.
510
*/
511
boolean processEntryEvents(EntryNode node, int mask) {
512
SolarisWatchKey key = (SolarisWatchKey)node.parent();
513
Set<? extends WatchEvent.Kind<?>> events = key.events();
514
if (events == null) {
515
// key has been cancelled so ignore event
516
return true;
517
}
518
519
// entry modified
520
if (((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) &&
521
events.contains(StandardWatchEventKinds.ENTRY_MODIFY))
522
{
523
key.signalEvent(StandardWatchEventKinds.ENTRY_MODIFY, node.name());
524
}
525
526
527
return false;
528
}
529
530
/**
531
* Registers all entries in the given directory
532
*
533
* The {@code sendCreateEvents} and {@code sendDeleteEvents} parameters
534
* indicates if ENTRY_CREATE and ENTRY_DELETE events should be queued
535
* when new entries are found. When initially registering a directory
536
* they will always be false. When re-scanning a directory then it
537
* depends on if the events are enabled or not.
538
*/
539
void registerChildren(UnixPath dir,
540
SolarisWatchKey parent,
541
boolean sendCreateEvents,
542
boolean sendDeleteEvents)
543
{
544
boolean isModifyEnabled =
545
parent.events().contains(StandardWatchEventKinds.ENTRY_MODIFY) ;
546
547
// reset visited flag on entries so that we can detect file deletes
548
for (EntryNode node: parent.children().values()) {
549
node.setVisited(false);
550
}
551
552
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
553
for (Path entry: stream) {
554
Path name = entry.getFileName();
555
556
// skip entry if already registered
557
EntryNode node = parent.getChild(name);
558
if (node != null) {
559
node.setVisited(true);
560
continue;
561
}
562
563
// new entry found
564
565
long object = 0L;
566
int errno = 0;
567
boolean addNode = false;
568
569
// if ENTRY_MODIFY enabled then we register the entry for events
570
if (isModifyEnabled) {
571
try {
572
UnixPath path = (UnixPath)entry;
573
int events = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB);
574
object = registerImpl(path, events);
575
addNode = true;
576
} catch (UnixException x) {
577
errno = x.errno();
578
}
579
} else {
580
addNode = true;
581
}
582
583
if (addNode) {
584
// create node
585
node = new EntryNode(object, (UnixPath)entry.getFileName(), parent);
586
node.setVisited(true);
587
// tell the parent about it
588
parent.addChild(entry.getFileName(), node);
589
if (object != 0L)
590
object2Node.put(object, node);
591
}
592
593
// send ENTRY_CREATE event for the new file
594
// send ENTRY_DELETE event for files that were deleted immediately
595
boolean deleted = (errno == ENOENT);
596
if (sendCreateEvents && (addNode || deleted))
597
parent.signalEvent(StandardWatchEventKinds.ENTRY_CREATE, name);
598
if (sendDeleteEvents && deleted)
599
parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, name);
600
601
}
602
} catch (DirectoryIteratorException | IOException x) {
603
// queue OVERFLOW event so that user knows to re-scan directory
604
parent.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
605
return;
606
}
607
608
// clean-up and send ENTRY_DELETE events for any entries that were
609
// not found
610
Iterator<Map.Entry<Path,EntryNode>> iterator =
611
parent.children().entrySet().iterator();
612
while (iterator.hasNext()) {
613
Map.Entry<Path,EntryNode> entry = iterator.next();
614
EntryNode node = entry.getValue();
615
if (!node.isVisited()) {
616
long object = node.object();
617
if (object != 0L) {
618
object2Node.remove(object);
619
releaseObject(object, true);
620
}
621
if (sendDeleteEvents)
622
parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, node.name());
623
iterator.remove();
624
}
625
}
626
}
627
628
/**
629
* Update watch key's events. If ENTRY_MODIFY changes to be enabled
630
* then register each file in the direcory; If ENTRY_MODIFY changed to
631
* be disabled then unregister each file.
632
*/
633
void updateEvents(SolarisWatchKey key, Set<? extends WatchEvent.Kind<?>> events)
634
throws UnixException
635
{
636
637
// update events, rembering if ENTRY_MODIFY was previously
638
// enabled or disabled.
639
boolean oldModifyEnabled = key.events()
640
.contains(StandardWatchEventKinds.ENTRY_MODIFY);
641
key.setEvents(events);
642
643
// check if ENTRY_MODIFY has changed
644
boolean newModifyEnabled = events
645
.contains(StandardWatchEventKinds.ENTRY_MODIFY);
646
if (newModifyEnabled != oldModifyEnabled) {
647
UnixException ex = null;
648
for (EntryNode node: key.children().values()) {
649
if (newModifyEnabled) {
650
// register
651
UnixPath path = key.getDirectory().resolve(node.name());
652
int ev = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB);
653
try {
654
long object = registerImpl(path, ev);
655
object2Node.put(object, node);
656
node.setObject(object);
657
} catch (UnixException x) {
658
// if file has been deleted then it will be detected
659
// as a FILE_MODIFIED event on the directory
660
if (x.errno() != ENOENT) {
661
ex = x;
662
break;
663
}
664
}
665
} else {
666
// unregister
667
releaseChild(node);
668
}
669
}
670
671
// an error occurred
672
if (ex != null) {
673
releaseChildren(key);
674
throw ex;
675
}
676
}
677
}
678
679
/**
680
* Calls port_associate to register the given path.
681
* Returns pointer to fileobj structure that is allocated for
682
* the registration.
683
*/
684
long registerImpl(UnixPath dir, int events)
685
throws UnixException
686
{
687
// allocate memory for the path (file_obj->fo_name field)
688
byte[] path = dir.getByteArrayForSysCalls();
689
int len = path.length;
690
long name = unsafe.allocateMemory(len+1);
691
unsafe.copyMemory(path, Unsafe.ARRAY_BYTE_BASE_OFFSET, null,
692
name, (long)len);
693
unsafe.putByte(name + len, (byte)0);
694
695
// allocate memory for filedatanode structure - this is the object
696
// to port_associate
697
long object = unsafe.allocateMemory(SIZEOF_FILEOBJ);
698
unsafe.setMemory(null, object, SIZEOF_FILEOBJ, (byte)0);
699
unsafe.putAddress(object + OFFSET_FO_NAME, name);
700
701
// associate the object with the port
702
try {
703
portAssociate(port,
704
PORT_SOURCE_FILE,
705
object,
706
events);
707
} catch (UnixException x) {
708
// debugging
709
if (x.errno() == EAGAIN) {
710
System.err.println("The maximum number of objects associated "+
711
"with the port has been reached");
712
}
713
714
unsafe.freeMemory(name);
715
unsafe.freeMemory(object);
716
throw x;
717
}
718
return object;
719
}
720
721
/**
722
* Frees all resources for an file_obj object; optionally remove
723
* association from port
724
*/
725
void releaseObject(long object, boolean dissociate) {
726
// remove association
727
if (dissociate) {
728
try {
729
portDissociate(port, PORT_SOURCE_FILE, object);
730
} catch (UnixException x) {
731
// ignore
732
}
733
}
734
735
// free native memory
736
long name = unsafe.getAddress(object + OFFSET_FO_NAME);
737
unsafe.freeMemory(name);
738
unsafe.freeMemory(object);
739
}
740
}
741
742
/**
743
* A node with native (file_obj) resources
744
*/
745
private static interface Node {
746
long object();
747
}
748
749
/**
750
* A directory node with a map of the entries in the directory
751
*/
752
private static interface DirectoryNode extends Node {
753
void addChild(Path name, EntryNode node);
754
void removeChild(Path name);
755
EntryNode getChild(Path name);
756
}
757
758
/**
759
* An implementation of a node that is an entry in a directory.
760
*/
761
private static class EntryNode implements Node {
762
private long object;
763
private final UnixPath name;
764
private final DirectoryNode parent;
765
private boolean visited;
766
767
EntryNode(long object, UnixPath name, DirectoryNode parent) {
768
this.object = object;
769
this.name = name;
770
this.parent = parent;
771
}
772
773
@Override
774
public long object() {
775
return object;
776
}
777
778
void setObject(long ptr) {
779
this.object = ptr;
780
}
781
782
UnixPath name() {
783
return name;
784
}
785
786
DirectoryNode parent() {
787
return parent;
788
}
789
790
boolean isVisited() {
791
return visited;
792
}
793
794
void setVisited(boolean v) {
795
this.visited = v;
796
}
797
}
798
799
// -- native methods --
800
801
private static native void init();
802
803
private static native int portCreate() throws UnixException;
804
805
private static native void portAssociate(int port, int source, long object, int events)
806
throws UnixException;
807
808
private static native void portDissociate(int port, int source, long object)
809
throws UnixException;
810
811
private static native void portSend(int port, int events)
812
throws UnixException;
813
814
private static native int portGetn(int port, long address, int max)
815
throws UnixException;
816
817
static {
818
AccessController.doPrivileged(new PrivilegedAction<Void>() {
819
public Void run() {
820
System.loadLibrary("nio");
821
return null;
822
}});
823
init();
824
}
825
}
826
827