Merge
This commit is contained in:
commit
77e24ab76e
1
.hgtags
1
.hgtags
@ -476,3 +476,4 @@ dfa46cfe56346884a61efdc30dc50f7505d66761 jdk-11+1
|
||||
1fd4d6068f54561cfc67d54fc9ca84af7212c4f8 jdk-11+3
|
||||
e59941f7247d451fa7df9eaef3fce0f492f8420c jdk-11+4
|
||||
d5c43e9f08fb9a7c74aae0d48daf17f2ad2afaef jdk-11+5
|
||||
3acb379b86725c47e7f33358cb22efa8752ae532 jdk-11+6
|
||||
|
@ -40,7 +40,7 @@
|
||||
$ make run-test-jdk_lang JTREG="JOBS=8"
|
||||
$ make run-test TEST=jdk_lang
|
||||
$ make run-test-only TEST="gtest:LogTagSet gtest:LogTagSetDescriptions" GTEST="REPEAT=-1"
|
||||
$ make run-test TEST="hotspot/test:hotspot_gc" JTREG="JOBS=1;TIMEOUT=8;VM_OTIONS=-XshowSettings -Xlog:gc+ref=debug"
|
||||
$ make run-test TEST="hotspot/test:hotspot_gc" JTREG="JOBS=1;TIMEOUT=8;VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"
|
||||
$ make run-test TEST="jtreg:hotspot/test:hotspot_gc hotspot/test/native_sanity/JniVersion.java"
|
||||
$ make exploded-run-test TEST=hotspot_tier1</code></pre>
|
||||
<h3 id="configuration">Configuration</h3>
|
||||
@ -77,8 +77,8 @@ TEST FAILURE</code></pre>
|
||||
<h2 id="test-suite-control">Test suite control</h2>
|
||||
<p>It is possible to control various aspects of the test suites using make control variables.</p>
|
||||
<p>These variables use a keyword=value approach to allow multiple values to be set. So, for instance, <code>JTREG="JOBS=1;TIMEOUT=8"</code> will set the JTReg concurrency level to 1 and the timeout factor to 8. This is equivalent to setting <code>JTREG_JOBS=1 JTREG_TIMEOUT=8</code>, but using the keyword format means that the <code>JTREG</code> variable is parsed and verified for correctness, so <code>JTREG="TMIEOUT=8"</code> would give an error, while <code>JTREG_TMIEOUT=8</code> would just pass unnoticed.</p>
|
||||
<p>To separate multiple keyword=value pairs, use <code>;</code> (semicolon). Since the shell normally eats <code>;</code>, the recommended usage is to write the assignment inside qoutes, e.g. <code>JTREG="...;..."</code>. This will also make sure spaces are preserved, as in <code>JTREG="VM_OTIONS=-XshowSettings -Xlog:gc+ref=debug"</code>.</p>
|
||||
<p>(Other ways are possible, e.g. using backslash: <code>JTREG=JOBS=1\;TIMEOUT=8</code>. Also, as a special technique, the string <code>%20</code> will be replaced with space for certain options, e.g. <code>JTREG=VM_OTIONS=-XshowSettings%20-Xlog:gc+ref=debug</code>. This can be useful if you have layers of scripts and have trouble getting proper quoting of command line arguments through.)</p>
|
||||
<p>To separate multiple keyword=value pairs, use <code>;</code> (semicolon). Since the shell normally eats <code>;</code>, the recommended usage is to write the assignment inside qoutes, e.g. <code>JTREG="...;..."</code>. This will also make sure spaces are preserved, as in <code>JTREG="VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"</code>.</p>
|
||||
<p>(Other ways are possible, e.g. using backslash: <code>JTREG=JOBS=1\;TIMEOUT=8</code>. Also, as a special technique, the string <code>%20</code> will be replaced with space for certain options, e.g. <code>JTREG=VM_OPTIONS=-XshowSettings%20-Xlog:gc+ref=debug</code>. This can be useful if you have layers of scripts and have trouble getting proper quoting of command line arguments through.)</p>
|
||||
<p>As far as possible, the names of the keywords have been standardized between test suites.</p>
|
||||
<h3 id="jtreg-keywords">JTReg keywords</h3>
|
||||
<h4 id="jobs">JOBS</h4>
|
||||
|
@ -18,7 +18,7 @@ Some example command-lines:
|
||||
$ make run-test-jdk_lang JTREG="JOBS=8"
|
||||
$ make run-test TEST=jdk_lang
|
||||
$ make run-test-only TEST="gtest:LogTagSet gtest:LogTagSetDescriptions" GTEST="REPEAT=-1"
|
||||
$ make run-test TEST="hotspot/test:hotspot_gc" JTREG="JOBS=1;TIMEOUT=8;VM_OTIONS=-XshowSettings -Xlog:gc+ref=debug"
|
||||
$ make run-test TEST="hotspot/test:hotspot_gc" JTREG="JOBS=1;TIMEOUT=8;VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"
|
||||
$ make run-test TEST="jtreg:hotspot/test:hotspot_gc hotspot/test/native_sanity/JniVersion.java"
|
||||
$ make exploded-run-test TEST=hotspot_tier1
|
||||
|
||||
@ -140,11 +140,11 @@ pass unnoticed.
|
||||
To separate multiple keyword=value pairs, use `;` (semicolon). Since the shell
|
||||
normally eats `;`, the recommended usage is to write the assignment inside
|
||||
qoutes, e.g. `JTREG="...;..."`. This will also make sure spaces are preserved,
|
||||
as in `JTREG="VM_OTIONS=-XshowSettings -Xlog:gc+ref=debug"`.
|
||||
as in `JTREG="VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"`.
|
||||
|
||||
(Other ways are possible, e.g. using backslash: `JTREG=JOBS=1\;TIMEOUT=8`.
|
||||
Also, as a special technique, the string `%20` will be replaced with space for
|
||||
certain options, e.g. `JTREG=VM_OTIONS=-XshowSettings%20-Xlog:gc+ref=debug`.
|
||||
certain options, e.g. `JTREG=VM_OPTIONS=-XshowSettings%20-Xlog:gc+ref=debug`.
|
||||
This can be useful if you have layers of scripts and have trouble getting
|
||||
proper quoting of command line arguments through.)
|
||||
|
||||
|
@ -23,101 +23,50 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
LIBJSOUND_SRC_DIRS := \
|
||||
LIBJSOUND_SRC_DIRS := $(wildcard \
|
||||
$(TOPDIR)/src/java.desktop/share/native/libjsound \
|
||||
$(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libjsound \
|
||||
#
|
||||
$(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS)/native/libjsound \
|
||||
)
|
||||
|
||||
LIBJSOUND_CFLAGS := \
|
||||
-I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \
|
||||
$(LIBJAVA_HEADER_FLAGS) \
|
||||
$(foreach dir, $(LIBJSOUND_SRC_DIRS), -I$(dir)) \
|
||||
-DUSE_PORTS=TRUE \
|
||||
-DUSE_DAUDIO=TRUE \
|
||||
#
|
||||
|
||||
LIBJSOUND_SRC_FILES := Utilities.c Platform.c
|
||||
|
||||
EXTRA_SOUND_JNI_LIBS :=
|
||||
|
||||
LIBJSOUND_MIDIFILES := \
|
||||
MidiInDevice.c \
|
||||
MidiInDeviceProvider.c \
|
||||
MidiOutDevice.c \
|
||||
MidiOutDeviceProvider.c \
|
||||
PlatformMidi.c
|
||||
|
||||
# files needed for ports
|
||||
LIBJSOUND_PORTFILES := \
|
||||
PortMixerProvider.c \
|
||||
PortMixer.c
|
||||
|
||||
# files needed for direct audio
|
||||
LIBJSOUND_DAUDIOFILES := \
|
||||
DirectAudioDeviceProvider.c \
|
||||
DirectAudioDevice.c
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
EXTRA_SOUND_JNI_LIBS += jsoundds
|
||||
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_WINDOWS \
|
||||
ifneq ($(OPENJDK_TARGET_OS), solaris)
|
||||
LIBJSOUND_CFLAGS += \
|
||||
-DUSE_PLATFORM_MIDI_OUT=TRUE \
|
||||
-DUSE_PLATFORM_MIDI_IN=TRUE \
|
||||
-DUSE_PORTS=TRUE
|
||||
LIBJSOUND_SRC_FILES += \
|
||||
PLATFORM_API_WinOS_Charset_Util.cpp \
|
||||
PLATFORM_API_WinOS_MidiIn.cpp \
|
||||
PLATFORM_API_WinOS_MidiOut.c \
|
||||
PLATFORM_API_WinOS_Util.c \
|
||||
PLATFORM_API_WinOS_Ports.c
|
||||
LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES)
|
||||
LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES)
|
||||
endif # OPENJDK_TARGET_OS windows
|
||||
#
|
||||
endif
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_WINDOWS
|
||||
endif
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), linux)
|
||||
EXTRA_SOUND_JNI_LIBS += jsoundalsa
|
||||
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_LINUX
|
||||
endif # OPENJDK_TARGET_OS linux
|
||||
endif
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), aix)
|
||||
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_AIX
|
||||
endif # OPENJDK_TARGET_OS aix
|
||||
endif
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
LIBJSOUND_TOOLCHAIN := TOOLCHAIN_LINK_CXX
|
||||
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_MACOSX \
|
||||
-DUSE_PORTS=TRUE \
|
||||
-DUSE_DAUDIO=TRUE \
|
||||
-DUSE_PLATFORM_MIDI_OUT=TRUE \
|
||||
-DUSE_PLATFORM_MIDI_IN=TRUE
|
||||
LIBJSOUND_SRC_DIRS += $(TOPDIR)/src/java.desktop/macosx/native/libjsound
|
||||
LIBJSOUND_SRC_FILES += \
|
||||
PLATFORM_API_MacOSX_Utils.cpp \
|
||||
PLATFORM_API_MacOSX_PCM.cpp \
|
||||
PLATFORM_API_MacOSX_Ports.cpp \
|
||||
PLATFORM_API_MacOSX_MidiIn.c \
|
||||
PLATFORM_API_MacOSX_MidiOut.c \
|
||||
PLATFORM_API_MacOSX_MidiUtils.c
|
||||
LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES)
|
||||
LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES)
|
||||
LIBJSOUND_SRC_FILES += $(LIBJSOUND_DAUDIOFILES)
|
||||
endif # OPENJDK_TARGET_OS macosx
|
||||
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_MACOSX
|
||||
endif
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), solaris)
|
||||
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_SOLARIS \
|
||||
-DUSE_PORTS=TRUE \
|
||||
-DUSE_DAUDIO=TRUE
|
||||
LIBJSOUND_SRC_FILES += \
|
||||
PLATFORM_API_SolarisOS_Utils.c \
|
||||
PLATFORM_API_SolarisOS_Ports.c \
|
||||
PLATFORM_API_SolarisOS_PCM.c
|
||||
LIBJSOUND_SRC_FILES += $(LIBJSOUND_MIDIFILES)
|
||||
LIBJSOUND_SRC_FILES += $(LIBJSOUND_PORTFILES)
|
||||
LIBJSOUND_SRC_FILES += $(LIBJSOUND_DAUDIOFILES)
|
||||
endif # OPENJDK_TARGET_OS solaris
|
||||
|
||||
LIBJSOUND_CFLAGS += -DEXTRA_SOUND_JNI_LIBS='"$(EXTRA_SOUND_JNI_LIBS)"'
|
||||
LIBJSOUND_CFLAGS += -DX_PLATFORM=X_SOLARIS
|
||||
endif
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBJSOUND, \
|
||||
NAME := jsound, \
|
||||
SRC := $(LIBJSOUND_SRC_DIRS), \
|
||||
INCLUDE_FILES := $(LIBJSOUND_SRC_FILES), \
|
||||
TOOLCHAIN := $(LIBJSOUND_TOOLCHAIN), \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
@ -127,10 +76,11 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJSOUND, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LIBS_unix := -ljava -ljvm, \
|
||||
LIBS_linux := $(ALSA_LIBS), \
|
||||
LIBS_macosx := -framework CoreAudio -framework CoreFoundation \
|
||||
-framework CoreServices -framework AudioUnit $(LIBCXX) \
|
||||
-framework CoreMIDI -framework AudioToolbox, \
|
||||
LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib winmm.lib, \
|
||||
-framework CoreServices -framework AudioUnit \
|
||||
-framework CoreMIDI -framework AudioToolbox $(LIBCXX), \
|
||||
LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib dsound.lib winmm.lib user32.lib ole32.lib, \
|
||||
))
|
||||
|
||||
$(BUILD_LIBJSOUND): $(call FindLib, java.base, java)
|
||||
@ -138,61 +88,3 @@ $(BUILD_LIBJSOUND): $(call FindLib, java.base, java)
|
||||
TARGETS += $(BUILD_LIBJSOUND)
|
||||
|
||||
##########################################################################################
|
||||
|
||||
ifneq ($(filter jsoundalsa, $(EXTRA_SOUND_JNI_LIBS)), )
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBJSOUNDALSA, \
|
||||
NAME := jsoundalsa, \
|
||||
SRC := $(LIBJSOUND_SRC_DIRS), \
|
||||
INCLUDE_FILES := Utilities.c $(LIBJSOUND_MIDIFILES) $(LIBJSOUND_PORTFILES) \
|
||||
$(LIBJSOUND_DAUDIOFILES) \
|
||||
PLATFORM_API_LinuxOS_ALSA_CommonUtils.c \
|
||||
PLATFORM_API_LinuxOS_ALSA_PCM.c \
|
||||
PLATFORM_API_LinuxOS_ALSA_PCMUtils.c \
|
||||
PLATFORM_API_LinuxOS_ALSA_MidiIn.c \
|
||||
PLATFORM_API_LinuxOS_ALSA_MidiOut.c \
|
||||
PLATFORM_API_LinuxOS_ALSA_MidiUtils.c \
|
||||
PLATFORM_API_LinuxOS_ALSA_Ports.c, \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(ALSA_CFLAGS) \
|
||||
$(LIBJSOUND_CFLAGS) \
|
||||
-DUSE_DAUDIO=TRUE \
|
||||
-DUSE_PORTS=TRUE \
|
||||
-DUSE_PLATFORM_MIDI_OUT=TRUE \
|
||||
-DUSE_PLATFORM_MIDI_IN=TRUE, \
|
||||
MAPFILE := $(TOPDIR)/make/mapfiles/libjsoundalsa/mapfile-vers, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LIBS := $(ALSA_LIBS) -ljava -ljvm, \
|
||||
))
|
||||
|
||||
$(BUILD_LIBJSOUNDALSA): $(call FindLib, java.base, java)
|
||||
|
||||
TARGETS += $(BUILD_LIBJSOUNDALSA)
|
||||
|
||||
endif
|
||||
|
||||
##########################################################################################
|
||||
|
||||
ifneq ($(filter jsoundds, $(EXTRA_SOUND_JNI_LIBS)), )
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBJSOUNDDS, \
|
||||
NAME := jsoundds, \
|
||||
SRC := $(LIBJSOUND_SRC_DIRS), \
|
||||
INCLUDE_FILES := Utilities.c $(LIBJSOUND_DAUDIOFILES) \
|
||||
PLATFORM_API_WinOS_Charset_Util.cpp \
|
||||
PLATFORM_API_WinOS_DirectSound.cpp, \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
$(LIBJSOUND_CFLAGS) \
|
||||
-DUSE_DAUDIO=TRUE, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LIBS := $(JDKLIB_LIBS) dsound.lib winmm.lib user32.lib ole32.lib, \
|
||||
))
|
||||
|
||||
$(BUILD_LIBJSOUNDDS): $(call FindLib, java.base, java)
|
||||
|
||||
TARGETS += $(BUILD_LIBJSOUNDDS)
|
||||
|
||||
endif
|
||||
|
@ -65,8 +65,6 @@ SUNWprivate_1.1 {
|
||||
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices;
|
||||
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor;
|
||||
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion;
|
||||
Java_com_sun_media_sound_Platform_nGetExtraLibraries;
|
||||
Java_com_sun_media_sound_Platform_nGetLibraryForFeature;
|
||||
Java_com_sun_media_sound_Platform_nIsBigEndian;
|
||||
Java_com_sun_media_sound_PortMixer_nClose;
|
||||
Java_com_sun_media_sound_PortMixer_nControlGetFloatValue;
|
||||
|
@ -1,82 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Define library interface.
|
||||
|
||||
SUNWprivate_1.1 {
|
||||
global:
|
||||
Java_com_sun_media_sound_DirectAudioDeviceProvider_nGetNumDevices;
|
||||
Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nAvailable;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nClose;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nFlush;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nGetBufferSize;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nGetBytePosition;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nGetFormats;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nIsStillDraining;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nOpen;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nRead;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nRequiresServicing;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nService;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nSetBytePosition;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nStart;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nStop;
|
||||
Java_com_sun_media_sound_DirectAudioDevice_nWrite;
|
||||
Java_com_sun_media_sound_MidiInDeviceProvider_nGetDescription;
|
||||
Java_com_sun_media_sound_MidiInDeviceProvider_nGetName;
|
||||
Java_com_sun_media_sound_MidiInDeviceProvider_nGetNumDevices;
|
||||
Java_com_sun_media_sound_MidiInDeviceProvider_nGetVendor;
|
||||
Java_com_sun_media_sound_MidiInDeviceProvider_nGetVersion;
|
||||
Java_com_sun_media_sound_MidiInDevice_nClose;
|
||||
Java_com_sun_media_sound_MidiInDevice_nGetMessages;
|
||||
Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp;
|
||||
Java_com_sun_media_sound_MidiInDevice_nOpen;
|
||||
Java_com_sun_media_sound_MidiInDevice_nStart;
|
||||
Java_com_sun_media_sound_MidiInDevice_nStop;
|
||||
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetDescription;
|
||||
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetName;
|
||||
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetNumDevices;
|
||||
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVendor;
|
||||
Java_com_sun_media_sound_MidiOutDeviceProvider_nGetVersion;
|
||||
Java_com_sun_media_sound_MidiOutDevice_nClose;
|
||||
Java_com_sun_media_sound_MidiOutDevice_nGetTimeStamp;
|
||||
Java_com_sun_media_sound_MidiOutDevice_nOpen;
|
||||
Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage;
|
||||
Java_com_sun_media_sound_MidiOutDevice_nSendShortMessage;
|
||||
Java_com_sun_media_sound_PortMixerProvider_nGetNumDevices;
|
||||
Java_com_sun_media_sound_PortMixerProvider_nNewPortMixerInfo;
|
||||
Java_com_sun_media_sound_PortMixer_nClose;
|
||||
Java_com_sun_media_sound_PortMixer_nControlGetFloatValue;
|
||||
Java_com_sun_media_sound_PortMixer_nControlGetIntValue;
|
||||
Java_com_sun_media_sound_PortMixer_nControlSetFloatValue;
|
||||
Java_com_sun_media_sound_PortMixer_nControlSetIntValue;
|
||||
Java_com_sun_media_sound_PortMixer_nGetControls;
|
||||
Java_com_sun_media_sound_PortMixer_nGetPortCount;
|
||||
Java_com_sun_media_sound_PortMixer_nGetPortName;
|
||||
Java_com_sun_media_sound_PortMixer_nGetPortType;
|
||||
Java_com_sun_media_sound_PortMixer_nOpen;
|
||||
local:
|
||||
*;
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -37,23 +37,12 @@ SUNWprivate_1.1 {
|
||||
Java_sun_nio_ch_DatagramDispatcher_readv0;
|
||||
Java_sun_nio_ch_DatagramDispatcher_write0;
|
||||
Java_sun_nio_ch_DatagramDispatcher_writev0;
|
||||
Java_sun_nio_ch_EPollArrayWrapper_epollCreate;
|
||||
Java_sun_nio_ch_EPollArrayWrapper_epollCtl;
|
||||
Java_sun_nio_ch_EPollArrayWrapper_epollWait;
|
||||
Java_sun_nio_ch_EPollArrayWrapper_init;
|
||||
Java_sun_nio_ch_EPollArrayWrapper_interrupt;
|
||||
Java_sun_nio_ch_EPollArrayWrapper_offsetofData;
|
||||
Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent;
|
||||
Java_sun_nio_ch_EPoll_eventSize;
|
||||
Java_sun_nio_ch_EPoll_eventsOffset;
|
||||
Java_sun_nio_ch_EPoll_dataOffset;
|
||||
Java_sun_nio_ch_EPoll_epollCreate;
|
||||
Java_sun_nio_ch_EPoll_epollCtl;
|
||||
Java_sun_nio_ch_EPoll_epollWait;
|
||||
Java_sun_nio_ch_EPollPort_close0;
|
||||
Java_sun_nio_ch_EPollPort_drain1;
|
||||
Java_sun_nio_ch_EPollPort_interrupt;
|
||||
Java_sun_nio_ch_EPollPort_socketpair;
|
||||
Java_sun_nio_ch_EPoll_create;
|
||||
Java_sun_nio_ch_EPoll_ctl;
|
||||
Java_sun_nio_ch_EPoll_wait;
|
||||
Java_sun_nio_ch_FileChannelImpl_initIDs;
|
||||
Java_sun_nio_ch_FileChannelImpl_map0;
|
||||
Java_sun_nio_ch_FileChannelImpl_position0;
|
||||
@ -95,6 +84,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_nio_ch_IOUtil_makePipe;
|
||||
Java_sun_nio_ch_IOUtil_randomBytes;
|
||||
Java_sun_nio_ch_IOUtil_setfdVal;
|
||||
Java_sun_nio_ch_IOUtil_write1;
|
||||
Java_sun_nio_ch_NativeThread_current;
|
||||
Java_sun_nio_ch_NativeThread_init;
|
||||
Java_sun_nio_ch_NativeThread_signal;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -42,7 +42,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_nio_ch_FileChannelImpl_position0;
|
||||
Java_sun_nio_ch_FileChannelImpl_transferTo0;
|
||||
Java_sun_nio_ch_FileChannelImpl_unmap0;
|
||||
Java_sun_nio_ch_FileDispatcherImpl_allocate0;
|
||||
Java_sun_nio_ch_FileDispatcherImpl_allocate0;
|
||||
Java_sun_nio_ch_FileDispatcherImpl_close0;
|
||||
Java_sun_nio_ch_FileDispatcherImpl_closeIntFD;
|
||||
Java_sun_nio_ch_FileDispatcherImpl_force0;
|
||||
@ -71,117 +71,115 @@ SUNWprivate_1.1 {
|
||||
Java_sun_nio_ch_IOUtil_configureBlocking;
|
||||
Java_sun_nio_ch_IOUtil_drain;
|
||||
Java_sun_nio_ch_IOUtil_fdVal;
|
||||
Java_sun_nio_ch_IOUtil_fdLimit;
|
||||
Java_sun_nio_ch_IOUtil_initIDs;
|
||||
Java_sun_nio_ch_IOUtil_iovMax;
|
||||
Java_sun_nio_ch_IOUtil_makePipe;
|
||||
Java_sun_nio_ch_IOUtil_randomBytes;
|
||||
Java_sun_nio_ch_IOUtil_setfdVal;
|
||||
Java_sun_nio_ch_IOUtil_iovMax;
|
||||
Java_sun_nio_ch_KQueue_kqueue;
|
||||
Java_sun_nio_ch_KQueue_keventRegister;
|
||||
Java_sun_nio_ch_KQueue_keventPoll;
|
||||
Java_sun_nio_ch_KQueue_keventSize;
|
||||
Java_sun_nio_ch_KQueue_identOffset;
|
||||
Java_sun_nio_ch_KQueue_filterOffset;
|
||||
Java_sun_nio_ch_KQueue_flagsOffset;
|
||||
Java_sun_nio_ch_KQueuePort_socketpair;
|
||||
Java_sun_nio_ch_KQueuePort_interrupt;
|
||||
Java_sun_nio_ch_KQueuePort_drain1;
|
||||
Java_sun_nio_ch_KQueuePort_close0;
|
||||
Java_sun_nio_ch_NativeThread_current;
|
||||
Java_sun_nio_ch_NativeThread_init;
|
||||
Java_sun_nio_ch_NativeThread_signal;
|
||||
Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0;
|
||||
Java_sun_nio_ch_Net_canJoin6WithIPv4Group0;
|
||||
Java_sun_nio_ch_Net_socket0;
|
||||
Java_sun_nio_ch_Net_bind0;
|
||||
Java_sun_nio_ch_Net_connect0;
|
||||
Java_sun_nio_ch_Net_listen;
|
||||
Java_sun_nio_ch_Net_localPort;
|
||||
Java_sun_nio_ch_Net_localInetAddress;
|
||||
Java_sun_nio_ch_Net_getIntOption0;
|
||||
Java_sun_nio_ch_Net_setIntOption0;
|
||||
Java_sun_nio_ch_IOUtil_write1;
|
||||
Java_sun_nio_ch_KQueue_create;
|
||||
Java_sun_nio_ch_KQueue_register;
|
||||
Java_sun_nio_ch_KQueue_poll;
|
||||
Java_sun_nio_ch_KQueue_keventSize;
|
||||
Java_sun_nio_ch_KQueue_identOffset;
|
||||
Java_sun_nio_ch_KQueue_filterOffset;
|
||||
Java_sun_nio_ch_KQueue_flagsOffset;
|
||||
Java_sun_nio_ch_NativeThread_current;
|
||||
Java_sun_nio_ch_NativeThread_init;
|
||||
Java_sun_nio_ch_NativeThread_signal;
|
||||
Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0;
|
||||
Java_sun_nio_ch_Net_canJoin6WithIPv4Group0;
|
||||
Java_sun_nio_ch_Net_socket0;
|
||||
Java_sun_nio_ch_Net_bind0;
|
||||
Java_sun_nio_ch_Net_connect0;
|
||||
Java_sun_nio_ch_Net_listen;
|
||||
Java_sun_nio_ch_Net_localPort;
|
||||
Java_sun_nio_ch_Net_localInetAddress;
|
||||
Java_sun_nio_ch_Net_getIntOption0;
|
||||
Java_sun_nio_ch_Net_setIntOption0;
|
||||
Java_sun_nio_ch_Net_initIDs;
|
||||
Java_sun_nio_ch_Net_isIPv6Available0;
|
||||
Java_sun_nio_ch_Net_isReusePortAvailable0;
|
||||
Java_sun_nio_ch_Net_joinOrDrop4;
|
||||
Java_sun_nio_ch_Net_blockOrUnblock4;
|
||||
Java_sun_nio_ch_Net_joinOrDrop6;
|
||||
Java_sun_nio_ch_Net_blockOrUnblock6;
|
||||
Java_sun_nio_ch_Net_setInterface4;
|
||||
Java_sun_nio_ch_Net_getInterface4;
|
||||
Java_sun_nio_ch_Net_setInterface6;
|
||||
Java_sun_nio_ch_Net_getInterface6;
|
||||
Java_sun_nio_ch_Net_shutdown;
|
||||
Java_sun_nio_ch_Net_poll;
|
||||
Java_sun_nio_ch_Net_pollinValue;
|
||||
Java_sun_nio_ch_Net_polloutValue;
|
||||
Java_sun_nio_ch_Net_pollerrValue;
|
||||
Java_sun_nio_ch_Net_pollhupValue;
|
||||
Java_sun_nio_ch_Net_pollnvalValue;
|
||||
Java_sun_nio_ch_Net_pollconnValue;
|
||||
Java_sun_nio_ch_Net_joinOrDrop4;
|
||||
Java_sun_nio_ch_Net_blockOrUnblock4;
|
||||
Java_sun_nio_ch_Net_joinOrDrop6;
|
||||
Java_sun_nio_ch_Net_blockOrUnblock6;
|
||||
Java_sun_nio_ch_Net_setInterface4;
|
||||
Java_sun_nio_ch_Net_getInterface4;
|
||||
Java_sun_nio_ch_Net_setInterface6;
|
||||
Java_sun_nio_ch_Net_getInterface6;
|
||||
Java_sun_nio_ch_Net_shutdown;
|
||||
Java_sun_nio_ch_Net_poll;
|
||||
Java_sun_nio_ch_Net_pollinValue;
|
||||
Java_sun_nio_ch_Net_polloutValue;
|
||||
Java_sun_nio_ch_Net_pollerrValue;
|
||||
Java_sun_nio_ch_Net_pollhupValue;
|
||||
Java_sun_nio_ch_Net_pollnvalValue;
|
||||
Java_sun_nio_ch_Net_pollconnValue;
|
||||
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
|
||||
Java_sun_nio_ch_PollArrayWrapper_interrupt;
|
||||
Java_sun_nio_ch_PollArrayWrapper_poll0;
|
||||
Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
|
||||
Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
|
||||
Java_sun_nio_ch_SocketChannelImpl_checkConnect;
|
||||
Java_sun_nio_ch_SocketChannelImpl_sendOutOfBandData;
|
||||
Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0;
|
||||
Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs;
|
||||
Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect;
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_initIDs;
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_getfsstat;
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_fsstatEntry;
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_endfsstat;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_init;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getcwd;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_strerror;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_dup;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_access0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_exists0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_stat0;
|
||||
Java_sun_nio_ch_SocketChannelImpl_sendOutOfBandData;
|
||||
Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0;
|
||||
Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs;
|
||||
Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect;
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_initIDs;
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_getfsstat;
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_fsstatEntry;
|
||||
Java_sun_nio_fs_BsdNativeDispatcher_endfsstat;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_init;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getcwd;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_strerror;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_dup;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_access0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_exists0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_stat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_stat1;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_lstat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fstat;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fstatat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_chmod0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fchmod;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_chown0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_lchown0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fchown;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_utimes0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_futimes;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_open0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_openat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_close0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_read;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_write;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fopen0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fclose;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_opendir0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fdopendir;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_readdir;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_closedir;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_link0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_unlink0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_rename0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_renameat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_mkdir0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_rmdir0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_symlink0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_readlink0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_realpath0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_statvfs0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_pathconf0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fpathconf;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_mknod0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getpwuid;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getgrgid;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0;
|
||||
Java_sun_nio_fs_UnixCopyFile_transfer;
|
||||
handleSocketError;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_lstat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fstat;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fstatat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_chmod0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fchmod;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_chown0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_lchown0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fchown;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_utimes0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_futimes;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_open0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_openat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_close0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_read;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_write;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fopen0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fclose;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_opendir0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fdopendir;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_readdir;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_closedir;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_link0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_unlink0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_rename0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_renameat0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_mkdir0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_rmdir0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_symlink0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_readlink0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_realpath0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_statvfs0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_pathconf0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_fpathconf;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_mknod0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getpwuid;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getgrgid;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0;
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0;
|
||||
Java_sun_nio_fs_UnixCopyFile_transfer;
|
||||
handleSocketError;
|
||||
|
||||
local:
|
||||
*;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,7 +38,6 @@ SUNWprivate_1.1 {
|
||||
Java_sun_nio_ch_DatagramDispatcher_write0;
|
||||
Java_sun_nio_ch_DatagramDispatcher_writev0;
|
||||
Java_sun_nio_ch_DevPollArrayWrapper_init;
|
||||
Java_sun_nio_ch_DevPollArrayWrapper_interrupt;
|
||||
Java_sun_nio_ch_DevPollArrayWrapper_poll0;
|
||||
Java_sun_nio_ch_DevPollArrayWrapper_register;
|
||||
Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple;
|
||||
@ -83,6 +82,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_nio_ch_IOUtil_makePipe;
|
||||
Java_sun_nio_ch_IOUtil_randomBytes;
|
||||
Java_sun_nio_ch_IOUtil_setfdVal;
|
||||
Java_sun_nio_ch_IOUtil_write1;
|
||||
Java_sun_nio_ch_NativeThread_current;
|
||||
Java_sun_nio_ch_NativeThread_init;
|
||||
Java_sun_nio_ch_NativeThread_signal;
|
||||
|
@ -1298,22 +1298,37 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
|
||||
# Find the common images to compare, prioritizing later build stages
|
||||
if [ -d "$THIS/install/jdk" ] && [ -d "$OTHER/install/jdk" ]; then
|
||||
THIS_JDK="$THIS/install/jdk"
|
||||
THIS_JRE="$THIS/install/jre"
|
||||
OTHER_JDK="$OTHER/install/jdk"
|
||||
OTHER_JRE="$OTHER/install/jre"
|
||||
echo "Selecting install images for compare"
|
||||
echo "Selecting install images for JDK compare"
|
||||
if [ -d "$THIS/install/jre" ] && [ -d "$OTHER/install/jre" ]; then
|
||||
THIS_JRE="$THIS/install/jre"
|
||||
OTHER_JRE="$OTHER/install/jre"
|
||||
echo "Also selecting install images for JRE compare"
|
||||
else
|
||||
echo "No install JRE image found"
|
||||
fi
|
||||
elif [ -d "$THIS/images/jdk" ] && [ -d "$OTHER/deploy/images/jdk" ]; then
|
||||
THIS_JDK="$THIS/images/jdk"
|
||||
THIS_JRE="$THIS/images/jre"
|
||||
OTHER_JDK="$OTHER/deploy/images/jdk"
|
||||
OTHER_JRE="$OTHER/deploy/images/jre"
|
||||
echo "Selecting deploy images for compare"
|
||||
echo "Selecting deploy images for JDK compare"
|
||||
if [ -d "$THIS/images/jre" ] && [ -d "$OTHER/deploy/images/jre" ]; then
|
||||
THIS_JRE="$THIS/images/jre"
|
||||
OTHER_JRE="$OTHER/deploy/images/jre"
|
||||
echo "Selecting deploy images for JRE compare"
|
||||
else
|
||||
echo "No deploy JRE image found"
|
||||
fi
|
||||
elif [ -d "$THIS/images/jdk" ] && [ -d "$OTHER/images/jdk" ]; then
|
||||
THIS_JDK="$THIS/images/jdk"
|
||||
THIS_JRE="$THIS/images/jre"
|
||||
OTHER_JDK="$OTHER/images/jdk"
|
||||
OTHER_JRE="$OTHER/images/jre"
|
||||
echo "Selecting jdk images for compare"
|
||||
echo "Selecting normal images for JDK compare"
|
||||
if [ -d "$THIS/images/jre" ] && [ -d "$OTHER/images/jre" ]; then
|
||||
THIS_JRE="$THIS/images/jre"
|
||||
OTHER_JRE="$OTHER/images/jre"
|
||||
echo "Selecting normal images for JRE compare"
|
||||
else
|
||||
echo "No normal JRE image found"
|
||||
fi
|
||||
elif [ -d "$(ls -d $THIS/licensee-src/build/*/images/jdk 2> /dev/null)" ] \
|
||||
&& [ -d "$(ls -d $OTHER/licensee-src/build/*/images/jdk 2> /dev/null)" ]
|
||||
then
|
||||
@ -1406,9 +1421,11 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
|
||||
else
|
||||
OTHER_SEC_DIR="$OTHER/tmp"
|
||||
fi
|
||||
OTHER_SEC_BIN="$OTHER_SEC_DIR/sec-bin.zip"
|
||||
THIS_SEC_DIR="$THIS/images"
|
||||
THIS_SEC_BIN="$THIS_SEC_DIR/sec-bin.zip"
|
||||
if [ -f "$THIS_SEC_DIR/sec-bin.zip" ]; then
|
||||
OTHER_SEC_BIN="$OTHER_SEC_DIR/sec-bin.zip"
|
||||
THIS_SEC_DIR="$THIS/images"
|
||||
THIS_SEC_BIN="$THIS_SEC_DIR/sec-bin.zip"
|
||||
fi
|
||||
if [ "$OPENJDK_TARGET_OS" = "windows" ]; then
|
||||
if [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; then
|
||||
JGSS_WINDOWS_BIN="jgss-windows-x64-bin.zip"
|
||||
@ -1437,11 +1454,12 @@ if [ "$CMP_NAMES" = "true" ]; then
|
||||
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
|
||||
echo -n "JDK "
|
||||
compare_dirs $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
echo -n "JRE "
|
||||
compare_dirs $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
|
||||
echo -n "JDK "
|
||||
compare_files $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
fi
|
||||
if [ -n "$THIS_JRE" ] && [ -n "$OTHER_JRE" ]; then
|
||||
echo -n "JRE "
|
||||
compare_dirs $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
echo -n "JRE "
|
||||
compare_files $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
fi
|
||||
@ -1480,49 +1498,38 @@ if [ "$CMP_NAMES" = "true" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$CMP_PERMS" = "true" ]; then
|
||||
if [ "$CMP_LIBS" = "true" ]; then
|
||||
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
|
||||
echo -n "JDK "
|
||||
compare_permissions $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
echo -n "JRE "
|
||||
compare_permissions $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
compare_all_libs $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
fi
|
||||
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
|
||||
compare_permissions $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
|
||||
compare_all_libs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
|
||||
fi
|
||||
if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
|
||||
echo -n "JavaAppletPlugin "
|
||||
compare_permissions $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
|
||||
compare_all_libs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
|
||||
fi
|
||||
if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
|
||||
echo -n "Sparkle.framework "
|
||||
compare_permissions $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
|
||||
compare_all_libs $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$CMP_TYPES" = "true" ]; then
|
||||
if [ "$CMP_EXECS" = "true" ]; then
|
||||
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
|
||||
echo -n "JDK "
|
||||
compare_file_types $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
echo -n "JRE "
|
||||
compare_file_types $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
fi
|
||||
if [ -n "$THIS_JDK_BUNDLE" ] && [ -n "$OTHER_JDK_BUNDLE" ]; then
|
||||
echo -n "JDK Bundle "
|
||||
compare_file_types $THIS_JDK_BUNDLE $OTHER_JDK_BUNDLE $COMPARE_ROOT/jdk-bundle
|
||||
echo -n "JRE Bundle "
|
||||
compare_file_types $THIS_JRE_BUNDLE $OTHER_JRE_BUNDLE $COMPARE_ROOT/jre-bundle
|
||||
compare_all_execs $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
fi
|
||||
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
|
||||
compare_file_types $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
|
||||
compare_all_execs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
|
||||
fi
|
||||
if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
|
||||
echo -n "JavaAppletPlugin "
|
||||
compare_file_types $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
|
||||
compare_all_execs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
|
||||
fi
|
||||
if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
|
||||
echo -n "Sparkle.framework "
|
||||
compare_file_types $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
|
||||
compare_all_execs $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -1530,6 +1537,8 @@ if [ "$CMP_GENERAL" = "true" ]; then
|
||||
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
|
||||
echo -n "JDK "
|
||||
compare_general_files $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
fi
|
||||
if [ -n "$THIS_JRE" ] && [ -n "$OTHER_JRE" ]; then
|
||||
echo -n "JRE "
|
||||
compare_general_files $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
fi
|
||||
@ -1601,46 +1610,53 @@ if [ "$CMP_JARS" = "true" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$CMP_LIBS" = "true" ]; then
|
||||
if [ "$CMP_PERMS" = "true" ]; then
|
||||
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
|
||||
echo -n "JDK "
|
||||
compare_all_libs $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then
|
||||
echo -n "JRE "
|
||||
compare_all_libs $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
fi
|
||||
compare_permissions $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
fi
|
||||
if [ -n "$THIS_JRE" ] && [ -n "$OTHER_JRE" ]; then
|
||||
echo -n "JRE "
|
||||
compare_permissions $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
fi
|
||||
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
|
||||
compare_all_libs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
|
||||
compare_permissions $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
|
||||
fi
|
||||
if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
|
||||
echo -n "JavaAppletPlugin "
|
||||
compare_all_libs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
|
||||
compare_permissions $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
|
||||
fi
|
||||
if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
|
||||
echo -n "Sparkle.framework "
|
||||
compare_all_libs $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
|
||||
compare_permissions $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$CMP_EXECS" = "true" ]; then
|
||||
if [ "$CMP_TYPES" = "true" ]; then
|
||||
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
|
||||
compare_all_execs $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
if [ "$OPENJDK_TARGET_OS" = "macosx" ]; then
|
||||
echo -n "JRE "
|
||||
compare_all_execs $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
fi
|
||||
echo -n "JDK "
|
||||
compare_file_types $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
|
||||
fi
|
||||
if [ -n "$THIS_JRE" ] && [ -n "$OTHER_JRE" ]; then
|
||||
echo -n "JRE "
|
||||
compare_file_types $THIS_JRE $OTHER_JRE $COMPARE_ROOT/jre
|
||||
fi
|
||||
if [ -n "$THIS_JDK_BUNDLE" ] && [ -n "$OTHER_JDK_BUNDLE" ]; then
|
||||
echo -n "JDK Bundle "
|
||||
compare_file_types $THIS_JDK_BUNDLE $OTHER_JDK_BUNDLE $COMPARE_ROOT/jdk-bundle
|
||||
echo -n "JRE Bundle "
|
||||
compare_file_types $THIS_JRE_BUNDLE $OTHER_JRE_BUNDLE $COMPARE_ROOT/jre-bundle
|
||||
fi
|
||||
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
|
||||
compare_all_execs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
|
||||
compare_file_types $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
|
||||
fi
|
||||
if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
|
||||
echo -n "JavaAppletPlugin "
|
||||
compare_all_execs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
|
||||
compare_file_types $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
|
||||
fi
|
||||
if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
|
||||
echo -n "Sparkle.framework "
|
||||
compare_all_execs $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
|
||||
compare_file_types $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -339,7 +339,7 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "sparcv9" ]
|
||||
|
||||
DIS_DIFF_FILTER="$SED \
|
||||
-e 's/^[0-9a-f]\{16\}/<ADDR>:/' \
|
||||
-e 's/^ *[0-9a-f]\{3,8\}:/ <ADDR>:/' \
|
||||
-e 's/^ *[0-9a-f]\{3,12\}:/ <ADDR>:/' \
|
||||
-e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: <NUMS>/' \
|
||||
-e 's/\$[a-zA-Z0-9_\$]\{15\}\./<SYM>./' \
|
||||
-e 's/, [0-9a-fx\-]\{1,8\}/, <ADDR>/g' \
|
||||
|
@ -109,11 +109,11 @@ class EPoll {
|
||||
|
||||
private static native int dataOffset();
|
||||
|
||||
static native int epollCreate() throws IOException;
|
||||
static native int create() throws IOException;
|
||||
|
||||
static native int epollCtl(int epfd, int opcode, int fd, int events);
|
||||
static native int ctl(int epfd, int opcode, int fd, int events);
|
||||
|
||||
static native int epollWait(int epfd, long pollAddress, int numfds)
|
||||
static native int wait(int epfd, long pollAddress, int numfds, int timeout)
|
||||
throws IOException;
|
||||
|
||||
static {
|
||||
|
@ -1,309 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
|
||||
/**
|
||||
* Manipulates a native array of epoll_event structs on Linux:
|
||||
*
|
||||
* typedef union epoll_data {
|
||||
* void *ptr;
|
||||
* int fd;
|
||||
* __uint32_t u32;
|
||||
* __uint64_t u64;
|
||||
* } epoll_data_t;
|
||||
*
|
||||
* struct epoll_event {
|
||||
* __uint32_t events;
|
||||
* epoll_data_t data;
|
||||
* };
|
||||
*
|
||||
* The system call to wait for I/O events is epoll_wait(2). It populates an
|
||||
* array of epoll_event structures that are passed to the call. The data
|
||||
* member of the epoll_event structure contains the same data as was set
|
||||
* when the file descriptor was registered to epoll via epoll_ctl(2). In
|
||||
* this implementation we set data.fd to be the file descriptor that we
|
||||
* register. That way, we have the file descriptor available when we
|
||||
* process the events.
|
||||
*/
|
||||
|
||||
class EPollArrayWrapper {
|
||||
// EPOLL_EVENTS
|
||||
private static final int EPOLLIN = 0x001;
|
||||
|
||||
// opcodes
|
||||
private static final int EPOLL_CTL_ADD = 1;
|
||||
private static final int EPOLL_CTL_DEL = 2;
|
||||
private static final int EPOLL_CTL_MOD = 3;
|
||||
|
||||
// Miscellaneous constants
|
||||
private static final int SIZE_EPOLLEVENT = sizeofEPollEvent();
|
||||
private static final int EVENT_OFFSET = 0;
|
||||
private static final int DATA_OFFSET = offsetofData();
|
||||
private static final int FD_OFFSET = DATA_OFFSET;
|
||||
private static final int OPEN_MAX = IOUtil.fdLimit();
|
||||
private static final int NUM_EPOLLEVENTS = Math.min(OPEN_MAX, 8192);
|
||||
|
||||
// Special value to indicate that an update should be ignored
|
||||
private static final byte KILLED = (byte)-1;
|
||||
|
||||
// Initial size of arrays for fd registration changes
|
||||
private static final int INITIAL_PENDING_UPDATE_SIZE = 64;
|
||||
|
||||
// maximum size of updatesLow
|
||||
private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
|
||||
new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
|
||||
|
||||
// The fd of the epoll driver
|
||||
private final int epfd;
|
||||
|
||||
// The epoll_event array for results from epoll_wait
|
||||
private final AllocatedNativeObject pollArray;
|
||||
|
||||
// Base address of the epoll_event array
|
||||
private final long pollArrayAddress;
|
||||
|
||||
// The fd of the interrupt line going out
|
||||
private final int outgoingInterruptFD;
|
||||
|
||||
// Number of updated pollfd entries
|
||||
private int updated;
|
||||
|
||||
// object to synchronize fd registration changes
|
||||
private final Object updateLock = new Object();
|
||||
|
||||
// number of file descriptors with registration changes pending
|
||||
private int updateCount;
|
||||
|
||||
// file descriptors with registration changes pending
|
||||
private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
|
||||
|
||||
// events for file descriptors with registration changes pending, indexed
|
||||
// by file descriptor and stored as bytes for efficiency reasons. For
|
||||
// file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
|
||||
// least) then the update is stored in a map.
|
||||
private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
|
||||
private final Map<Integer,Byte> eventsHigh = new HashMap<>();
|
||||
|
||||
// Used by release and updateRegistrations to track whether a file
|
||||
// descriptor is registered with epoll.
|
||||
private final BitSet registered = new BitSet();
|
||||
|
||||
|
||||
EPollArrayWrapper(int fd0, int fd1) throws IOException {
|
||||
// creates the epoll file descriptor
|
||||
epfd = epollCreate();
|
||||
|
||||
// the epoll_event array passed to epoll_wait
|
||||
int allocationSize = NUM_EPOLLEVENTS * SIZE_EPOLLEVENT;
|
||||
pollArray = new AllocatedNativeObject(allocationSize, true);
|
||||
pollArrayAddress = pollArray.address();
|
||||
|
||||
outgoingInterruptFD = fd1;
|
||||
epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
|
||||
}
|
||||
|
||||
void putEventOps(int i, int event) {
|
||||
int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
|
||||
pollArray.putInt(offset, event);
|
||||
}
|
||||
|
||||
void putDescriptor(int i, int fd) {
|
||||
int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
|
||||
pollArray.putInt(offset, fd);
|
||||
}
|
||||
|
||||
int getEventOps(int i) {
|
||||
int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
|
||||
return pollArray.getInt(offset);
|
||||
}
|
||||
|
||||
int getDescriptor(int i) {
|
||||
int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
|
||||
return pollArray.getInt(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if updates for the given key (file
|
||||
* descriptor) are killed.
|
||||
*/
|
||||
private boolean isEventsHighKilled(Integer key) {
|
||||
assert key >= MAX_UPDATE_ARRAY_SIZE;
|
||||
Byte value = eventsHigh.get(key);
|
||||
return (value != null && value == KILLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pending update events for the given file descriptor. This
|
||||
* method has no effect if the update events is already set to KILLED,
|
||||
* unless {@code force} is {@code true}.
|
||||
*/
|
||||
private void setUpdateEvents(int fd, byte events, boolean force) {
|
||||
if (fd < MAX_UPDATE_ARRAY_SIZE) {
|
||||
if ((eventsLow[fd] != KILLED) || force) {
|
||||
eventsLow[fd] = events;
|
||||
}
|
||||
} else {
|
||||
Integer key = Integer.valueOf(fd);
|
||||
if (!isEventsHighKilled(key) || force) {
|
||||
eventsHigh.put(key, Byte.valueOf(events));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pending update events for the given file descriptor.
|
||||
*/
|
||||
private byte getUpdateEvents(int fd) {
|
||||
if (fd < MAX_UPDATE_ARRAY_SIZE) {
|
||||
return eventsLow[fd];
|
||||
} else {
|
||||
Byte result = eventsHigh.get(Integer.valueOf(fd));
|
||||
// result should never be null
|
||||
return result.byteValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the events for a given file descriptor
|
||||
*/
|
||||
void setInterest(int fd, int mask) {
|
||||
synchronized (updateLock) {
|
||||
// record the file descriptor and events
|
||||
int oldCapacity = updateDescriptors.length;
|
||||
if (updateCount == oldCapacity) {
|
||||
int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
|
||||
int[] newDescriptors = new int[newCapacity];
|
||||
System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
|
||||
updateDescriptors = newDescriptors;
|
||||
}
|
||||
updateDescriptors[updateCount++] = fd;
|
||||
|
||||
// events are stored as bytes for efficiency reasons
|
||||
byte b = (byte)mask;
|
||||
assert (b == mask) && (b != KILLED);
|
||||
setUpdateEvents(fd, b, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a file descriptor
|
||||
*/
|
||||
void add(int fd) {
|
||||
// force the initial update events to 0 as it may be KILLED by a
|
||||
// previous registration.
|
||||
synchronized (updateLock) {
|
||||
assert !registered.get(fd);
|
||||
setUpdateEvents(fd, (byte)0, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file descriptor
|
||||
*/
|
||||
void remove(int fd) {
|
||||
synchronized (updateLock) {
|
||||
// kill pending and future update for this file descriptor
|
||||
setUpdateEvents(fd, KILLED, false);
|
||||
|
||||
// remove from epoll
|
||||
if (registered.get(fd)) {
|
||||
epollCtl(epfd, EPOLL_CTL_DEL, fd, 0);
|
||||
registered.clear(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close epoll file descriptor and free poll array
|
||||
*/
|
||||
void close() throws IOException {
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
pollArray.free();
|
||||
}
|
||||
|
||||
int poll(long timeout) throws IOException {
|
||||
updateRegistrations();
|
||||
return epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the pending registrations.
|
||||
*/
|
||||
private void updateRegistrations() {
|
||||
synchronized (updateLock) {
|
||||
int j = 0;
|
||||
while (j < updateCount) {
|
||||
int fd = updateDescriptors[j];
|
||||
short events = getUpdateEvents(fd);
|
||||
boolean isRegistered = registered.get(fd);
|
||||
int opcode = 0;
|
||||
|
||||
if (events != KILLED) {
|
||||
if (isRegistered) {
|
||||
opcode = (events != 0) ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
|
||||
} else {
|
||||
opcode = (events != 0) ? EPOLL_CTL_ADD : 0;
|
||||
}
|
||||
if (opcode != 0) {
|
||||
epollCtl(epfd, opcode, fd, events);
|
||||
if (opcode == EPOLL_CTL_ADD) {
|
||||
registered.set(fd);
|
||||
} else if (opcode == EPOLL_CTL_DEL) {
|
||||
registered.clear(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
updateCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void interrupt() {
|
||||
interrupt(outgoingInterruptFD);
|
||||
}
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
init();
|
||||
}
|
||||
|
||||
private native int epollCreate();
|
||||
private native void epollCtl(int epfd, int opcode, int fd, int events);
|
||||
private native int epollWait(long pollAddress, int numfds, long timeout,
|
||||
int epfd) throws IOException;
|
||||
private static native int sizeofEPollEvent();
|
||||
private static native int offsetofData();
|
||||
private static native void interrupt(int fd);
|
||||
private static native void init();
|
||||
}
|
@ -30,7 +30,13 @@ import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import static sun.nio.ch.EPoll.*;
|
||||
|
||||
import static sun.nio.ch.EPoll.EPOLLIN;
|
||||
import static sun.nio.ch.EPoll.EPOLLONESHOT;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_ADD;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_DEL;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_MOD;
|
||||
|
||||
|
||||
/**
|
||||
* AsynchronousChannelGroup implementation based on the Linux epoll facility.
|
||||
@ -48,6 +54,9 @@ final class EPollPort
|
||||
// epoll file descriptor
|
||||
private final int epfd;
|
||||
|
||||
// address of the poll array passed to epoll_wait
|
||||
private final long address;
|
||||
|
||||
// true if epoll closed
|
||||
private boolean closed;
|
||||
|
||||
@ -57,9 +66,6 @@ final class EPollPort
|
||||
// number of wakeups pending
|
||||
private final AtomicInteger wakeupCount = new AtomicInteger();
|
||||
|
||||
// address of the poll array passed to epoll_wait
|
||||
private final long address;
|
||||
|
||||
// encapsulates an event for a channel
|
||||
static class Event {
|
||||
final PollableChannel channel;
|
||||
@ -85,23 +91,21 @@ final class EPollPort
|
||||
{
|
||||
super(provider, pool);
|
||||
|
||||
// open epoll
|
||||
this.epfd = epollCreate();
|
||||
this.epfd = EPoll.create();
|
||||
this.address = EPoll.allocatePollArray(MAX_EPOLL_EVENTS);
|
||||
|
||||
// create socket pair for wakeup mechanism
|
||||
int[] sv = new int[2];
|
||||
try {
|
||||
socketpair(sv);
|
||||
// register one end with epoll
|
||||
epollCtl(epfd, EPOLL_CTL_ADD, sv[0], EPOLLIN);
|
||||
} catch (IOException x) {
|
||||
close0(epfd);
|
||||
throw x;
|
||||
long fds = IOUtil.makePipe(true);
|
||||
this.sp = new int[]{(int) (fds >>> 32), (int) fds};
|
||||
} catch (IOException ioe) {
|
||||
EPoll.freePollArray(address);
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
throw ioe;
|
||||
}
|
||||
this.sp = sv;
|
||||
|
||||
// allocate the poll array
|
||||
this.address = allocatePollArray(MAX_EPOLL_EVENTS);
|
||||
// register one end with epoll
|
||||
EPoll.ctl(epfd, EPOLL_CTL_ADD, sp[0], EPOLLIN);
|
||||
|
||||
// create the queue and offer the special event to ensure that the first
|
||||
// threads polls
|
||||
@ -123,17 +127,17 @@ final class EPollPort
|
||||
return;
|
||||
closed = true;
|
||||
}
|
||||
freePollArray(address);
|
||||
close0(sp[0]);
|
||||
close0(sp[1]);
|
||||
close0(epfd);
|
||||
try { FileDispatcherImpl.closeIntFD(epfd); } catch (IOException ioe) { }
|
||||
try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { }
|
||||
try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { }
|
||||
EPoll.freePollArray(address);
|
||||
}
|
||||
|
||||
private void wakeup() {
|
||||
if (wakeupCount.incrementAndGet() == 1) {
|
||||
// write byte to socketpair to force wakeup
|
||||
try {
|
||||
interrupt(sp[1]);
|
||||
IOUtil.write1(sp[1], (byte)0);
|
||||
} catch (IOException x) {
|
||||
throw new AssertionError(x);
|
||||
}
|
||||
@ -171,9 +175,9 @@ final class EPollPort
|
||||
@Override
|
||||
void startPoll(int fd, int events) {
|
||||
// update events (or add to epoll on first usage)
|
||||
int err = epollCtl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
|
||||
int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
|
||||
if (err == ENOENT)
|
||||
err = epollCtl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
|
||||
err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
|
||||
if (err != 0)
|
||||
throw new AssertionError(); // should not happen
|
||||
}
|
||||
@ -191,7 +195,11 @@ final class EPollPort
|
||||
private Event poll() throws IOException {
|
||||
try {
|
||||
for (;;) {
|
||||
int n = epollWait(epfd, address, MAX_EPOLL_EVENTS);
|
||||
int n;
|
||||
do {
|
||||
n = EPoll.wait(epfd, address, MAX_EPOLL_EVENTS, -1);
|
||||
} while (n == IOStatus.INTERRUPTED);
|
||||
|
||||
/*
|
||||
* 'n' events have been read. Here we map them to their
|
||||
* corresponding channel in batch and queue n-1 so that
|
||||
@ -201,14 +209,14 @@ final class EPollPort
|
||||
fdToChannelLock.readLock().lock();
|
||||
try {
|
||||
while (n-- > 0) {
|
||||
long eventAddress = getEvent(address, n);
|
||||
int fd = getDescriptor(eventAddress);
|
||||
long eventAddress = EPoll.getEvent(address, n);
|
||||
int fd = EPoll.getDescriptor(eventAddress);
|
||||
|
||||
// wakeup
|
||||
if (fd == sp[0]) {
|
||||
if (wakeupCount.decrementAndGet() == 0) {
|
||||
// no more wakeups so drain pipe
|
||||
drain1(sp[0]);
|
||||
IOUtil.drain(sp[0]);
|
||||
}
|
||||
|
||||
// queue special event if there are more events
|
||||
@ -222,7 +230,7 @@ final class EPollPort
|
||||
|
||||
PollableChannel channel = fdToChannel.get(fd);
|
||||
if (channel != null) {
|
||||
int events = getEvents(eventAddress);
|
||||
int events = EPoll.getEvents(eventAddress);
|
||||
Event ev = new Event(channel, events);
|
||||
|
||||
// n-1 events are queued; This thread handles
|
||||
@ -306,18 +314,4 @@ final class EPollPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native void socketpair(int[] sv) throws IOException;
|
||||
|
||||
private static native void interrupt(int fd) throws IOException;
|
||||
|
||||
private static native void drain1(int fd) throws IOException;
|
||||
|
||||
private static native void close0(int fd);
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
}
|
||||
|
@ -26,33 +26,59 @@
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.util.*;
|
||||
import java.nio.channels.ClosedSelectorException;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.BitSet;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static sun.nio.ch.EPoll.EPOLLIN;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_ADD;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_DEL;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_MOD;
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of Selector for Linux 2.6+ kernels that uses
|
||||
* the epoll event notification facility.
|
||||
* Linux epoll based Selector implementation
|
||||
*/
|
||||
class EPollSelectorImpl
|
||||
extends SelectorImpl
|
||||
{
|
||||
// File descriptors used for interrupt
|
||||
|
||||
class EPollSelectorImpl extends SelectorImpl {
|
||||
|
||||
// maximum number of events to poll in one call to epoll_wait
|
||||
private static final int NUM_EPOLLEVENTS = Math.min(IOUtil.fdLimit(), 1024);
|
||||
|
||||
// epoll file descriptor
|
||||
private final int epfd;
|
||||
|
||||
// address of poll array when polling with epoll_wait
|
||||
private final long pollArrayAddress;
|
||||
|
||||
// file descriptors used for interrupt
|
||||
private final int fd0;
|
||||
private final int fd1;
|
||||
|
||||
// The poll object
|
||||
private final EPollArrayWrapper pollWrapper;
|
||||
// maps file descriptor to selection key, synchronize on selector
|
||||
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
|
||||
|
||||
// Maps from file descriptors to keys
|
||||
private final Map<Integer, SelectionKeyImpl> fdToKey;
|
||||
// file descriptors registered with epoll, synchronize on selector
|
||||
private final BitSet registered = new BitSet();
|
||||
|
||||
// True if this Selector has been closed
|
||||
private volatile boolean closed;
|
||||
// pending new registrations/updates, queued by implRegister and putEventOps
|
||||
private final Object updateLock = new Object();
|
||||
private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
|
||||
private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
|
||||
private final Deque<Integer> updateOps = new ArrayDeque<>();
|
||||
|
||||
// Lock for interrupt triggering and clearing
|
||||
// interrupt triggering and clearing
|
||||
private final Object interruptLock = new Object();
|
||||
private boolean interruptTriggered = false;
|
||||
private boolean interruptTriggered;
|
||||
|
||||
/**
|
||||
* Package private constructor called by factory method in
|
||||
@ -60,40 +86,57 @@ class EPollSelectorImpl
|
||||
*/
|
||||
EPollSelectorImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp);
|
||||
long pipeFds = IOUtil.makePipe(false);
|
||||
fd0 = (int) (pipeFds >>> 32);
|
||||
fd1 = (int) pipeFds;
|
||||
|
||||
this.epfd = EPoll.create();
|
||||
this.pollArrayAddress = EPoll.allocatePollArray(NUM_EPOLLEVENTS);
|
||||
|
||||
try {
|
||||
pollWrapper = new EPollArrayWrapper(fd0, fd1);
|
||||
fdToKey = new HashMap<>();
|
||||
} catch (Throwable t) {
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
} catch (IOException ioe0) {
|
||||
t.addSuppressed(ioe0);
|
||||
}
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
} catch (IOException ioe1) {
|
||||
t.addSuppressed(ioe1);
|
||||
}
|
||||
throw t;
|
||||
long fds = IOUtil.makePipe(false);
|
||||
this.fd0 = (int) (fds >>> 32);
|
||||
this.fd1 = (int) fds;
|
||||
} catch (IOException ioe) {
|
||||
EPoll.freePollArray(pollArrayAddress);
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
// register one end of the socket pair for wakeups
|
||||
EPoll.ctl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
|
||||
}
|
||||
|
||||
private void ensureOpen() {
|
||||
if (closed)
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doSelect(long timeout) throws IOException {
|
||||
ensureOpen();
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
int numEntries;
|
||||
processUpdateQueue();
|
||||
processDeregisterQueue();
|
||||
try {
|
||||
begin();
|
||||
numEntries = pollWrapper.poll(timeout);
|
||||
|
||||
// epoll_wait timeout is int
|
||||
int to = (int) Math.min(timeout, Integer.MAX_VALUE);
|
||||
boolean timedPoll = (to > 0);
|
||||
do {
|
||||
long startTime = timedPoll ? System.nanoTime() : 0;
|
||||
numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, to);
|
||||
if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
|
||||
// timed poll interrupted so need to adjust timeout
|
||||
long adjust = System.nanoTime() - startTime;
|
||||
to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
|
||||
if (to <= 0) {
|
||||
// timeout expired so no retry
|
||||
numEntries = 0;
|
||||
}
|
||||
}
|
||||
} while (numEntries == IOStatus.INTERRUPTED);
|
||||
assert IOStatus.check(numEntries);
|
||||
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
@ -101,21 +144,70 @@ class EPollSelectorImpl
|
||||
return updateSelectedKeys(numEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process new registrations and changes to the interest ops.
|
||||
*/
|
||||
private void processUpdateQueue() {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
synchronized (updateLock) {
|
||||
SelectionKeyImpl ski;
|
||||
|
||||
// new registrations
|
||||
while ((ski = newKeys.pollFirst()) != null) {
|
||||
if (ski.isValid()) {
|
||||
SelChImpl ch = ski.channel;
|
||||
int fd = ch.getFDVal();
|
||||
SelectionKeyImpl previous = fdToKey.put(fd, ski);
|
||||
assert previous == null;
|
||||
assert registered.get(fd) == false;
|
||||
}
|
||||
}
|
||||
|
||||
// changes to interest ops
|
||||
assert updateKeys.size() == updateOps.size();
|
||||
while ((ski = updateKeys.pollFirst()) != null) {
|
||||
int ops = updateOps.pollFirst();
|
||||
int fd = ski.channel.getFDVal();
|
||||
if (ski.isValid() && fdToKey.containsKey(fd)) {
|
||||
if (registered.get(fd)) {
|
||||
if (ops == 0) {
|
||||
// remove from epoll
|
||||
EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
|
||||
registered.clear(fd);
|
||||
} else {
|
||||
// modify events
|
||||
EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, ops);
|
||||
}
|
||||
} else if (ops != 0) {
|
||||
// add to epoll
|
||||
EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, ops);
|
||||
registered.set(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the keys whose fd's have been selected by the epoll.
|
||||
* Add the ready keys to the ready queue.
|
||||
*/
|
||||
private int updateSelectedKeys(int numEntries) throws IOException {
|
||||
assert Thread.holdsLock(this);
|
||||
assert Thread.holdsLock(nioSelectedKeys());
|
||||
|
||||
boolean interrupted = false;
|
||||
int numKeysUpdated = 0;
|
||||
for (int i=0; i<numEntries; i++) {
|
||||
int nextFD = pollWrapper.getDescriptor(i);
|
||||
if (nextFD == fd0) {
|
||||
long event = EPoll.getEvent(pollArrayAddress, i);
|
||||
int fd = EPoll.getDescriptor(event);
|
||||
if (fd == fd0) {
|
||||
interrupted = true;
|
||||
} else {
|
||||
SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
|
||||
SelectionKeyImpl ski = fdToKey.get(fd);
|
||||
if (ski != null) {
|
||||
int rOps = pollWrapper.getEventOps(i);
|
||||
int rOps = EPoll.getEvents(event);
|
||||
if (selectedKeys.contains(ski)) {
|
||||
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
|
||||
numKeysUpdated++;
|
||||
@ -140,16 +232,17 @@ class EPollSelectorImpl
|
||||
|
||||
@Override
|
||||
protected void implClose() throws IOException {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
assert Thread.holdsLock(this);
|
||||
assert Thread.holdsLock(nioKeys());
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
pollWrapper.close();
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
EPoll.freePollArray(pollArrayAddress);
|
||||
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
|
||||
@ -167,42 +260,57 @@ class EPollSelectorImpl
|
||||
|
||||
@Override
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
assert Thread.holdsLock(nioKeys());
|
||||
ensureOpen();
|
||||
SelChImpl ch = ski.channel;
|
||||
int fd = Integer.valueOf(ch.getFDVal());
|
||||
fdToKey.put(fd, ski);
|
||||
pollWrapper.add(fd);
|
||||
synchronized (updateLock) {
|
||||
newKeys.addLast(ski);
|
||||
}
|
||||
keys.add(ski);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
assert (ski.getIndex() >= 0);
|
||||
SelChImpl ch = ski.channel;
|
||||
int fd = ch.getFDVal();
|
||||
fdToKey.remove(Integer.valueOf(fd));
|
||||
pollWrapper.remove(fd);
|
||||
ski.setIndex(-1);
|
||||
keys.remove(ski);
|
||||
assert !ski.isValid();
|
||||
assert Thread.holdsLock(this);
|
||||
assert Thread.holdsLock(nioKeys());
|
||||
assert Thread.holdsLock(nioSelectedKeys());
|
||||
|
||||
int fd = ski.channel.getFDVal();
|
||||
fdToKey.remove(fd);
|
||||
if (registered.get(fd)) {
|
||||
EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
|
||||
registered.clear(fd);
|
||||
}
|
||||
|
||||
selectedKeys.remove(ski);
|
||||
keys.remove(ski);
|
||||
|
||||
// remove from channel's key set
|
||||
deregister(ski);
|
||||
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
((SelChImpl) selch).kill();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putEventOps(SelectionKeyImpl ski, int ops) {
|
||||
ensureOpen();
|
||||
SelChImpl ch = ski.channel;
|
||||
pollWrapper.setInterest(ch.getFDVal(), ops);
|
||||
synchronized (updateLock) {
|
||||
updateOps.addLast(ops); // ops first in case adding the key fails
|
||||
updateKeys.addLast(ski);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Selector wakeup() {
|
||||
synchronized (interruptLock) {
|
||||
if (!interruptTriggered) {
|
||||
pollWrapper.interrupt();
|
||||
try {
|
||||
IOUtil.write1(fd1, (byte)0);
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -103,8 +103,8 @@ public class LinuxFileSystemProvider extends UnixFileSystemProvider {
|
||||
@Override
|
||||
FileTypeDetector getFileTypeDetector() {
|
||||
String userHome = GetPropertyAction.privilegedGetProperty("user.home");
|
||||
Path userMimeTypes = Paths.get(userHome, ".mime.types");
|
||||
Path etcMimeTypes = Paths.get("/etc/mime.types");
|
||||
Path userMimeTypes = Path.of(userHome, ".mime.types");
|
||||
Path etcMimeTypes = Path.of("/etc/mime.types");
|
||||
|
||||
return chain(new MimeTypesFileTypeDetector(userMimeTypes),
|
||||
new MimeTypesFileTypeDetector(etcMimeTypes));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,53 +23,51 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_EPoll.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_eventSize(JNIEnv* env, jclass this)
|
||||
Java_sun_nio_ch_EPoll_eventSize(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return sizeof(struct epoll_event);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_eventsOffset(JNIEnv* env, jclass this)
|
||||
Java_sun_nio_ch_EPoll_eventsOffset(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return offsetof(struct epoll_event, events);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_dataOffset(JNIEnv* env, jclass this)
|
||||
Java_sun_nio_ch_EPoll_dataOffset(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return offsetof(struct epoll_event, data);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_epollCreate(JNIEnv *env, jclass c) {
|
||||
/*
|
||||
* epoll_create expects a size as a hint to the kernel about how to
|
||||
* dimension internal structures. We can't predict the size in advance.
|
||||
*/
|
||||
Java_sun_nio_ch_EPoll_create(JNIEnv *env, jclass clazz) {
|
||||
/* size hint not used in modern kernels */
|
||||
int epfd = epoll_create(256);
|
||||
if (epfd < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed");
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed");
|
||||
}
|
||||
return epfd;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_epollCtl(JNIEnv *env, jclass c, jint epfd,
|
||||
jint opcode, jint fd, jint events)
|
||||
Java_sun_nio_ch_EPoll_ctl(JNIEnv *env, jclass clazz, jint epfd,
|
||||
jint opcode, jint fd, jint events)
|
||||
{
|
||||
struct epoll_event event;
|
||||
int res;
|
||||
@ -77,21 +75,23 @@ Java_sun_nio_ch_EPoll_epollCtl(JNIEnv *env, jclass c, jint epfd,
|
||||
event.events = events;
|
||||
event.data.fd = fd;
|
||||
|
||||
RESTARTABLE(epoll_ctl(epfd, (int)opcode, (int)fd, &event), res);
|
||||
|
||||
res = epoll_ctl(epfd, (int)opcode, (int)fd, &event);
|
||||
return (res == 0) ? 0 : errno;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_epollWait(JNIEnv *env, jclass c,
|
||||
jint epfd, jlong address, jint numfds)
|
||||
Java_sun_nio_ch_EPoll_wait(JNIEnv *env, jclass clazz, jint epfd,
|
||||
jlong address, jint numfds, jint timeout)
|
||||
{
|
||||
struct epoll_event *events = jlong_to_ptr(address);
|
||||
int res;
|
||||
|
||||
RESTARTABLE(epoll_wait(epfd, events, numfds, -1), res);
|
||||
int res = epoll_wait(epfd, events, numfds, timeout);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
|
||||
if (errno == EINTR) {
|
||||
return IOS_INTERRUPTED;
|
||||
} else {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include "sun_nio_ch_EPollArrayWrapper.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#define RESTARTABLE(_cmd, _result) do { \
|
||||
do { \
|
||||
_result = _cmd; \
|
||||
} while((_result == -1) && (errno == EINTR)); \
|
||||
} while(0)
|
||||
|
||||
|
||||
static int
|
||||
iepoll(int epfd, struct epoll_event *events, int numfds, jlong timeout)
|
||||
{
|
||||
jlong start, now;
|
||||
int remaining = timeout;
|
||||
struct timeval t;
|
||||
int diff;
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
start = t.tv_sec * 1000 + t.tv_usec / 1000;
|
||||
|
||||
for (;;) {
|
||||
int res = epoll_wait(epfd, events, numfds, remaining);
|
||||
if (res < 0 && errno == EINTR) {
|
||||
if (remaining >= 0) {
|
||||
gettimeofday(&t, NULL);
|
||||
now = t.tv_sec * 1000 + t.tv_usec / 1000;
|
||||
diff = now - start;
|
||||
remaining -= diff;
|
||||
if (diff < 0 || remaining <= 0) {
|
||||
return 0;
|
||||
}
|
||||
start = now;
|
||||
}
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_EPollArrayWrapper_init(JNIEnv *env, jclass this)
|
||||
{
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPollArrayWrapper_epollCreate(JNIEnv *env, jobject this)
|
||||
{
|
||||
/*
|
||||
* epoll_create expects a size as a hint to the kernel about how to
|
||||
* dimension internal structures. We can't predict the size in advance.
|
||||
*/
|
||||
int epfd = epoll_create(256);
|
||||
if (epfd < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed");
|
||||
}
|
||||
return epfd;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent(JNIEnv* env, jclass this)
|
||||
{
|
||||
return sizeof(struct epoll_event);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPollArrayWrapper_offsetofData(JNIEnv* env, jclass this)
|
||||
{
|
||||
return offsetof(struct epoll_event, data);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_EPollArrayWrapper_epollCtl(JNIEnv *env, jobject this, jint epfd,
|
||||
jint opcode, jint fd, jint events)
|
||||
{
|
||||
struct epoll_event event;
|
||||
int res;
|
||||
|
||||
event.events = events;
|
||||
event.data.fd = fd;
|
||||
|
||||
RESTARTABLE(epoll_ctl(epfd, (int)opcode, (int)fd, &event), res);
|
||||
|
||||
/*
|
||||
* A channel may be registered with several Selectors. When each Selector
|
||||
* is polled a EPOLL_CTL_DEL op will be inserted into its pending update
|
||||
* list to remove the file descriptor from epoll. The "last" Selector will
|
||||
* close the file descriptor which automatically unregisters it from each
|
||||
* epoll descriptor. To avoid costly synchronization between Selectors we
|
||||
* allow pending updates to be processed, ignoring errors. The errors are
|
||||
* harmless as the last update for the file descriptor is guaranteed to
|
||||
* be EPOLL_CTL_DEL.
|
||||
*/
|
||||
if (res < 0 && errno != EBADF && errno != ENOENT && errno != EPERM) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_ctl failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPollArrayWrapper_epollWait(JNIEnv *env, jobject this,
|
||||
jlong address, jint numfds,
|
||||
jlong timeout, jint epfd)
|
||||
{
|
||||
struct epoll_event *events = jlong_to_ptr(address);
|
||||
int res;
|
||||
|
||||
if (timeout <= 0) { /* Indefinite or no wait */
|
||||
RESTARTABLE(epoll_wait(epfd, events, numfds, timeout), res);
|
||||
} else { /* Bounded wait; bounded restarts */
|
||||
res = iepoll(epfd, events, numfds, timeout);
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_EPollArrayWrapper_interrupt(JNIEnv *env, jobject this, jint fd)
|
||||
{
|
||||
int fakebuf[1];
|
||||
fakebuf[0] = 1;
|
||||
if (write(fd, fakebuf, 1) < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env,"write to interrupt fd failed");
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_EPollPort.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_EPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
|
||||
int sp[2];
|
||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
|
||||
} else {
|
||||
jint res[2];
|
||||
res[0] = (jint)sp[0];
|
||||
res[1] = (jint)sp[1];
|
||||
(*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_EPollPort_interrupt(JNIEnv *env, jclass c, jint fd) {
|
||||
int res;
|
||||
int buf[1];
|
||||
buf[0] = 1;
|
||||
RESTARTABLE(write(fd, buf, 1), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "write failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_EPollPort_drain1(JNIEnv *env, jclass cl, jint fd) {
|
||||
int res;
|
||||
char buf[1];
|
||||
RESTARTABLE(read(fd, buf, 1), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "drain1 failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_EPollPort_close0(JNIEnv *env, jclass c, jint fd) {
|
||||
int res;
|
||||
RESTARTABLE(close(fd), res);
|
||||
}
|
@ -84,17 +84,17 @@ class KQueue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file descriptor from a kevent (assuming to be in ident field)
|
||||
* Returns the file descriptor from a kevent (assuming it is in the ident field)
|
||||
*/
|
||||
static int getDescriptor(long address) {
|
||||
return unsafe.getInt(address + OFFSET_IDENT);
|
||||
}
|
||||
|
||||
static int getFilter(long address) {
|
||||
static short getFilter(long address) {
|
||||
return unsafe.getShort(address + OFFSET_FILTER);
|
||||
}
|
||||
|
||||
static int getFlags(long address) {
|
||||
static short getFlags(long address) {
|
||||
return unsafe.getShort(address + OFFSET_FLAGS);
|
||||
}
|
||||
|
||||
@ -108,11 +108,11 @@ class KQueue {
|
||||
|
||||
private static native int flagsOffset();
|
||||
|
||||
static native int kqueue() throws IOException;
|
||||
static native int create() throws IOException;
|
||||
|
||||
static native int keventRegister(int kqpfd, int fd, int filter, int flags);
|
||||
static native int register(int kqfd, int fd, int filter, int flags);
|
||||
|
||||
static native int keventPoll(int kqpfd, long pollAddress, int nevents)
|
||||
static native int poll(int kqfd, long pollAddress, int nevents, long timeout)
|
||||
throws IOException;
|
||||
|
||||
static {
|
||||
|
@ -1,197 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* KQueueArrayWrapper.java
|
||||
* Implementation of Selector using FreeBSD / Mac OS X kqueues
|
||||
* Derived from Sun's DevPollArrayWrapper
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/*
|
||||
* struct kevent { // 32-bit 64-bit
|
||||
* uintptr_t ident; // 4 8
|
||||
* short filter; // 2 2
|
||||
* u_short flags; // 2 2
|
||||
* u_int fflags; // 4 4
|
||||
* intptr_t data; // 4 8
|
||||
* void *udata; // 4 8
|
||||
* } // Total: 20 32
|
||||
*
|
||||
* The implementation works in 32-bit and 64-bit world. We do this by calling a
|
||||
* native function that actually sets the sizes and offsets of the fields based
|
||||
* on which mode we're in.
|
||||
*/
|
||||
|
||||
class KQueueArrayWrapper {
|
||||
// kevent filters
|
||||
static short EVFILT_READ;
|
||||
static short EVFILT_WRITE;
|
||||
|
||||
// kevent struct
|
||||
// These fields are now set by initStructSizes in the static initializer.
|
||||
static short SIZEOF_KEVENT;
|
||||
static short FD_OFFSET;
|
||||
static short FILTER_OFFSET;
|
||||
|
||||
// kevent array size
|
||||
static final int NUM_KEVENTS = 128;
|
||||
|
||||
// Are we in a 64-bit VM?
|
||||
static boolean is64bit;
|
||||
|
||||
// The kevent array (used for outcoming events only)
|
||||
private final AllocatedNativeObject keventArray;
|
||||
private final long keventArrayAddress;
|
||||
|
||||
// The kqueue fd
|
||||
private final int kq;
|
||||
|
||||
// The fd of the interrupt line going out
|
||||
private final int outgoingInterruptFD;
|
||||
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initStructSizes();
|
||||
String datamodel =
|
||||
GetPropertyAction.privilegedGetProperty("sun.arch.data.model");
|
||||
is64bit = "64".equals(datamodel);
|
||||
}
|
||||
|
||||
KQueueArrayWrapper(int fd0, int fd1) throws IOException {
|
||||
int allocationSize = SIZEOF_KEVENT * NUM_KEVENTS;
|
||||
keventArray = new AllocatedNativeObject(allocationSize, true);
|
||||
keventArrayAddress = keventArray.address();
|
||||
kq = init();
|
||||
register0(kq, fd0, 1, 0);
|
||||
outgoingInterruptFD = fd1;
|
||||
}
|
||||
|
||||
// Used to update file description registrations
|
||||
private static class Update {
|
||||
SelChImpl channel;
|
||||
int events;
|
||||
Update(SelChImpl channel, int events) {
|
||||
this.channel = channel;
|
||||
this.events = events;
|
||||
}
|
||||
}
|
||||
|
||||
private LinkedList<Update> updateList = new LinkedList<Update>();
|
||||
|
||||
int getReventOps(int index) {
|
||||
int result = 0;
|
||||
int offset = SIZEOF_KEVENT*index + FILTER_OFFSET;
|
||||
short filter = keventArray.getShort(offset);
|
||||
|
||||
// This is all that's necessary based on inspection of usage:
|
||||
// SinkChannelImpl, SourceChannelImpl, DatagramChannelImpl,
|
||||
// ServerSocketChannelImpl, SocketChannelImpl
|
||||
if (filter == EVFILT_READ) {
|
||||
result |= Net.POLLIN;
|
||||
} else if (filter == EVFILT_WRITE) {
|
||||
result |= Net.POLLOUT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int getDescriptor(int index) {
|
||||
int offset = SIZEOF_KEVENT*index + FD_OFFSET;
|
||||
/* The ident field is 8 bytes in 64-bit world, however the API wants us
|
||||
* to return an int. Hence read the 8 bytes but return as an int.
|
||||
*/
|
||||
if (is64bit) {
|
||||
long fd = keventArray.getLong(offset);
|
||||
assert fd <= Integer.MAX_VALUE;
|
||||
return (int) fd;
|
||||
} else {
|
||||
return keventArray.getInt(offset);
|
||||
}
|
||||
}
|
||||
|
||||
void setInterest(SelChImpl channel, int events) {
|
||||
synchronized (updateList) {
|
||||
// update existing registration
|
||||
updateList.add(new Update(channel, events));
|
||||
}
|
||||
}
|
||||
|
||||
void release(SelChImpl channel) {
|
||||
synchronized (updateList) {
|
||||
// flush any pending updates
|
||||
for (Iterator<Update> it = updateList.iterator(); it.hasNext();) {
|
||||
if (it.next().channel == channel) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// remove
|
||||
register0(kq, channel.getFDVal(), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void updateRegistrations() {
|
||||
synchronized (updateList) {
|
||||
Update u;
|
||||
while ((u = updateList.poll()) != null) {
|
||||
SelChImpl ch = u.channel;
|
||||
if (!ch.isOpen())
|
||||
continue;
|
||||
|
||||
register0(kq, ch.getFDVal(), u.events & Net.POLLIN, u.events & Net.POLLOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void close() throws IOException {
|
||||
FileDispatcherImpl.closeIntFD(kq);
|
||||
keventArray.free();
|
||||
}
|
||||
|
||||
int poll(long timeout) {
|
||||
updateRegistrations();
|
||||
return kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout);
|
||||
}
|
||||
|
||||
void interrupt() {
|
||||
interrupt(outgoingInterruptFD);
|
||||
}
|
||||
|
||||
private native int init();
|
||||
private static native void initStructSizes();
|
||||
|
||||
private native void register0(int kq, int fd, int read, int write);
|
||||
private native int kevent0(int kq, long keventAddress, int keventCount,
|
||||
long timeout);
|
||||
private static native void interrupt(int fd);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,7 +30,11 @@ import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import static sun.nio.ch.KQueue.*;
|
||||
|
||||
import static sun.nio.ch.KQueue.EVFILT_READ;
|
||||
import static sun.nio.ch.KQueue.EVFILT_WRITE;
|
||||
import static sun.nio.ch.KQueue.EV_ADD;
|
||||
import static sun.nio.ch.KQueue.EV_ONESHOT;
|
||||
|
||||
/**
|
||||
* AsynchronousChannelGroup implementation based on the BSD kqueue facility.
|
||||
@ -45,6 +49,9 @@ final class KQueuePort
|
||||
// kqueue file descriptor
|
||||
private final int kqfd;
|
||||
|
||||
// address of the poll array passed to kqueue_wait
|
||||
private final long address;
|
||||
|
||||
// true if kqueue closed
|
||||
private boolean closed;
|
||||
|
||||
@ -54,9 +61,6 @@ final class KQueuePort
|
||||
// number of wakeups pending
|
||||
private final AtomicInteger wakeupCount = new AtomicInteger();
|
||||
|
||||
// address of the poll array passed to kqueue_wait
|
||||
private final long address;
|
||||
|
||||
// encapsulates an event for a channel
|
||||
static class Event {
|
||||
final PollableChannel channel;
|
||||
@ -82,28 +86,25 @@ final class KQueuePort
|
||||
{
|
||||
super(provider, pool);
|
||||
|
||||
// open kqueue
|
||||
this.kqfd = kqueue();
|
||||
this.kqfd = KQueue.create();
|
||||
this.address = KQueue.allocatePollArray(MAX_KEVENTS_TO_POLL);
|
||||
|
||||
// create socket pair for wakeup mechanism
|
||||
int[] sv = new int[2];
|
||||
try {
|
||||
socketpair(sv);
|
||||
|
||||
// register one end with kqueue
|
||||
keventRegister(kqfd, sv[0], EVFILT_READ, EV_ADD);
|
||||
} catch (IOException x) {
|
||||
close0(kqfd);
|
||||
throw x;
|
||||
long fds = IOUtil.makePipe(true);
|
||||
this.sp = new int[]{(int) (fds >>> 32), (int) fds};
|
||||
} catch (IOException ioe) {
|
||||
KQueue.freePollArray(address);
|
||||
FileDispatcherImpl.closeIntFD(kqfd);
|
||||
throw ioe;
|
||||
}
|
||||
this.sp = sv;
|
||||
|
||||
// allocate the poll array
|
||||
this.address = allocatePollArray(MAX_KEVENTS_TO_POLL);
|
||||
// register one end with kqueue
|
||||
KQueue.register(kqfd, sp[0], EVFILT_READ, EV_ADD);
|
||||
|
||||
// create the queue and offer the special event to ensure that the first
|
||||
// threads polls
|
||||
this.queue = new ArrayBlockingQueue<Event>(MAX_KEVENTS_TO_POLL);
|
||||
this.queue = new ArrayBlockingQueue<>(MAX_KEVENTS_TO_POLL);
|
||||
this.queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
|
||||
@ -121,17 +122,18 @@ final class KQueuePort
|
||||
return;
|
||||
closed = true;
|
||||
}
|
||||
freePollArray(address);
|
||||
close0(sp[0]);
|
||||
close0(sp[1]);
|
||||
close0(kqfd);
|
||||
|
||||
try { FileDispatcherImpl.closeIntFD(kqfd); } catch (IOException ioe) { }
|
||||
try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { }
|
||||
try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { }
|
||||
KQueue.freePollArray(address);
|
||||
}
|
||||
|
||||
private void wakeup() {
|
||||
if (wakeupCount.incrementAndGet() == 1) {
|
||||
// write byte to socketpair to force wakeup
|
||||
try {
|
||||
interrupt(sp[1]);
|
||||
IOUtil.write1(sp[1], (byte)0);
|
||||
} catch (IOException x) {
|
||||
throw new AssertionError(x);
|
||||
}
|
||||
@ -173,9 +175,9 @@ final class KQueuePort
|
||||
int err = 0;
|
||||
int flags = (EV_ADD|EV_ONESHOT);
|
||||
if ((events & Net.POLLIN) > 0)
|
||||
err = keventRegister(kqfd, fd, EVFILT_READ, flags);
|
||||
err = KQueue.register(kqfd, fd, EVFILT_READ, flags);
|
||||
if (err == 0 && (events & Net.POLLOUT) > 0)
|
||||
err = keventRegister(kqfd, fd, EVFILT_WRITE, flags);
|
||||
err = KQueue.register(kqfd, fd, EVFILT_WRITE, flags);
|
||||
if (err != 0)
|
||||
throw new InternalError("kevent failed: " + err); // should not happen
|
||||
}
|
||||
@ -193,7 +195,11 @@ final class KQueuePort
|
||||
private Event poll() throws IOException {
|
||||
try {
|
||||
for (;;) {
|
||||
int n = keventPoll(kqfd, address, MAX_KEVENTS_TO_POLL);
|
||||
int n;
|
||||
do {
|
||||
n = KQueue.poll(kqfd, address, MAX_KEVENTS_TO_POLL, -1L);
|
||||
} while (n == IOStatus.INTERRUPTED);
|
||||
|
||||
/*
|
||||
* 'n' events have been read. Here we map them to their
|
||||
* corresponding channel in batch and queue n-1 so that
|
||||
@ -203,14 +209,14 @@ final class KQueuePort
|
||||
fdToChannelLock.readLock().lock();
|
||||
try {
|
||||
while (n-- > 0) {
|
||||
long keventAddress = getEvent(address, n);
|
||||
int fd = getDescriptor(keventAddress);
|
||||
long keventAddress = KQueue.getEvent(address, n);
|
||||
int fd = KQueue.getDescriptor(keventAddress);
|
||||
|
||||
// wakeup
|
||||
if (fd == sp[0]) {
|
||||
if (wakeupCount.decrementAndGet() == 0) {
|
||||
// no more wakeups so drain pipe
|
||||
drain1(sp[0]);
|
||||
IOUtil.drain(sp[0]);
|
||||
}
|
||||
|
||||
// queue special event if there are more events
|
||||
@ -224,7 +230,7 @@ final class KQueuePort
|
||||
|
||||
PollableChannel channel = fdToChannel.get(fd);
|
||||
if (channel != null) {
|
||||
int filter = getFilter(keventAddress);
|
||||
int filter = KQueue.getFilter(keventAddress);
|
||||
int events = 0;
|
||||
if (filter == EVFILT_READ)
|
||||
events = Net.POLLIN;
|
||||
@ -314,18 +320,4 @@ final class KQueuePort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native void socketpair(int[] sv) throws IOException;
|
||||
|
||||
private static native void interrupt(int fd) throws IOException;
|
||||
|
||||
private static native void drain1(int fd) throws IOException;
|
||||
|
||||
private static native void close0(int fd);
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,6 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* KQueueSelectorImpl.java
|
||||
* Implementation of Selector using FreeBSD / Mac OS X kqueues
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -36,85 +31,111 @@ import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.BitSet;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class KQueueSelectorImpl
|
||||
extends SelectorImpl
|
||||
{
|
||||
// File descriptors used for interrupt
|
||||
import static sun.nio.ch.KQueue.EVFILT_READ;
|
||||
import static sun.nio.ch.KQueue.EVFILT_WRITE;
|
||||
import static sun.nio.ch.KQueue.EV_ADD;
|
||||
import static sun.nio.ch.KQueue.EV_DELETE;
|
||||
|
||||
/**
|
||||
* KQueue based Selector implementation for macOS
|
||||
*/
|
||||
|
||||
class KQueueSelectorImpl extends SelectorImpl {
|
||||
|
||||
// maximum number of events to poll in one call to kqueue
|
||||
private static final int MAX_KEVENTS = 256;
|
||||
|
||||
// kqueue file descriptor
|
||||
private final int kqfd;
|
||||
|
||||
// address of poll array (event list) when polling for pending events
|
||||
private final long pollArrayAddress;
|
||||
|
||||
// file descriptors used for interrupt
|
||||
private final int fd0;
|
||||
private final int fd1;
|
||||
|
||||
// The kqueue manipulator
|
||||
private final KQueueArrayWrapper kqueueWrapper;
|
||||
// maps file descriptor to selection key, synchronize on selector
|
||||
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
|
||||
|
||||
// Map from a file descriptor to an entry containing the selection key
|
||||
private final HashMap<Integer, MapEntry> fdMap;
|
||||
// file descriptors registered with kqueue, synchronize on selector
|
||||
private final BitSet registeredReadFilter = new BitSet();
|
||||
private final BitSet registeredWriteFilter = new BitSet();
|
||||
|
||||
// True if this Selector has been closed
|
||||
private boolean closed;
|
||||
// pending new registrations/updates, queued by implRegister and putEventOps
|
||||
private final Object updateLock = new Object();
|
||||
private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
|
||||
private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
|
||||
private final Deque<Integer> updateOps = new ArrayDeque<>();
|
||||
|
||||
// Lock for interrupt triggering and clearing
|
||||
// interrupt triggering and clearing
|
||||
private final Object interruptLock = new Object();
|
||||
private boolean interruptTriggered;
|
||||
|
||||
// used by updateSelectedKeys to handle cases where the same file
|
||||
// descriptor is polled by more than one filter
|
||||
private long updateCount;
|
||||
private int pollCount;
|
||||
|
||||
// Used to map file descriptors to a selection key and "update count"
|
||||
// (see updateSelectedKeys for usage).
|
||||
private static class MapEntry {
|
||||
SelectionKeyImpl ski;
|
||||
long updateCount;
|
||||
MapEntry(SelectionKeyImpl ski) {
|
||||
this.ski = ski;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private constructor called by factory method in
|
||||
* the abstract superclass Selector.
|
||||
*/
|
||||
KQueueSelectorImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp);
|
||||
long fds = IOUtil.makePipe(false);
|
||||
fd0 = (int)(fds >>> 32);
|
||||
fd1 = (int)fds;
|
||||
|
||||
this.kqfd = KQueue.create();
|
||||
this.pollArrayAddress = KQueue.allocatePollArray(MAX_KEVENTS);
|
||||
|
||||
try {
|
||||
kqueueWrapper = new KQueueArrayWrapper(fd0, fd1);
|
||||
fdMap = new HashMap<>();
|
||||
} catch (Throwable t) {
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
} catch (IOException ioe0) {
|
||||
t.addSuppressed(ioe0);
|
||||
}
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
} catch (IOException ioe1) {
|
||||
t.addSuppressed(ioe1);
|
||||
}
|
||||
throw t;
|
||||
long fds = IOUtil.makePipe(false);
|
||||
this.fd0 = (int) (fds >>> 32);
|
||||
this.fd1 = (int) fds;
|
||||
} catch (IOException ioe) {
|
||||
KQueue.freePollArray(pollArrayAddress);
|
||||
FileDispatcherImpl.closeIntFD(kqfd);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
// register one end of the socket pair for wakeups
|
||||
KQueue.register(kqfd, fd0, EVFILT_READ, EV_ADD);
|
||||
}
|
||||
|
||||
private void ensureOpen() {
|
||||
if (closed)
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doSelect(long timeout)
|
||||
throws IOException
|
||||
{
|
||||
ensureOpen();
|
||||
protected int doSelect(long timeout) throws IOException {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
int numEntries;
|
||||
processUpdateQueue();
|
||||
processDeregisterQueue();
|
||||
try {
|
||||
begin();
|
||||
numEntries = kqueueWrapper.poll(timeout);
|
||||
|
||||
long to = Math.min(timeout, Integer.MAX_VALUE); // max kqueue timeout
|
||||
boolean timedPoll = (to > 0);
|
||||
do {
|
||||
long startTime = timedPoll ? System.nanoTime() : 0;
|
||||
numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, to);
|
||||
if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
|
||||
// timed poll interrupted so need to adjust timeout
|
||||
long adjust = System.nanoTime() - startTime;
|
||||
to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
|
||||
if (to <= 0) {
|
||||
// timeout expired so no retry
|
||||
numEntries = 0;
|
||||
}
|
||||
}
|
||||
} while (numEntries == IOStatus.INTERRUPTED);
|
||||
assert IOStatus.check(numEntries);
|
||||
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
@ -122,40 +143,101 @@ class KQueueSelectorImpl
|
||||
return updateSelectedKeys(numEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process new registrations and changes to the interest ops.
|
||||
*/
|
||||
private void processUpdateQueue() {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
synchronized (updateLock) {
|
||||
SelectionKeyImpl ski;
|
||||
|
||||
// new registrations
|
||||
while ((ski = newKeys.pollFirst()) != null) {
|
||||
if (ski.isValid()) {
|
||||
SelChImpl ch = ski.channel;
|
||||
int fd = ch.getFDVal();
|
||||
SelectionKeyImpl previous = fdToKey.put(fd, ski);
|
||||
assert previous == null;
|
||||
assert registeredReadFilter.get(fd) == false;
|
||||
assert registeredWriteFilter.get(fd) == false;
|
||||
}
|
||||
}
|
||||
|
||||
// changes to interest ops
|
||||
assert updateKeys.size() == updateOps.size();
|
||||
while ((ski = updateKeys.pollFirst()) != null) {
|
||||
int ops = updateOps.pollFirst();
|
||||
int fd = ski.channel.getFDVal();
|
||||
if (ski.isValid() && fdToKey.containsKey(fd)) {
|
||||
// add or delete interest in read events
|
||||
if (registeredReadFilter.get(fd)) {
|
||||
if ((ops & Net.POLLIN) == 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
|
||||
registeredReadFilter.clear(fd);
|
||||
}
|
||||
} else if ((ops & Net.POLLIN) != 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_READ, EV_ADD);
|
||||
registeredReadFilter.set(fd);
|
||||
}
|
||||
|
||||
// add or delete interest in write events
|
||||
if (registeredWriteFilter.get(fd)) {
|
||||
if ((ops & Net.POLLOUT) == 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
|
||||
registeredWriteFilter.clear(fd);
|
||||
}
|
||||
} else if ((ops & Net.POLLOUT) != 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_ADD);
|
||||
registeredWriteFilter.set(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the keys whose fd's have been selected by kqueue.
|
||||
* Add the ready keys to the selected key set.
|
||||
* If the interrupt fd has been selected, drain it and clear the interrupt.
|
||||
*/
|
||||
private int updateSelectedKeys(int numEntries)
|
||||
throws IOException
|
||||
{
|
||||
private int updateSelectedKeys(int numEntries) throws IOException {
|
||||
assert Thread.holdsLock(this);
|
||||
assert Thread.holdsLock(nioSelectedKeys());
|
||||
|
||||
int numKeysUpdated = 0;
|
||||
boolean interrupted = false;
|
||||
|
||||
// A file descriptor may be registered with kqueue with more than one
|
||||
// filter and so there may be more than one event for a fd. The update
|
||||
// count in the MapEntry tracks when the fd was last updated and this
|
||||
// ensures that the ready ops are updated rather than replaced by a
|
||||
// second or subsequent event.
|
||||
updateCount++;
|
||||
// filter and so there may be more than one event for a fd. The poll
|
||||
// count is incremented here and compared against the SelectionKey's
|
||||
// "lastPolled" field. This ensures that the ready ops is updated rather
|
||||
// than replaced when a file descriptor is polled by both the read and
|
||||
// write filter.
|
||||
pollCount++;
|
||||
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
int nextFD = kqueueWrapper.getDescriptor(i);
|
||||
if (nextFD == fd0) {
|
||||
long kevent = KQueue.getEvent(pollArrayAddress, i);
|
||||
int fd = KQueue.getDescriptor(kevent);
|
||||
if (fd == fd0) {
|
||||
interrupted = true;
|
||||
} else {
|
||||
MapEntry me = fdMap.get(Integer.valueOf(nextFD));
|
||||
if (me != null) {
|
||||
int rOps = kqueueWrapper.getReventOps(i);
|
||||
SelectionKeyImpl ski = me.ski;
|
||||
SelectionKeyImpl ski = fdToKey.get(fd);
|
||||
if (ski != null) {
|
||||
int rOps = 0;
|
||||
short filter = KQueue.getFilter(kevent);
|
||||
if (filter == EVFILT_READ) {
|
||||
rOps |= Net.POLLIN;
|
||||
} else if (filter == EVFILT_WRITE) {
|
||||
rOps |= Net.POLLOUT;
|
||||
}
|
||||
|
||||
if (selectedKeys.contains(ski)) {
|
||||
// first time this file descriptor has been encountered on this
|
||||
// update?
|
||||
if (me.updateCount != updateCount) {
|
||||
// file descriptor may be polled more than once per poll
|
||||
if (ski.lastPolled != pollCount) {
|
||||
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
|
||||
numKeysUpdated++;
|
||||
me.updateCount = updateCount;
|
||||
ski.lastPolled = pollCount;
|
||||
}
|
||||
} else {
|
||||
// ready ops have already been set on this update
|
||||
@ -166,7 +248,7 @@ class KQueueSelectorImpl
|
||||
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
|
||||
selectedKeys.add(ski);
|
||||
numKeysUpdated++;
|
||||
me.updateCount = updateCount;
|
||||
ski.lastPolled = pollCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,63 +263,90 @@ class KQueueSelectorImpl
|
||||
|
||||
@Override
|
||||
protected void implClose() throws IOException {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
assert !isOpen();
|
||||
assert Thread.holdsLock(this);
|
||||
assert Thread.holdsLock(nioKeys());
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
kqueueWrapper.close();
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
FileDispatcherImpl.closeIntFD(kqfd);
|
||||
KQueue.freePollArray(pollArrayAddress);
|
||||
|
||||
// Deregister channels
|
||||
Iterator<SelectionKey> i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
|
||||
// Deregister channels
|
||||
Iterator<SelectionKey> i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
assert Thread.holdsLock(nioKeys());
|
||||
ensureOpen();
|
||||
int fd = IOUtil.fdVal(ski.channel.getFD());
|
||||
fdMap.put(Integer.valueOf(fd), new MapEntry(ski));
|
||||
synchronized (updateLock) {
|
||||
newKeys.addLast(ski);
|
||||
}
|
||||
keys.add(ski);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
assert !ski.isValid();
|
||||
assert Thread.holdsLock(this);
|
||||
assert Thread.holdsLock(nioKeys());
|
||||
assert Thread.holdsLock(nioSelectedKeys());
|
||||
|
||||
int fd = ski.channel.getFDVal();
|
||||
fdMap.remove(Integer.valueOf(fd));
|
||||
kqueueWrapper.release(ski.channel);
|
||||
keys.remove(ski);
|
||||
fdToKey.remove(fd);
|
||||
if (registeredReadFilter.get(fd)) {
|
||||
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
|
||||
registeredReadFilter.clear(fd);
|
||||
}
|
||||
if (registeredWriteFilter.get(fd)) {
|
||||
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
|
||||
registeredWriteFilter.clear(fd);
|
||||
}
|
||||
|
||||
selectedKeys.remove(ski);
|
||||
keys.remove(ski);
|
||||
|
||||
// remove from channel's key set
|
||||
deregister(ski);
|
||||
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
((SelChImpl) selch).kill();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putEventOps(SelectionKeyImpl ski, int ops) {
|
||||
ensureOpen();
|
||||
kqueueWrapper.setInterest(ski.channel, ops);
|
||||
synchronized (updateLock) {
|
||||
updateOps.addLast(ops); // ops first in case adding the key fails
|
||||
updateKeys.addLast(ski);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Selector wakeup() {
|
||||
synchronized (interruptLock) {
|
||||
if (!interruptTriggered) {
|
||||
kqueueWrapper.interrupt();
|
||||
try {
|
||||
IOUtil.write1(fd1, (byte)0);
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
|
@ -23,17 +23,10 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* KQueueSelectorProvider.java
|
||||
* Implementation of Selector using FreeBSD / Mac OS X kqueues
|
||||
* Derived from Sun's DevPollSelectorProvider
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.nio.channels.spi.AbstractSelector;
|
||||
|
||||
public class KQueueSelectorProvider
|
||||
extends SelectorProviderImpl
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,7 +26,6 @@
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.spi.FileTypeDetector;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
@ -46,7 +45,7 @@ public class MacOSXFileSystemProvider extends BsdFileSystemProvider {
|
||||
|
||||
@Override
|
||||
FileTypeDetector getFileTypeDetector() {
|
||||
Path userMimeTypes = Paths.get(GetPropertyAction
|
||||
Path userMimeTypes = Path.of(GetPropertyAction
|
||||
.privilegedGetProperty("user.home"), ".mime.types");
|
||||
|
||||
return chain(new MimeTypesFileTypeDetector(userMimeTypes),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,76 +23,91 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_KQueue.h"
|
||||
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jlong.h"
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_KQueue.h"
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_keventSize(JNIEnv* env, jclass this)
|
||||
Java_sun_nio_ch_KQueue_keventSize(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return sizeof(struct kevent);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_identOffset(JNIEnv* env, jclass this)
|
||||
Java_sun_nio_ch_KQueue_identOffset(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return offsetof(struct kevent, ident);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_filterOffset(JNIEnv* env, jclass this)
|
||||
Java_sun_nio_ch_KQueue_filterOffset(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return offsetof(struct kevent, filter);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_flagsOffset(JNIEnv* env, jclass this)
|
||||
Java_sun_nio_ch_KQueue_flagsOffset(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return offsetof(struct kevent, flags);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_kqueue(JNIEnv *env, jclass c) {
|
||||
Java_sun_nio_ch_KQueue_create(JNIEnv *env, jclass clazz) {
|
||||
int kqfd = kqueue();
|
||||
if (kqfd < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
return kqfd;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_keventRegister(JNIEnv *env, jclass c, jint kqfd,
|
||||
jint fd, jint filter, jint flags)
|
||||
Java_sun_nio_ch_KQueue_register(JNIEnv *env, jclass clazz, jint kqfd,
|
||||
jint fd, jint filter, jint flags)
|
||||
|
||||
{
|
||||
struct kevent changes[1];
|
||||
struct timespec timeout = {0, 0};
|
||||
int res;
|
||||
|
||||
EV_SET(&changes[0], fd, filter, flags, 0, 0, 0);
|
||||
RESTARTABLE(kevent(kqfd, &changes[0], 1, NULL, 0, &timeout), res);
|
||||
RESTARTABLE(kevent(kqfd, &changes[0], 1, NULL, 0, NULL), res);
|
||||
return (res == -1) ? errno : 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueue_keventPoll(JNIEnv *env, jclass c,
|
||||
jint kqfd, jlong address, jint nevents)
|
||||
Java_sun_nio_ch_KQueue_poll(JNIEnv *env, jclass clazz, jint kqfd, jlong address,
|
||||
jint nevents, jlong timeout)
|
||||
{
|
||||
struct kevent *events = jlong_to_ptr(address);
|
||||
int res;
|
||||
struct timespec ts;
|
||||
struct timespec *tsp;
|
||||
|
||||
RESTARTABLE(kevent(kqfd, NULL, 0, events, nevents, NULL), res);
|
||||
if (timeout >= 0) {
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000000;
|
||||
tsp = &ts;
|
||||
} else {
|
||||
tsp = NULL;
|
||||
}
|
||||
|
||||
res = kevent(kqfd, NULL, 0, events, nevents, tsp);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
|
||||
if (errno == EINTR) {
|
||||
return IOS_INTERRUPTED;
|
||||
} else {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "kqueue failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* KQueueArrayWrapper.c
|
||||
* Implementation of Selector using FreeBSD / Mac OS X kqueues
|
||||
* Derived from Sun's DevPollArrayWrapper
|
||||
*/
|
||||
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_initStructSizes(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
#define CHECK_EXCEPTION() { \
|
||||
if ((*env)->ExceptionCheck(env)) { \
|
||||
goto exceptionOccurred; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_ERROR_AND_EXCEPTION(_field) { \
|
||||
if (_field == NULL) { \
|
||||
goto badField; \
|
||||
} \
|
||||
CHECK_EXCEPTION(); \
|
||||
}
|
||||
|
||||
|
||||
jfieldID field;
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_READ", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, EVFILT_READ);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_WRITE", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, EVFILT_WRITE);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "SIZEOF_KEVENT", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, (short) sizeof(struct kevent));
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "FD_OFFSET", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, ident));
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
field = (*env)->GetStaticFieldID(env, clazz, "FILTER_OFFSET", "S");
|
||||
CHECK_ERROR_AND_EXCEPTION(field);
|
||||
(*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, filter));
|
||||
CHECK_EXCEPTION();
|
||||
return;
|
||||
|
||||
badField:
|
||||
return;
|
||||
|
||||
exceptionOccurred:
|
||||
return;
|
||||
|
||||
#undef CHECK_EXCEPTION
|
||||
#undef CHECK_ERROR_AND_EXCEPTION
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_init(JNIEnv *env, jobject this)
|
||||
{
|
||||
int kq = kqueue();
|
||||
if (kq < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue() failed");
|
||||
}
|
||||
return kq;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_register0(JNIEnv *env, jobject this,
|
||||
jint kq, jint fd, jint r, jint w)
|
||||
{
|
||||
struct kevent changes[2];
|
||||
struct kevent errors[2];
|
||||
struct timespec dontBlock = {0, 0};
|
||||
|
||||
// if (r) then { register for read } else { unregister for read }
|
||||
// if (w) then { register for write } else { unregister for write }
|
||||
// Ignore errors - they're probably complaints about deleting non-
|
||||
// added filters - but provide an error array anyway because
|
||||
// kqueue behaves erratically if some of its registrations fail.
|
||||
EV_SET(&changes[0], fd, EVFILT_READ, r ? EV_ADD : EV_DELETE, 0, 0, 0);
|
||||
EV_SET(&changes[1], fd, EVFILT_WRITE, w ? EV_ADD : EV_DELETE, 0, 0, 0);
|
||||
kevent(kq, changes, 2, errors, 2, &dontBlock);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_kevent0(JNIEnv *env, jobject this, jint kq,
|
||||
jlong kevAddr, jint kevCount,
|
||||
jlong timeout)
|
||||
{
|
||||
struct kevent *kevs = (struct kevent *)jlong_to_ptr(kevAddr);
|
||||
struct timespec ts;
|
||||
struct timespec *tsp;
|
||||
int result;
|
||||
|
||||
// Java timeout is in milliseconds. Convert to struct timespec.
|
||||
// Java timeout == -1 : wait forever : timespec timeout of NULL
|
||||
// Java timeout == 0 : return immediately : timespec timeout of zero
|
||||
if (timeout >= 0) {
|
||||
// For some indeterminate reason kevent(2) has been found to fail with
|
||||
// an EINVAL error for timeout values greater than or equal to
|
||||
// 100000001000L. To avoid this problem, clamp the timeout arbitrarily
|
||||
// to the maximum value of a 32-bit signed integer which is
|
||||
// approximately 25 days in milliseconds.
|
||||
const jlong timeoutMax = 0x7fffffff; // java.lang.Integer.MAX_VALUE
|
||||
if (timeout > timeoutMax) {
|
||||
timeout = timeoutMax;
|
||||
}
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000000; //nanosec = 1 million millisec
|
||||
tsp = &ts;
|
||||
} else {
|
||||
tsp = NULL;
|
||||
}
|
||||
|
||||
RESTARTABLE(kevent(kq, NULL, 0, kevs, kevCount, tsp), result);
|
||||
if (result < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env,
|
||||
"KQueueArrayWrapper: kevent poll failed");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueueArrayWrapper_interrupt(JNIEnv *env, jclass cls, jint fd)
|
||||
{
|
||||
char c = 1;
|
||||
if (1 != write(fd, &c, 1)) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: interrupt failed");
|
||||
}
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_KQueuePort.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueuePort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
|
||||
int sp[2];
|
||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
|
||||
} else {
|
||||
jint res[2];
|
||||
res[0] = (jint)sp[0];
|
||||
res[1] = (jint)sp[1];
|
||||
(*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueuePort_interrupt(JNIEnv *env, jclass c, jint fd) {
|
||||
int res;
|
||||
int buf[1];
|
||||
buf[0] = 1;
|
||||
RESTARTABLE(write(fd, buf, 1), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "write failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueuePort_drain1(JNIEnv *env, jclass cl, jint fd) {
|
||||
int res;
|
||||
char buf[1];
|
||||
RESTARTABLE(read(fd, buf, 1), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "drain1 failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_KQueuePort_close0(JNIEnv *env, jclass c, jint fd) {
|
||||
int res;
|
||||
RESTARTABLE(close(fd), res);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,12 +25,15 @@
|
||||
|
||||
package java.io;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A <code>ByteArrayInputStream</code> contains
|
||||
* A {@code ByteArrayInputStream} contains
|
||||
* an internal buffer that contains bytes that
|
||||
* may be read from the stream. An internal
|
||||
* counter keeps track of the next byte to
|
||||
* be supplied by the <code>read</code> method.
|
||||
* be supplied by the {@code read} method.
|
||||
* <p>
|
||||
* Closing a {@code ByteArrayInputStream} has no effect. The methods in
|
||||
* this class can be called after the stream has been closed without
|
||||
@ -40,15 +43,14 @@ package java.io;
|
||||
* @see java.io.StringBufferInputStream
|
||||
* @since 1.0
|
||||
*/
|
||||
public
|
||||
class ByteArrayInputStream extends InputStream {
|
||||
public class ByteArrayInputStream extends InputStream {
|
||||
|
||||
/**
|
||||
* An array of bytes that was provided
|
||||
* by the creator of the stream. Elements <code>buf[0]</code>
|
||||
* through <code>buf[count-1]</code> are the
|
||||
* by the creator of the stream. Elements {@code buf[0]}
|
||||
* through {@code buf[count-1]} are the
|
||||
* only bytes that can ever be read from the
|
||||
* stream; element <code>buf[pos]</code> is
|
||||
* stream; element {@code buf[pos]} is
|
||||
* the next byte to be read.
|
||||
*/
|
||||
protected byte buf[];
|
||||
@ -56,9 +58,9 @@ class ByteArrayInputStream extends InputStream {
|
||||
/**
|
||||
* The index of the next character to read from the input stream buffer.
|
||||
* This value should always be nonnegative
|
||||
* and not larger than the value of <code>count</code>.
|
||||
* and not larger than the value of {@code count}.
|
||||
* The next byte to be read from the input stream buffer
|
||||
* will be <code>buf[pos]</code>.
|
||||
* will be {@code buf[pos]}.
|
||||
*/
|
||||
protected int pos;
|
||||
|
||||
@ -66,9 +68,9 @@ class ByteArrayInputStream extends InputStream {
|
||||
* The currently marked position in the stream.
|
||||
* ByteArrayInputStream objects are marked at position zero by
|
||||
* default when constructed. They may be marked at another
|
||||
* position within the buffer by the <code>mark()</code> method.
|
||||
* position within the buffer by the {@code mark()} method.
|
||||
* The current buffer position is set to this point by the
|
||||
* <code>reset()</code> method.
|
||||
* {@code reset()} method.
|
||||
* <p>
|
||||
* If no mark has been set, then the value of mark is the offset
|
||||
* passed to the constructor (or 0 if the offset was not supplied).
|
||||
@ -81,22 +83,22 @@ class ByteArrayInputStream extends InputStream {
|
||||
* The index one greater than the last valid character in the input
|
||||
* stream buffer.
|
||||
* This value should always be nonnegative
|
||||
* and not larger than the length of <code>buf</code>.
|
||||
* and not larger than the length of {@code buf}.
|
||||
* It is one greater than the position of
|
||||
* the last byte within <code>buf</code> that
|
||||
* the last byte within {@code buf} that
|
||||
* can ever be read from the input stream buffer.
|
||||
*/
|
||||
protected int count;
|
||||
|
||||
/**
|
||||
* Creates a <code>ByteArrayInputStream</code>
|
||||
* so that it uses <code>buf</code> as its
|
||||
* Creates a {@code ByteArrayInputStream}
|
||||
* so that it uses {@code buf} as its
|
||||
* buffer array.
|
||||
* The buffer array is not copied.
|
||||
* The initial value of <code>pos</code>
|
||||
* is <code>0</code> and the initial value
|
||||
* of <code>count</code> is the length of
|
||||
* <code>buf</code>.
|
||||
* The initial value of {@code pos}
|
||||
* is {@code 0} and the initial value
|
||||
* of {@code count} is the length of
|
||||
* {@code buf}.
|
||||
*
|
||||
* @param buf the input buffer.
|
||||
*/
|
||||
@ -107,12 +109,12 @@ class ByteArrayInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates <code>ByteArrayInputStream</code>
|
||||
* that uses <code>buf</code> as its
|
||||
* buffer array. The initial value of <code>pos</code>
|
||||
* is <code>offset</code> and the initial value
|
||||
* of <code>count</code> is the minimum of <code>offset+length</code>
|
||||
* and <code>buf.length</code>.
|
||||
* Creates {@code ByteArrayInputStream}
|
||||
* that uses {@code buf} as its
|
||||
* buffer array. The initial value of {@code pos}
|
||||
* is {@code offset} and the initial value
|
||||
* of {@code count} is the minimum of {@code offset+length}
|
||||
* and {@code buf.length}.
|
||||
* The buffer array is not copied. The buffer's mark is
|
||||
* set to the specified offset.
|
||||
*
|
||||
@ -129,15 +131,15 @@ class ByteArrayInputStream extends InputStream {
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from this input stream. The value
|
||||
* byte is returned as an <code>int</code> in the range
|
||||
* <code>0</code> to <code>255</code>. If no byte is available
|
||||
* byte is returned as an {@code int} in the range
|
||||
* {@code 0} to {@code 255}. If no byte is available
|
||||
* because the end of the stream has been reached, the value
|
||||
* <code>-1</code> is returned.
|
||||
* {@code -1} is returned.
|
||||
* <p>
|
||||
* This <code>read</code> method
|
||||
* This {@code read} method
|
||||
* cannot block.
|
||||
*
|
||||
* @return the next byte of data, or <code>-1</code> if the end of the
|
||||
* @return the next byte of data, or {@code -1} if the end of the
|
||||
* stream has been reached.
|
||||
*/
|
||||
public synchronized int read() {
|
||||
@ -145,40 +147,30 @@ class ByteArrayInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to <code>len</code> bytes of data into an array of bytes
|
||||
* from this input stream.
|
||||
* If <code>pos</code> equals <code>count</code>,
|
||||
* then <code>-1</code> is returned to indicate
|
||||
* end of file. Otherwise, the number <code>k</code>
|
||||
* of bytes read is equal to the smaller of
|
||||
* <code>len</code> and <code>count-pos</code>.
|
||||
* If <code>k</code> is positive, then bytes
|
||||
* <code>buf[pos]</code> through <code>buf[pos+k-1]</code>
|
||||
* are copied into <code>b[off]</code> through
|
||||
* <code>b[off+k-1]</code> in the manner performed
|
||||
* by <code>System.arraycopy</code>. The
|
||||
* value <code>k</code> is added into <code>pos</code>
|
||||
* and <code>k</code> is returned.
|
||||
* Reads up to {@code len} bytes of data into an array of bytes from this
|
||||
* input stream. If {@code pos} equals {@code count}, then {@code -1} is
|
||||
* returned to indicate end of file. Otherwise, the number {@code k} of
|
||||
* bytes read is equal to the smaller of {@code len} and {@code count-pos}.
|
||||
* If {@code k} is positive, then bytes {@code buf[pos]} through
|
||||
* {@code buf[pos+k-1]} are copied into {@code b[off]} through
|
||||
* {@code b[off+k-1]} in the manner performed by {@code System.arraycopy}.
|
||||
* The value {@code k} is added into {@code pos} and {@code k} is returned.
|
||||
* <p>
|
||||
* This <code>read</code> method cannot block.
|
||||
* This {@code read} method cannot block.
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
* @param off the start offset in the destination array <code>b</code>
|
||||
* @param off the start offset in the destination array {@code b}
|
||||
* @param len the maximum number of bytes read.
|
||||
* @return the total number of bytes read into the buffer, or
|
||||
* <code>-1</code> if there is no more data because the end of
|
||||
* {@code -1} if there is no more data because the end of
|
||||
* the stream has been reached.
|
||||
* @exception NullPointerException If <code>b</code> is <code>null</code>.
|
||||
* @exception IndexOutOfBoundsException If <code>off</code> is negative,
|
||||
* <code>len</code> is negative, or <code>len</code> is greater than
|
||||
* <code>b.length - off</code>
|
||||
* @throws NullPointerException If {@code b} is {@code null}.
|
||||
* @throws IndexOutOfBoundsException If {@code off} is negative,
|
||||
* {@code len} is negative, or {@code len} is greater than
|
||||
* {@code b.length - off}
|
||||
*/
|
||||
public synchronized int read(byte b[], int off, int len) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (off < 0 || len < 0 || len > b.length - off) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
Objects.checkFromIndexSize(off, len, b.length);
|
||||
|
||||
if (pos >= count) {
|
||||
return -1;
|
||||
@ -196,14 +188,32 @@ class ByteArrayInputStream extends InputStream {
|
||||
return len;
|
||||
}
|
||||
|
||||
public synchronized byte[] readAllBytes() {
|
||||
byte[] result = Arrays.copyOfRange(buf, pos, count);
|
||||
pos = count;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int readNBytes(byte[] b, int off, int len) {
|
||||
int n = read(b, off, len);
|
||||
return n == -1 ? 0 : n;
|
||||
}
|
||||
|
||||
public synchronized long transferTo(OutputStream out) throws IOException {
|
||||
int len = count - pos;
|
||||
out.write(buf, pos, len);
|
||||
pos = count;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips <code>n</code> bytes of input from this input stream. Fewer
|
||||
* Skips {@code n} bytes of input from this input stream. Fewer
|
||||
* bytes might be skipped if the end of the input stream is reached.
|
||||
* The actual number <code>k</code>
|
||||
* The actual number {@code k}
|
||||
* of bytes to be skipped is equal to the smaller
|
||||
* of <code>n</code> and <code>count-pos</code>.
|
||||
* The value <code>k</code> is added into <code>pos</code>
|
||||
* and <code>k</code> is returned.
|
||||
* of {@code n} and {@code count-pos}.
|
||||
* The value {@code k} is added into {@code pos}
|
||||
* and {@code k} is returned.
|
||||
*
|
||||
* @param n the number of bytes to be skipped.
|
||||
* @return the actual number of bytes skipped.
|
||||
@ -222,7 +232,7 @@ class ByteArrayInputStream extends InputStream {
|
||||
* Returns the number of remaining bytes that can be read (or skipped over)
|
||||
* from this input stream.
|
||||
* <p>
|
||||
* The value returned is <code>count - pos</code>,
|
||||
* The value returned is {@code count - pos},
|
||||
* which is the number of bytes remaining to be read from the input buffer.
|
||||
*
|
||||
* @return the number of remaining bytes that can be read (or skipped
|
||||
@ -233,9 +243,9 @@ class ByteArrayInputStream extends InputStream {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if this <code>InputStream</code> supports mark/reset. The
|
||||
* <code>markSupported</code> method of <code>ByteArrayInputStream</code>
|
||||
* always returns <code>true</code>.
|
||||
* Tests if this {@code InputStream} supports mark/reset. The
|
||||
* {@code markSupported} method of {@code ByteArrayInputStream}
|
||||
* always returns {@code true}.
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
@ -253,7 +263,7 @@ class ByteArrayInputStream extends InputStream {
|
||||
* offset passed to the constructor (or 0 if the offset was not
|
||||
* supplied).
|
||||
*
|
||||
* <p> Note: The <code>readAheadLimit</code> for this class
|
||||
* <p> Note: The {@code readAheadLimit} for this class
|
||||
* has no meaning.
|
||||
*
|
||||
* @since 1.1
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,7 +30,6 @@ import java.io.FilePermission;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Objects;
|
||||
@ -63,7 +62,7 @@ final class ProxyClassesDumper {
|
||||
}
|
||||
try {
|
||||
path = path.trim();
|
||||
final Path dir = Paths.get(path.length() == 0 ? "." : path);
|
||||
final Path dir = Path.of(path.length() == 0 ? "." : path);
|
||||
AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +34,6 @@ import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
@ -346,11 +345,11 @@ class ProxyGenerator {
|
||||
int i = name.lastIndexOf('.');
|
||||
Path path;
|
||||
if (i > 0) {
|
||||
Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
|
||||
Path dir = Path.of(name.substring(0, i).replace('.', File.separatorChar));
|
||||
Files.createDirectories(dir);
|
||||
path = dir.resolve(name.substring(i+1, name.length()) + ".class");
|
||||
} else {
|
||||
path = Paths.get(name + ".class");
|
||||
path = Path.of(name + ".class");
|
||||
}
|
||||
Files.write(path, classFile);
|
||||
return null;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -279,6 +279,9 @@ public abstract class DatagramChannel
|
||||
*
|
||||
* @return This datagram channel
|
||||
*
|
||||
* @throws AlreadyConnectedException
|
||||
* If this channel is already connected
|
||||
*
|
||||
* @throws ClosedChannelException
|
||||
* If this channel is closed
|
||||
*
|
||||
@ -292,6 +295,12 @@ public abstract class DatagramChannel
|
||||
* closing the channel and setting the current thread's
|
||||
* interrupt status
|
||||
*
|
||||
* @throws UnresolvedAddressException
|
||||
* If the given remote address is not fully resolved
|
||||
*
|
||||
* @throws UnsupportedAddressTypeException
|
||||
* If the type of the given remote address is not supported
|
||||
*
|
||||
* @throws SecurityException
|
||||
* If a security manager has been installed
|
||||
* and it does not permit access to the given remote address
|
||||
@ -444,6 +453,10 @@ public abstract class DatagramChannel
|
||||
* zero if there was insufficient room for the datagram in the
|
||||
* underlying output buffer
|
||||
*
|
||||
* @throws AlreadyConnectedException
|
||||
* If this channel is connected to a different address
|
||||
* from that specified by {@code target}
|
||||
*
|
||||
* @throws ClosedChannelException
|
||||
* If this channel is closed
|
||||
*
|
||||
@ -457,6 +470,12 @@ public abstract class DatagramChannel
|
||||
* closing the channel and setting the current thread's
|
||||
* interrupt status
|
||||
*
|
||||
* @throws UnresolvedAddressException
|
||||
* If the given remote address is not fully resolved
|
||||
*
|
||||
* @throws UnsupportedAddressTypeException
|
||||
* If the type of the given remote address is not supported
|
||||
*
|
||||
* @throws SecurityException
|
||||
* If a security manager has been installed
|
||||
* and it does not permit datagrams to be sent
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,6 +28,7 @@ package java.nio.file;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@ -93,12 +94,124 @@ import java.util.NoSuchElementException;
|
||||
* multiple concurrent threads.
|
||||
*
|
||||
* @since 1.7
|
||||
* @see Paths
|
||||
*/
|
||||
|
||||
public interface Path
|
||||
extends Comparable<Path>, Iterable<Path>, Watchable
|
||||
{
|
||||
/**
|
||||
* Returns a {@code Path} by converting a path string, or a sequence of
|
||||
* strings that when joined form a path string. If {@code more} does not
|
||||
* specify any elements then the value of the {@code first} parameter is
|
||||
* the path string to convert. If {@code more} specifies one or more
|
||||
* elements then each non-empty string, including {@code first}, is
|
||||
* considered to be a sequence of name elements and is joined to form a
|
||||
* path string. The details as to how the Strings are joined is provider
|
||||
* specific but typically they will be joined using the
|
||||
* {@link FileSystem#getSeparator name-separator} as the separator.
|
||||
* For example, if the name separator is "{@code /}" and
|
||||
* {@code getPath("/foo","bar","gus")} is invoked, then the path string
|
||||
* {@code "/foo/bar/gus"} is converted to a {@code Path}. A {@code Path}
|
||||
* representing an empty path is returned if {@code first} is the empty
|
||||
* string and {@code more} does not contain any non-empty strings.
|
||||
*
|
||||
* <p> The {@code Path} is obtained by invoking the {@link FileSystem#getPath
|
||||
* getPath} method of the {@link FileSystems#getDefault default} {@link
|
||||
* FileSystem}.
|
||||
*
|
||||
* <p> Note that while this method is very convenient, using it will imply
|
||||
* an assumed reference to the default {@code FileSystem} and limit the
|
||||
* utility of the calling code. Hence it should not be used in library code
|
||||
* intended for flexible reuse. A more flexible alternative is to use an
|
||||
* existing {@code Path} instance as an anchor, such as:
|
||||
* <pre>{@code
|
||||
* Path dir = ...
|
||||
* Path path = dir.resolve("file");
|
||||
* }</pre>
|
||||
*
|
||||
* @param first
|
||||
* the path string or initial part of the path string
|
||||
* @param more
|
||||
* additional strings to be joined to form the path string
|
||||
*
|
||||
* @return the resulting {@code Path}
|
||||
*
|
||||
* @throws InvalidPathException
|
||||
* if the path string cannot be converted to a {@code Path}
|
||||
*
|
||||
* @see FileSystem#getPath
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public static Path of(String first, String... more) {
|
||||
return FileSystems.getDefault().getPath(first, more);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Path} by converting a URI.
|
||||
*
|
||||
* <p> This method iterates over the {@link FileSystemProvider#installedProviders()
|
||||
* installed} providers to locate the provider that is identified by the
|
||||
* URI {@link URI#getScheme scheme} of the given URI. URI schemes are
|
||||
* compared without regard to case. If the provider is found then its {@link
|
||||
* FileSystemProvider#getPath getPath} method is invoked to convert the
|
||||
* URI.
|
||||
*
|
||||
* <p> In the case of the default provider, identified by the URI scheme
|
||||
* "file", the given URI has a non-empty path component, and undefined query
|
||||
* and fragment components. Whether the authority component may be present
|
||||
* is platform specific. The returned {@code Path} is associated with the
|
||||
* {@link FileSystems#getDefault default} file system.
|
||||
*
|
||||
* <p> The default provider provides a similar <em>round-trip</em> guarantee
|
||||
* to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it
|
||||
* is guaranteed that
|
||||
* <blockquote>{@code
|
||||
* Path.of(}<i>p</i>{@code .}{@link Path#toUri() toUri}{@code ()).equals(}
|
||||
* <i>p</i>{@code .}{@link Path#toAbsolutePath() toAbsolutePath}{@code ())}
|
||||
* </blockquote>
|
||||
* so long as the original {@code Path}, the {@code URI}, and the new {@code
|
||||
* Path} are all created in (possibly different invocations of) the same
|
||||
* Java virtual machine. Whether other providers make any guarantees is
|
||||
* provider specific and therefore unspecified.
|
||||
*
|
||||
* @param uri
|
||||
* the URI to convert
|
||||
*
|
||||
* @return the resulting {@code Path}
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if preconditions on the {@code uri} parameter do not hold. The
|
||||
* format of the URI is provider specific.
|
||||
* @throws FileSystemNotFoundException
|
||||
* The file system, identified by the URI, does not exist and
|
||||
* cannot be created automatically, or the provider identified by
|
||||
* the URI's scheme component is not installed
|
||||
* @throws SecurityException
|
||||
* if a security manager is installed and it denies an unspecified
|
||||
* permission to access the file system
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public static Path of(URI uri) {
|
||||
String scheme = uri.getScheme();
|
||||
if (scheme == null)
|
||||
throw new IllegalArgumentException("Missing scheme");
|
||||
|
||||
// check for default provider to avoid loading of installed providers
|
||||
if (scheme.equalsIgnoreCase("file"))
|
||||
return FileSystems.getDefault().provider().getPath(uri);
|
||||
|
||||
// try to find provider
|
||||
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
|
||||
if (provider.getScheme().equalsIgnoreCase(scheme)) {
|
||||
return provider.getPath(uri);
|
||||
}
|
||||
}
|
||||
|
||||
throw new FileSystemNotFoundException("Provider \"" + scheme + "\" not installed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file system that created this object.
|
||||
*
|
||||
@ -527,7 +640,7 @@ public interface Path
|
||||
* to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it
|
||||
* is guaranteed that
|
||||
* <blockquote>
|
||||
* {@link Paths#get(URI) Paths.get}{@code (}<i>p</i>{@code .toUri()).equals(}<i>p</i>
|
||||
* {@link Path#of(URI) Path.of}{@code (}<i>p</i>{@code .toUri()).equals(}<i>p</i>
|
||||
* {@code .}{@link #toAbsolutePath() toAbsolutePath}{@code ())}
|
||||
* </blockquote>
|
||||
* so long as the original {@code Path}, the {@code URI}, and the new {@code
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,7 +32,13 @@ import java.net.URI;
|
||||
* This class consists exclusively of static methods that return a {@link Path}
|
||||
* by converting a path string or {@link URI}.
|
||||
*
|
||||
* @apiNote
|
||||
* It is recommended to obtain a {@code Path} via the {@code Path.of} methods
|
||||
* instead of via the {@code get} methods defined in this class as this class
|
||||
* may be deprecated in a future release.
|
||||
*
|
||||
* @since 1.7
|
||||
* @see Path
|
||||
*/
|
||||
|
||||
public final class Paths {
|
||||
@ -40,33 +46,11 @@ public final class Paths {
|
||||
|
||||
/**
|
||||
* Converts a path string, or a sequence of strings that when joined form
|
||||
* a path string, to a {@code Path}. If {@code more} does not specify any
|
||||
* elements then the value of the {@code first} parameter is the path string
|
||||
* to convert. If {@code more} specifies one or more elements then each
|
||||
* non-empty string, including {@code first}, is considered to be a sequence
|
||||
* of name elements (see {@link Path}) and is joined to form a path string.
|
||||
* The details as to how the Strings are joined is provider specific but
|
||||
* typically they will be joined using the {@link FileSystem#getSeparator
|
||||
* name-separator} as the separator. For example, if the name separator is
|
||||
* "{@code /}" and {@code getPath("/foo","bar","gus")} is invoked, then the
|
||||
* path string {@code "/foo/bar/gus"} is converted to a {@code Path}.
|
||||
* A {@code Path} representing an empty path is returned if {@code first}
|
||||
* is the empty string and {@code more} does not contain any non-empty
|
||||
* strings.
|
||||
* a path string, to a {@code Path}.
|
||||
*
|
||||
* <p> The {@code Path} is obtained by invoking the {@link FileSystem#getPath
|
||||
* getPath} method of the {@link FileSystems#getDefault default} {@link
|
||||
* FileSystem}.
|
||||
*
|
||||
* <p> Note that while this method is very convenient, using it will imply
|
||||
* an assumed reference to the default {@code FileSystem} and limit the
|
||||
* utility of the calling code. Hence it should not be used in library code
|
||||
* intended for flexible reuse. A more flexible alternative is to use an
|
||||
* existing {@code Path} instance as an anchor, such as:
|
||||
* <pre>
|
||||
* Path dir = ...
|
||||
* Path path = dir.resolve("file");
|
||||
* </pre>
|
||||
* @implSpec
|
||||
* This method simply invokes {@link Path#of(String,String...)
|
||||
* Path.of(String, String...)} with the given parameters.
|
||||
*
|
||||
* @param first
|
||||
* the path string or initial part of the path string
|
||||
@ -79,38 +63,17 @@ public final class Paths {
|
||||
* if the path string cannot be converted to a {@code Path}
|
||||
*
|
||||
* @see FileSystem#getPath
|
||||
* @see Path#of(String,String...)
|
||||
*/
|
||||
public static Path get(String first, String... more) {
|
||||
return FileSystems.getDefault().getPath(first, more);
|
||||
return Path.of(first, more);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given URI to a {@link Path} object.
|
||||
*
|
||||
* <p> This method iterates over the {@link FileSystemProvider#installedProviders()
|
||||
* installed} providers to locate the provider that is identified by the
|
||||
* URI {@link URI#getScheme scheme} of the given URI. URI schemes are
|
||||
* compared without regard to case. If the provider is found then its {@link
|
||||
* FileSystemProvider#getPath getPath} method is invoked to convert the
|
||||
* URI.
|
||||
*
|
||||
* <p> In the case of the default provider, identified by the URI scheme
|
||||
* "file", the given URI has a non-empty path component, and undefined query
|
||||
* and fragment components. Whether the authority component may be present
|
||||
* is platform specific. The returned {@code Path} is associated with the
|
||||
* {@link FileSystems#getDefault default} file system.
|
||||
*
|
||||
* <p> The default provider provides a similar <em>round-trip</em> guarantee
|
||||
* to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it
|
||||
* is guaranteed that
|
||||
* <blockquote>{@code
|
||||
* Paths.get(}<i>p</i>{@code .}{@link Path#toUri() toUri}{@code ()).equals(}
|
||||
* <i>p</i>{@code .}{@link Path#toAbsolutePath() toAbsolutePath}{@code ())}
|
||||
* </blockquote>
|
||||
* so long as the original {@code Path}, the {@code URI}, and the new {@code
|
||||
* Path} are all created in (possibly different invocations of) the same
|
||||
* Java virtual machine. Whether other providers make any guarantees is
|
||||
* provider specific and therefore unspecified.
|
||||
* @implSpec
|
||||
* This method simply invokes {@link Path#of(URI) * Path.of(URI)} with the given parameter.
|
||||
*
|
||||
* @param uri
|
||||
* the URI to convert
|
||||
@ -127,23 +90,10 @@ public final class Paths {
|
||||
* @throws SecurityException
|
||||
* if a security manager is installed and it denies an unspecified
|
||||
* permission to access the file system
|
||||
*
|
||||
* @see Path#of(URI)
|
||||
*/
|
||||
public static Path get(URI uri) {
|
||||
String scheme = uri.getScheme();
|
||||
if (scheme == null)
|
||||
throw new IllegalArgumentException("Missing scheme");
|
||||
|
||||
// check for default provider to avoid loading of installed providers
|
||||
if (scheme.equalsIgnoreCase("file"))
|
||||
return FileSystems.getDefault().provider().getPath(uri);
|
||||
|
||||
// try to find provider
|
||||
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
|
||||
if (provider.getScheme().equalsIgnoreCase(scheme)) {
|
||||
return provider.getPath(uri);
|
||||
}
|
||||
}
|
||||
|
||||
throw new FileSystemNotFoundException("Provider \"" + scheme + "\" not installed");
|
||||
return Path.of(uri);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -46,7 +46,7 @@ class TempFileHelper {
|
||||
|
||||
// temporary directory location
|
||||
private static final Path tmpdir =
|
||||
Paths.get(GetPropertyAction.privilegedGetProperty("java.io.tmpdir"));
|
||||
Path.of(GetPropertyAction.privilegedGetProperty("java.io.tmpdir"));
|
||||
|
||||
private static final boolean isPosix =
|
||||
FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
|
||||
|
@ -93,9 +93,7 @@ public abstract class AbstractSet<E> extends AbstractCollection<E> implements Se
|
||||
return false;
|
||||
try {
|
||||
return containsAll(c);
|
||||
} catch (ClassCastException unused) {
|
||||
return false;
|
||||
} catch (NullPointerException unused) {
|
||||
} catch (ClassCastException | NullPointerException unused) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -70,146 +70,297 @@ class ImmutableCollections {
|
||||
|
||||
static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
|
||||
|
||||
// ---------- List Implementations ----------
|
||||
|
||||
abstract static class AbstractImmutableList<E> extends AbstractList<E>
|
||||
implements RandomAccess, Serializable {
|
||||
static abstract class AbstractImmutableCollection<E> extends AbstractCollection<E> {
|
||||
// all mutating methods throw UnsupportedOperationException
|
||||
@Override public boolean add(E e) { throw uoe(); }
|
||||
@Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
|
||||
@Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
|
||||
@Override public void clear() { throw uoe(); }
|
||||
@Override public boolean remove(Object o) { throw uoe(); }
|
||||
@Override public boolean removeAll(Collection<?> c) { throw uoe(); }
|
||||
@Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
|
||||
@Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); }
|
||||
@Override public boolean retainAll(Collection<?> c) { throw uoe(); }
|
||||
@Override public void sort(Comparator<? super E> c) { throw uoe(); }
|
||||
}
|
||||
|
||||
static final class List0<E> extends AbstractImmutableList<E> {
|
||||
private static final List0<?> INSTANCE = new List0<>();
|
||||
// ---------- List Implementations ----------
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> List0<T> instance() {
|
||||
return (List0<T>) INSTANCE;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> List<E> emptyList() {
|
||||
return (List<E>) ListN.EMPTY_LIST;
|
||||
}
|
||||
|
||||
private List0() { }
|
||||
static abstract class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
|
||||
implements List<E>, RandomAccess {
|
||||
|
||||
// all mutating methods throw UnsupportedOperationException
|
||||
@Override public void add(int index, E element) { throw uoe(); }
|
||||
@Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
|
||||
@Override public E remove(int index) { throw uoe(); }
|
||||
@Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); }
|
||||
@Override public E set(int index, E element) { throw uoe(); }
|
||||
@Override public void sort(Comparator<? super E> c) { throw uoe(); }
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
int size = size();
|
||||
subListRangeCheck(fromIndex, toIndex, size);
|
||||
return SubList.fromList(this, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
|
||||
return null; // but the compiler doesn't know this
|
||||
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
|
||||
if (fromIndex < 0)
|
||||
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
|
||||
if (toIndex > size)
|
||||
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
|
||||
if (fromIndex > toIndex)
|
||||
throw new IllegalArgumentException("fromIndex(" + fromIndex +
|
||||
") > toIndex(" + toIndex + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_LIST);
|
||||
return new ListItr<E>(this, size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
public ListIterator<E> listIterator() {
|
||||
return listIterator(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<E> listIterator(final int index) {
|
||||
int size = size();
|
||||
if (index < 0 || index > size) {
|
||||
throw outOfBounds(index);
|
||||
}
|
||||
return new ListItr<E>(this, size, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof List)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<?> oit = ((List<?>) o).iterator();
|
||||
for (int i = 0, s = size(); i < s; i++) {
|
||||
if (!oit.hasNext() || !get(i).equals(oit.next())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !oit.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
Objects.requireNonNull(o);
|
||||
return false;
|
||||
for (int i = 0, s = size(); i < s; i++) {
|
||||
if (o.equals(get(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> o) {
|
||||
return o.isEmpty(); // implicit nullcheck of o
|
||||
public int lastIndexOf(Object o) {
|
||||
Objects.requireNonNull(o);
|
||||
for (int i = size() - 1; i >= 0; i--) {
|
||||
if (o.equals(get(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static final class List1<E> extends AbstractImmutableList<E> {
|
||||
@Stable
|
||||
private final E e0;
|
||||
|
||||
List1(E e0) {
|
||||
this.e0 = Objects.requireNonNull(e0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, 1);
|
||||
return e0;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_LIST, e0);
|
||||
int hash = 1;
|
||||
for (int i = 0, s = size(); i < s; i++) {
|
||||
hash = 31 * hash + get(i).hashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return o.equals(e0); // implicit nullcheck of o
|
||||
return indexOf(o) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 + e0.hashCode();
|
||||
IndexOutOfBoundsException outOfBounds(int index) {
|
||||
return new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
|
||||
}
|
||||
}
|
||||
|
||||
static final class List2<E> extends AbstractImmutableList<E> {
|
||||
static final class ListItr<E> implements ListIterator<E> {
|
||||
|
||||
@Stable
|
||||
private final List<E> list;
|
||||
|
||||
@Stable
|
||||
private final int size;
|
||||
|
||||
private int cursor;
|
||||
|
||||
ListItr(List<E> list, int size) {
|
||||
this(list, size, 0);
|
||||
}
|
||||
|
||||
ListItr(List<E> list, int size, int index) {
|
||||
this.list = list;
|
||||
this.size = size;
|
||||
this.cursor = index;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return cursor != size;
|
||||
}
|
||||
|
||||
public E next() {
|
||||
try {
|
||||
int i = cursor;
|
||||
E next = list.get(i);
|
||||
cursor = i + 1;
|
||||
return next;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw uoe();
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return cursor != 0;
|
||||
}
|
||||
|
||||
public E previous() {
|
||||
try {
|
||||
int i = cursor - 1;
|
||||
E previous = list.get(i);
|
||||
cursor = i;
|
||||
return previous;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
public int nextIndex() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public int previousIndex() {
|
||||
return cursor - 1;
|
||||
}
|
||||
|
||||
public void set(E e) {
|
||||
throw uoe();
|
||||
}
|
||||
|
||||
public void add(E e) {
|
||||
throw uoe();
|
||||
}
|
||||
}
|
||||
|
||||
static final class SubList<E> extends AbstractImmutableList<E>
|
||||
implements RandomAccess {
|
||||
|
||||
@Stable
|
||||
private final List<E> root;
|
||||
|
||||
@Stable
|
||||
private final int offset;
|
||||
|
||||
@Stable
|
||||
private final int size;
|
||||
|
||||
private SubList(List<E> root, int offset, int size) {
|
||||
this.root = root;
|
||||
this.offset = offset;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a sublist of another SubList.
|
||||
*/
|
||||
static <E> SubList<E> fromSubList(SubList<E> parent, int fromIndex, int toIndex) {
|
||||
return new SubList<E>(parent.root, parent.offset + fromIndex, toIndex - fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a sublist of an arbitrary AbstractImmutableList, which is
|
||||
* not a SubList itself.
|
||||
*/
|
||||
static <E> SubList<E> fromList(List<E> list, int fromIndex, int toIndex) {
|
||||
return new SubList<E>(list, fromIndex, toIndex - fromIndex);
|
||||
}
|
||||
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, size);
|
||||
return root.get(offset + index);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
return new ListItr<E>(this, size());
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
rangeCheck(index);
|
||||
return new ListItr<E>(this, size(), index);
|
||||
}
|
||||
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
subListRangeCheck(fromIndex, toIndex, size);
|
||||
return SubList.fromSubList(this, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
private void rangeCheck(int index) {
|
||||
if (index < 0 || index > size) {
|
||||
throw outOfBounds(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class List12<E> extends AbstractImmutableList<E>
|
||||
implements Serializable {
|
||||
|
||||
@Stable
|
||||
private final E e0;
|
||||
|
||||
@Stable
|
||||
private final E e1;
|
||||
|
||||
List2(E e0, E e1) {
|
||||
List12(E e0) {
|
||||
this.e0 = Objects.requireNonNull(e0);
|
||||
this.e1 = null;
|
||||
}
|
||||
|
||||
List12(E e0, E e1) {
|
||||
this.e0 = Objects.requireNonNull(e0);
|
||||
this.e1 = Objects.requireNonNull(e1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 2;
|
||||
return e1 != null ? 2 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, 2);
|
||||
if (index == 0) {
|
||||
return e0;
|
||||
} else { // index == 1
|
||||
} else if (index == 1 && e1 != null) {
|
||||
return e1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 31 + e0.hashCode();
|
||||
return 31 * hash + e1.hashCode();
|
||||
throw outOfBounds(index);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
@ -217,11 +368,20 @@ class ImmutableCollections {
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_LIST, e0, e1);
|
||||
if (e1 == null) {
|
||||
return new CollSer(CollSer.IMM_LIST, e0);
|
||||
} else {
|
||||
return new CollSer(CollSer.IMM_LIST, e0, e1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class ListN<E> extends AbstractImmutableList<E> {
|
||||
static final class ListN<E> extends AbstractImmutableList<E>
|
||||
implements Serializable {
|
||||
|
||||
static final List<?> EMPTY_LIST = new ListN<>();
|
||||
|
||||
@Stable
|
||||
private final E[] elements;
|
||||
|
||||
@ -233,7 +393,12 @@ class ImmutableCollections {
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
tmp[i] = Objects.requireNonNull(input[i]);
|
||||
}
|
||||
this.elements = tmp;
|
||||
elements = tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -243,29 +408,9 @@ class ImmutableCollections {
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, elements.length);
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
for (E e : elements) {
|
||||
if (o.equals(e)) { // implicit nullcheck of o
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 1;
|
||||
for (E e : elements) {
|
||||
hash = 31 * hash + e.hashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
@ -277,105 +422,52 @@ class ImmutableCollections {
|
||||
|
||||
// ---------- Set Implementations ----------
|
||||
|
||||
abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
|
||||
@Override public boolean add(E e) { throw uoe(); }
|
||||
@Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
|
||||
@Override public void clear() { throw uoe(); }
|
||||
@Override public boolean remove(Object o) { throw uoe(); }
|
||||
@Override public boolean removeAll(Collection<?> c) { throw uoe(); }
|
||||
@Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
|
||||
@Override public boolean retainAll(Collection<?> c) { throw uoe(); }
|
||||
static abstract class AbstractImmutableSet<E> extends AbstractImmutableCollection<E>
|
||||
implements Set<E> {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
} else if (!(o instanceof Set)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Collection<?> c = (Collection<?>) o;
|
||||
if (c.size() != size()) {
|
||||
return false;
|
||||
}
|
||||
for (Object e : c) {
|
||||
if (e == null || !contains(e)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract int hashCode();
|
||||
}
|
||||
|
||||
static final class Set0<E> extends AbstractImmutableSet<E> {
|
||||
private static final Set0<?> INSTANCE = new Set0<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> Set0<T> instance() {
|
||||
return (Set0<T>) INSTANCE;
|
||||
}
|
||||
|
||||
private Set0() { }
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
Objects.requireNonNull(o);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> o) {
|
||||
return o.isEmpty(); // implicit nullcheck of o
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_SET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> Set<E> emptySet() {
|
||||
return (Set<E>) SetN.EMPTY_SET;
|
||||
}
|
||||
|
||||
static final class Set1<E> extends AbstractImmutableSet<E> {
|
||||
@Stable
|
||||
private final E e0;
|
||||
static final class Set12<E> extends AbstractImmutableSet<E>
|
||||
implements Serializable {
|
||||
|
||||
Set1(E e0) {
|
||||
this.e0 = Objects.requireNonNull(e0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return o.equals(e0); // implicit nullcheck of o
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Collections.singletonIterator(e0);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_SET, e0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return e0.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
static final class Set2<E> extends AbstractImmutableSet<E> {
|
||||
@Stable
|
||||
final E e0;
|
||||
@Stable
|
||||
final E e1;
|
||||
|
||||
Set2(E e0, E e1) {
|
||||
Set12(E e0) {
|
||||
this.e0 = Objects.requireNonNull(e0);
|
||||
this.e1 = null;
|
||||
}
|
||||
|
||||
Set12(E e0, E e1) {
|
||||
if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
|
||||
throw new IllegalArgumentException("duplicate element: " + e0);
|
||||
}
|
||||
@ -391,7 +483,7 @@ class ImmutableCollections {
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 2;
|
||||
return (e1 == null) ? 1 : 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -401,26 +493,26 @@ class ImmutableCollections {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return e0.hashCode() + e1.hashCode();
|
||||
return e0.hashCode() + (e1 == null ? 0 : e1.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new Iterator<E>() {
|
||||
private int idx = 0;
|
||||
return new Iterator<>() {
|
||||
private int idx = size();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return idx < 2;
|
||||
return idx > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
if (idx == 0) {
|
||||
idx = 1;
|
||||
if (idx == 1) {
|
||||
idx = 0;
|
||||
return e0;
|
||||
} else if (idx == 1) {
|
||||
idx = 2;
|
||||
} else if (idx == 2) {
|
||||
idx = 1;
|
||||
return e1;
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
@ -434,7 +526,11 @@ class ImmutableCollections {
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_SET, e0, e1);
|
||||
if (e1 == null) {
|
||||
return new CollSer(CollSer.IMM_SET, e0);
|
||||
} else {
|
||||
return new CollSer(CollSer.IMM_SET, e0, e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,7 +540,11 @@ class ImmutableCollections {
|
||||
* least one null is always present.
|
||||
* @param <E> the element type
|
||||
*/
|
||||
static final class SetN<E> extends AbstractImmutableSet<E> {
|
||||
static final class SetN<E> extends AbstractImmutableSet<E>
|
||||
implements Serializable {
|
||||
|
||||
static final Set<?> EMPTY_SET = new SetN<>();
|
||||
|
||||
@Stable
|
||||
final E[] elements;
|
||||
@Stable
|
||||
@ -474,12 +574,13 @@ class ImmutableCollections {
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return probe(o) >= 0; // implicit nullcheck of o
|
||||
Objects.requireNonNull(o);
|
||||
return size > 0 && probe(o) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new Iterator<E>() {
|
||||
return new Iterator<>() {
|
||||
private int idx = 0;
|
||||
|
||||
@Override
|
||||
@ -549,6 +650,11 @@ class ImmutableCollections {
|
||||
|
||||
// ---------- Map Implementations ----------
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <K,V> Map<K,V> emptyMap() {
|
||||
return (Map<K,V>) MapN.EMPTY_MAP;
|
||||
}
|
||||
|
||||
abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
|
||||
@Override public void clear() { throw uoe(); }
|
||||
@Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
|
||||
@ -565,47 +671,6 @@ class ImmutableCollections {
|
||||
@Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
|
||||
}
|
||||
|
||||
static final class Map0<K,V> extends AbstractImmutableMap<K,V> {
|
||||
private static final Map0<?,?> INSTANCE = new Map0<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <K,V> Map0<K,V> instance() {
|
||||
return (Map0<K,V>) INSTANCE;
|
||||
}
|
||||
|
||||
private Map0() { }
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<K,V>> entrySet() {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
Objects.requireNonNull(o);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
Objects.requireNonNull(o);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_MAP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
|
||||
@Stable
|
||||
private final K k0;
|
||||
@ -656,8 +721,12 @@ class ImmutableCollections {
|
||||
* @param <V> the value type
|
||||
*/
|
||||
static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
|
||||
|
||||
static final Map<?,?> EMPTY_MAP = new MapN<>();
|
||||
|
||||
@Stable
|
||||
final Object[] table; // pairs of key, value
|
||||
|
||||
@Stable
|
||||
final int size; // number of pairs
|
||||
|
||||
@ -689,14 +758,16 @@ class ImmutableCollections {
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return probe(o) >= 0; // implicit nullcheck of o
|
||||
Objects.requireNonNull(o);
|
||||
return size > 0 && probe(o) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
Objects.requireNonNull(o);
|
||||
for (int i = 1; i < table.length; i += 2) {
|
||||
Object v = table[i];
|
||||
if (v != null && o.equals(v)) { // implicit nullcheck of o
|
||||
if (v != null && o.equals(v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -718,6 +789,10 @@ class ImmutableCollections {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public V get(Object o) {
|
||||
if (size == 0) {
|
||||
Objects.requireNonNull(o);
|
||||
return null;
|
||||
}
|
||||
int i = probe(o);
|
||||
if (i >= 0) {
|
||||
return (V)table[i+1];
|
||||
@ -733,7 +808,7 @@ class ImmutableCollections {
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<K,V>> entrySet() {
|
||||
return new AbstractSet<Map.Entry<K,V>>() {
|
||||
return new AbstractSet<>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return MapN.this.size;
|
||||
@ -741,7 +816,7 @@ class ImmutableCollections {
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<K,V>> iterator() {
|
||||
return new Iterator<Map.Entry<K,V>>() {
|
||||
return new Iterator<>() {
|
||||
int idx = 0;
|
||||
|
||||
@Override
|
||||
@ -948,7 +1023,7 @@ final class CollSer implements Serializable {
|
||||
return Set.of(array);
|
||||
case IMM_MAP:
|
||||
if (array.length == 0) {
|
||||
return ImmutableCollections.Map0.instance();
|
||||
return ImmutableCollections.emptyMap();
|
||||
} else if (array.length == 2) {
|
||||
return new ImmutableCollections.Map1<>(array[0], array[1]);
|
||||
} else {
|
||||
|
@ -788,7 +788,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of() {
|
||||
return ImmutableCollections.List0.instance();
|
||||
return ImmutableCollections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -804,7 +804,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1) {
|
||||
return new ImmutableCollections.List1<>(e1);
|
||||
return new ImmutableCollections.List12<>(e1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -821,7 +821,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2) {
|
||||
return new ImmutableCollections.List2<>(e1, e2);
|
||||
return new ImmutableCollections.List12<>(e1, e2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1031,11 +1031,11 @@ public interface List<E> extends Collection<E> {
|
||||
static <E> List<E> of(E... elements) {
|
||||
switch (elements.length) { // implicit null check of elements
|
||||
case 0:
|
||||
return ImmutableCollections.List0.instance();
|
||||
return ImmutableCollections.emptyList();
|
||||
case 1:
|
||||
return new ImmutableCollections.List1<>(elements[0]);
|
||||
return new ImmutableCollections.List12<>(elements[0]);
|
||||
case 2:
|
||||
return new ImmutableCollections.List2<>(elements[0], elements[1]);
|
||||
return new ImmutableCollections.List12<>(elements[0], elements[1]);
|
||||
default:
|
||||
return new ImmutableCollections.ListN<>(elements);
|
||||
}
|
||||
|
@ -1287,7 +1287,7 @@ public interface Map<K, V> {
|
||||
* @since 9
|
||||
*/
|
||||
static <K, V> Map<K, V> of() {
|
||||
return ImmutableCollections.Map0.instance();
|
||||
return ImmutableCollections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1604,11 +1604,11 @@ public interface Map<K, V> {
|
||||
@SuppressWarnings("varargs")
|
||||
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
|
||||
if (entries.length == 0) { // implicit null check of entries array
|
||||
return ImmutableCollections.Map0.instance();
|
||||
return ImmutableCollections.emptyMap();
|
||||
} else if (entries.length == 1) {
|
||||
// implicit null check of the array slot
|
||||
return new ImmutableCollections.Map1<>(entries[0].getKey(),
|
||||
entries[0].getValue());
|
||||
entries[0].getValue());
|
||||
} else {
|
||||
Object[] kva = new Object[entries.length << 1];
|
||||
int a = 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2897,7 +2897,7 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
* letters:
|
||||
*
|
||||
* <pre>{@code
|
||||
* try (Scanner sc = new Scanner(Paths.get("input.txt"))) {
|
||||
* try (Scanner sc = new Scanner(Path.of("input.txt"))) {
|
||||
* Pattern pat = Pattern.compile("[A-Z]{7,}");
|
||||
* List<String> capWords = sc.findAll(pat)
|
||||
* .map(MatchResult::group)
|
||||
|
@ -449,7 +449,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of() {
|
||||
return ImmutableCollections.Set0.instance();
|
||||
return ImmutableCollections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -464,7 +464,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1) {
|
||||
return new ImmutableCollections.Set1<>(e1);
|
||||
return new ImmutableCollections.Set12<>(e1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -481,7 +481,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2) {
|
||||
return new ImmutableCollections.Set2<>(e1, e2);
|
||||
return new ImmutableCollections.Set12<>(e1, e2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -692,11 +692,11 @@ public interface Set<E> extends Collection<E> {
|
||||
static <E> Set<E> of(E... elements) {
|
||||
switch (elements.length) { // implicit null check of elements
|
||||
case 0:
|
||||
return ImmutableCollections.Set0.instance();
|
||||
return ImmutableCollections.emptySet();
|
||||
case 1:
|
||||
return new ImmutableCollections.Set1<>(elements[0]);
|
||||
return new ImmutableCollections.Set12<>(elements[0]);
|
||||
case 2:
|
||||
return new ImmutableCollections.Set2<>(elements[0], elements[1]);
|
||||
return new ImmutableCollections.Set12<>(elements[0], elements[1]);
|
||||
default:
|
||||
return new ImmutableCollections.SetN<>(elements);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,7 +32,6 @@ import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
@ -243,8 +242,8 @@ public class BootLoader {
|
||||
mn = location.substring(5, location.length());
|
||||
} else if (location.startsWith("file:/")) {
|
||||
// named module in exploded image
|
||||
Path path = Paths.get(URI.create(location));
|
||||
Path modulesDir = Paths.get(JAVA_HOME, "modules");
|
||||
Path path = Path.of(URI.create(location));
|
||||
Path modulesDir = Path.of(JAVA_HOME, "modules");
|
||||
if (path.startsWith(modulesDir)) {
|
||||
mn = path.getFileName().toString();
|
||||
}
|
||||
@ -267,7 +266,7 @@ public class BootLoader {
|
||||
private static URL toFileURL(String location) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
public URL run() {
|
||||
Path path = Paths.get(location);
|
||||
Path path = Path.of(location);
|
||||
if (Files.isRegularFile(path)) {
|
||||
try {
|
||||
return path.toUri().toURL();
|
||||
@ -285,7 +284,7 @@ public class BootLoader {
|
||||
private static Manifest getManifest(String location) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
public Manifest run() {
|
||||
Path jar = Paths.get(location);
|
||||
Path jar = Path.of(location);
|
||||
try (InputStream in = Files.newInputStream(jar);
|
||||
JarInputStream jis = new JarInputStream(in, false)) {
|
||||
return jis.getManifest();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,7 +28,7 @@ package jdk.internal.loader;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.Path;
|
||||
import java.security.CodeSource;
|
||||
import java.security.PermissionCollection;
|
||||
import java.util.jar.Manifest;
|
||||
@ -223,7 +223,7 @@ public class ClassLoaders {
|
||||
// Use an intermediate File object to construct a URI/URL without
|
||||
// authority component as URLClassPath can't handle URLs with a UNC
|
||||
// server name in the authority component.
|
||||
return Paths.get(s).toRealPath().toFile().toURI().toURL();
|
||||
return Path.of(s).toRealPath().toFile().toURI().toURL();
|
||||
} catch (InvalidPathException | IOException ignore) {
|
||||
// malformed path string or class path element does not exist
|
||||
return null;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +34,6 @@ import java.lang.module.ModuleReference;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -539,7 +538,7 @@ public final class ModuleBootstrap {
|
||||
Path[] paths = new Path[dirs.length];
|
||||
int i = 0;
|
||||
for (String dir: dirs) {
|
||||
paths[i++] = Paths.get(dir);
|
||||
paths[i++] = Path.of(dir);
|
||||
}
|
||||
return ModulePath.of(patcher, paths);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,7 +30,6 @@ import java.lang.module.Configuration;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
@ -129,7 +128,7 @@ public class ModuleHashesBuilder {
|
||||
() -> new InternalError("Selected module " + name + " not on module path"));
|
||||
|
||||
URI uri = rm.reference().location().get();
|
||||
Path path = Paths.get(uri);
|
||||
Path path = Path.of(uri);
|
||||
String fn = path.getFileName().toString();
|
||||
if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) {
|
||||
throw new UnsupportedOperationException(path + " is not a modular JAR or jmod file");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -43,7 +43,6 @@ import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -360,7 +359,7 @@ public class ModulePath implements ModuleFinder {
|
||||
URI uri = mref.location().orElse(null);
|
||||
if (uri != null) {
|
||||
if (uri.getScheme().equalsIgnoreCase("file")) {
|
||||
Path file = Paths.get(uri);
|
||||
Path file = Path.of(uri);
|
||||
return file.getFileName().toString();
|
||||
} else {
|
||||
return uri.toString();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,7 +38,6 @@ import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayDeque;
|
||||
@ -185,7 +184,7 @@ public final class SystemModuleFinders {
|
||||
|
||||
// probe to see if this is an images build
|
||||
String home = System.getProperty("java.home");
|
||||
Path modules = Paths.get(home, "lib", "modules");
|
||||
Path modules = Path.of(home, "lib", "modules");
|
||||
if (Files.isRegularFile(modules)) {
|
||||
if (USE_FAST_PATH) {
|
||||
SystemModules systemModules = allSystemModules();
|
||||
@ -205,7 +204,7 @@ public final class SystemModuleFinders {
|
||||
}
|
||||
|
||||
// exploded build (do not cache module finder)
|
||||
Path dir = Paths.get(home, "modules");
|
||||
Path dir = Path.of(home, "modules");
|
||||
if (!Files.isDirectory(dir))
|
||||
throw new InternalError("Unable to detect the run-time image");
|
||||
ModuleFinder f = ModulePath.of(ModuleBootstrap.patcher(), dir);
|
||||
|
@ -508,8 +508,7 @@ class DatagramChannelImpl
|
||||
if (remote != null) {
|
||||
// connected
|
||||
if (!target.equals(remote)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Connected address not equal to target address");
|
||||
throw new AlreadyConnectedException();
|
||||
}
|
||||
do {
|
||||
n = IOUtil.write(fd, src, -1, nd);
|
||||
|
@ -397,7 +397,9 @@ public class IOUtil {
|
||||
* The read end of the pipe is returned in the high 32 bits,
|
||||
* while the write end is returned in the low 32 bits.
|
||||
*/
|
||||
static native long makePipe(boolean blocking);
|
||||
static native long makePipe(boolean blocking) throws IOException;
|
||||
|
||||
static native int write1(int fd, byte b) throws IOException;
|
||||
|
||||
static native boolean drain(int fd) throws IOException;
|
||||
|
||||
|
@ -33,10 +33,10 @@ import java.nio.channels.spi.AbstractSelectionKey;
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of SelectionKey for Solaris.
|
||||
* An implementation of SelectionKey.
|
||||
*/
|
||||
|
||||
public class SelectionKeyImpl
|
||||
public final class SelectionKeyImpl
|
||||
extends AbstractSelectionKey
|
||||
{
|
||||
|
||||
@ -54,12 +54,14 @@ public class SelectionKeyImpl
|
||||
selector = sel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectableChannel channel() {
|
||||
return (SelectableChannel)channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Selector selector() {
|
||||
return selector;
|
||||
return (Selector)selector;
|
||||
}
|
||||
|
||||
int getIndex() { // package-private
|
||||
@ -75,16 +77,19 @@ public class SelectionKeyImpl
|
||||
throw new CancelledKeyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int interestOps() {
|
||||
ensureValid();
|
||||
return interestOps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectionKey interestOps(int ops) {
|
||||
ensureValid();
|
||||
return nioInterestOps(ops);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readyOps() {
|
||||
ensureValid();
|
||||
return readyOps;
|
||||
@ -131,4 +136,6 @@ public class SelectionKeyImpl
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// used by Selector implementations to record when the key was selected
|
||||
int lastPolled;
|
||||
}
|
||||
|
@ -78,6 +78,16 @@ public abstract class SelectorImpl
|
||||
return publicSelectedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public view of the key sets
|
||||
*/
|
||||
protected final Set<SelectionKey> nioKeys() {
|
||||
return publicKeys;
|
||||
}
|
||||
protected final Set<SelectionKey> nioSelectedKeys() {
|
||||
return publicSelectedKeys;
|
||||
}
|
||||
|
||||
protected abstract int doSelect(long timeout) throws IOException;
|
||||
|
||||
private int lockAndDoSelect(long timeout) throws IOException {
|
||||
@ -125,8 +135,6 @@ public abstract class SelectorImpl
|
||||
|
||||
protected abstract void implClose() throws IOException;
|
||||
|
||||
public abstract void putEventOps(SelectionKeyImpl sk, int ops);
|
||||
|
||||
@Override
|
||||
protected final SelectionKey register(AbstractSelectableChannel ch,
|
||||
int ops,
|
||||
@ -166,4 +174,9 @@ public abstract class SelectorImpl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to change the key's interest set
|
||||
*/
|
||||
public abstract void putEventOps(SelectionKeyImpl ski, int ops);
|
||||
}
|
||||
|
@ -210,25 +210,20 @@ class ServerSocketChannelImpl
|
||||
|
||||
@Override
|
||||
public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
|
||||
acceptLock.lock();
|
||||
try {
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
if (localAddress != null)
|
||||
throw new AlreadyBoundException();
|
||||
InetSocketAddress isa = (local == null)
|
||||
? new InetSocketAddress(0)
|
||||
: Net.checkAddress(local);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkListen(isa.getPort());
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
} finally {
|
||||
acceptLock.unlock();
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
if (localAddress != null)
|
||||
throw new AlreadyBoundException();
|
||||
InetSocketAddress isa = (local == null)
|
||||
? new InetSocketAddress(0)
|
||||
: Net.checkAddress(local);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkListen(isa.getPort());
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ import java.lang.reflect.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
@ -278,7 +278,7 @@ public class PolicyFile extends java.security.Policy {
|
||||
public URL run() {
|
||||
String sep = File.separator;
|
||||
try {
|
||||
return Paths.get(System.getProperty("java.home"),
|
||||
return Path.of(System.getProperty("java.home"),
|
||||
"lib", "security",
|
||||
"default.policy").toUri().toURL();
|
||||
} catch (MalformedURLException mue) {
|
||||
|
@ -27,7 +27,7 @@ package sun.security.tools.keytool;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.Path;
|
||||
import java.security.CodeSigner;
|
||||
import java.security.CryptoPrimitive;
|
||||
import java.security.KeyStore;
|
||||
@ -2189,7 +2189,7 @@ public final class Main {
|
||||
inplaceBackupName = srcksfname + ".old" + (n == 1 ? "" : n);
|
||||
File bkFile = new File(inplaceBackupName);
|
||||
if (!bkFile.exists()) {
|
||||
Files.copy(Paths.get(srcksfname), bkFile.toPath());
|
||||
Files.copy(Path.of(srcksfname), bkFile.toPath());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -244,21 +244,8 @@ Java_java_lang_System_initProperties(JNIEnv *env, jclass cla, jobject props)
|
||||
PUTPROP(props, "line.separator", sprops->line_separator);
|
||||
|
||||
/*
|
||||
* user.language
|
||||
* user.script, user.country, user.variant (if user's environment specifies them)
|
||||
* file.encoding
|
||||
* file encoding for stdout and stderr
|
||||
*/
|
||||
PUTPROP(props, "user.language", sprops->language);
|
||||
if (sprops->script) {
|
||||
PUTPROP(props, "user.script", sprops->script);
|
||||
}
|
||||
if (sprops->country) {
|
||||
PUTPROP(props, "user.country", sprops->country);
|
||||
}
|
||||
if (sprops->variant) {
|
||||
PUTPROP(props, "user.variant", sprops->variant);
|
||||
}
|
||||
PUTPROP(props, "file.encoding", sprops->encoding);
|
||||
if (sprops->sun_stdout_encoding != NULL) {
|
||||
PUTPROP(props, "sun.stdout.encoding", sprops->sun_stdout_encoding);
|
||||
}
|
||||
@ -314,7 +301,7 @@ Java_java_lang_System_initProperties(JNIEnv *env, jclass cla, jobject props)
|
||||
#endif
|
||||
|
||||
/* !!! DO NOT call PUTPROP_ForPlatformNString before this line !!!
|
||||
* !!! I18n properties have not been set up yet !!!
|
||||
* !!! The platform native encoding for strings has not been set up yet !!!
|
||||
*/
|
||||
InitializeEncoding(env, sprops->sun_jnu_encoding);
|
||||
|
||||
@ -379,17 +366,6 @@ Java_java_lang_System_initProperties(JNIEnv *env, jclass cla, jobject props)
|
||||
PUTPROP(props, "sun.desktop", sprops->desktop);
|
||||
}
|
||||
|
||||
/*
|
||||
* unset "user.language", "user.script", "user.country", and "user.variant"
|
||||
* in order to tell whether the command line option "-DXXXX=YYYY" is
|
||||
* specified or not. They will be reset in fillI18nProps() below.
|
||||
*/
|
||||
REMOVEPROP(props, "user.language");
|
||||
REMOVEPROP(props, "user.script");
|
||||
REMOVEPROP(props, "user.country");
|
||||
REMOVEPROP(props, "user.variant");
|
||||
REMOVEPROP(props, "file.encoding");
|
||||
|
||||
ret = JVM_InitProperties(env, props);
|
||||
|
||||
/* reconstruct i18n related properties */
|
||||
|
@ -127,7 +127,7 @@ class DevPollArrayWrapper {
|
||||
// descriptor is registered with /dev/poll.
|
||||
private final BitSet registered = new BitSet();
|
||||
|
||||
DevPollArrayWrapper() {
|
||||
DevPollArrayWrapper() throws IOException {
|
||||
int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
|
||||
pollArray = new AllocatedNativeObject(allocationSize, true);
|
||||
pollArrayAddress = pollArray.address();
|
||||
@ -136,7 +136,7 @@ class DevPollArrayWrapper {
|
||||
eventsHigh = new HashMap<>();
|
||||
}
|
||||
|
||||
void initInterrupt(int fd0, int fd1) {
|
||||
void initInterrupt(int fd0, int fd1) throws IOException {
|
||||
outgoingInterruptFD = fd1;
|
||||
incomingInterruptFD = fd0;
|
||||
register(wfd, fd0, POLLIN);
|
||||
@ -200,7 +200,7 @@ class DevPollArrayWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
void release(int fd) {
|
||||
void release(int fd) throws IOException {
|
||||
synchronized (updateLock) {
|
||||
// ignore any pending update for this file descriptor
|
||||
setUpdateEvents(fd, IGNORE);
|
||||
@ -297,7 +297,11 @@ class DevPollArrayWrapper {
|
||||
boolean interrupted = false;
|
||||
|
||||
public void interrupt() {
|
||||
interrupt(outgoingInterruptFD);
|
||||
try {
|
||||
IOUtil.write1(outgoingInterruptFD, (byte)0);
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public int interruptedIndex() {
|
||||
@ -312,13 +316,12 @@ class DevPollArrayWrapper {
|
||||
interrupted = false;
|
||||
}
|
||||
|
||||
private native int init();
|
||||
private native void register(int wfd, int fd, int mask);
|
||||
private native int init() throws IOException;
|
||||
private native void register(int wfd, int fd, int mask) throws IOException;
|
||||
private native void registerMultiple(int wfd, long address, int len)
|
||||
throws IOException;
|
||||
private native int poll0(long pollAddress, int numfds, long timeout,
|
||||
int wfd);
|
||||
private static native void interrupt(int fd);
|
||||
private native int poll0(long pollAddress, int numfds, long timeout, int wfd)
|
||||
throws IOException;
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
|
@ -61,7 +61,7 @@ class DevPollSelectorImpl
|
||||
* Package private constructor called by factory method in
|
||||
* the abstract superclass Selector.
|
||||
*/
|
||||
DevPollSelectorImpl(SelectorProvider sp) {
|
||||
DevPollSelectorImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp);
|
||||
long pipeFds = IOUtil.makePipe(false);
|
||||
fd0 = (int) (pipeFds >>> 32);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -181,12 +181,26 @@ class EventPortWrapper {
|
||||
}
|
||||
|
||||
// poll for events
|
||||
int updated = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
|
||||
int numEntries;
|
||||
long to = timeout;
|
||||
boolean timedPoll = (to > 0);
|
||||
do {
|
||||
long startTime = timedPoll ? System.currentTimeMillis() : 0;
|
||||
numEntries = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
|
||||
if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
|
||||
// timed poll interrupted so need to adjust timeout
|
||||
to -= System.currentTimeMillis() - startTime;
|
||||
if (to <= 0) {
|
||||
// timeout also expired so no retry
|
||||
numEntries = 0;
|
||||
}
|
||||
}
|
||||
} while (numEntries == IOStatus.INTERRUPTED);
|
||||
|
||||
// after polling we need to queue all polled file descriptors as they
|
||||
// are candidates to register for the next poll.
|
||||
synchronized (updateLock) {
|
||||
for (int i=0; i<updated; i++) {
|
||||
for (int i=0; i<numEntries; i++) {
|
||||
if (getSource(i) == PORT_SOURCE_USER) {
|
||||
interrupted = true;
|
||||
setDescriptor(i, -1);
|
||||
@ -199,7 +213,7 @@ class EventPortWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
return updated;
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
private void setInterest(int fd) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -164,7 +164,10 @@ class SolarisEventPort
|
||||
// A error here is fatal (thread will not be replaced)
|
||||
replaceMe = false;
|
||||
try {
|
||||
port_get(port, address);
|
||||
int n;
|
||||
do {
|
||||
n = port_get(port, address);
|
||||
} while (n == IOStatus.INTERRUPTED);
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
return;
|
||||
@ -240,7 +243,7 @@ class SolarisEventPort
|
||||
/**
|
||||
* Retrieves a single event from a port
|
||||
*/
|
||||
static native void port_get(int port, long pe) throws IOException;
|
||||
static native int port_get(int port, long address) throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieves at most {@code max} events from a port.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -84,9 +84,9 @@ public class SolarisFileSystemProvider extends UnixFileSystemProvider {
|
||||
|
||||
@Override
|
||||
FileTypeDetector getFileTypeDetector() {
|
||||
Path userMimeTypes = Paths.get(
|
||||
Path userMimeTypes = Path.of(
|
||||
GetPropertyAction.privilegedGetProperty("user.home"), ".mime.types");
|
||||
Path etcMimeTypes = Paths.get("/etc/mime.types");
|
||||
Path etcMimeTypes = Path.of("/etc/mime.types");
|
||||
|
||||
return chain(new MimeTypesFileTypeDetector(userMimeTypes),
|
||||
new MimeTypesFileTypeDetector(etcMimeTypes));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -176,14 +176,3 @@ Java_sun_nio_ch_DevPollArrayWrapper_poll0(JNIEnv *env, jobject this,
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_DevPollArrayWrapper_interrupt(JNIEnv *env, jclass this, jint fd)
|
||||
{
|
||||
int fakebuf[1];
|
||||
fakebuf[0] = 1;
|
||||
if (write(fd, fakebuf, 1) < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env,
|
||||
"Write to interrupt fd failed");
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,17 +23,18 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/types.h>
|
||||
#include <port.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_SolarisEventPort.h"
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
@ -51,8 +52,10 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_SolarisEventPort_port_1close
|
||||
(JNIEnv* env, jclass clazz, jint port)
|
||||
{
|
||||
int res;
|
||||
RESTARTABLE(close(port), res);
|
||||
int res = close(port);
|
||||
if (res < 0 && res != EINTR) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "close failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
@ -93,17 +96,23 @@ Java_sun_nio_ch_SolarisEventPort_port_1send(JNIEnv* env, jclass clazz,
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_SolarisEventPort_port_1get(JNIEnv* env, jclass clazz,
|
||||
jint port, jlong eventAddress)
|
||||
{
|
||||
int res;
|
||||
port_event_t* ev = (port_event_t*)jlong_to_ptr(eventAddress);
|
||||
|
||||
RESTARTABLE(port_get((int)port, ev, NULL), res);
|
||||
res = port_get((int)port, ev, NULL);
|
||||
if (res == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "port_get");
|
||||
if (errno == EINTR) {
|
||||
return IOS_INTERRUPTED;
|
||||
} else {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "port_get failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
@ -125,9 +134,13 @@ Java_sun_nio_ch_SolarisEventPort_port_1getn(JNIEnv* env, jclass clazz,
|
||||
}
|
||||
|
||||
res = port_getn((int)port, list, (uint_t)max, &n, tsp);
|
||||
if (res == -1) {
|
||||
if (errno != ETIME && errno != EINTR)
|
||||
JNU_ThrowIOExceptionWithLastError(env, "port_getn");
|
||||
if (res == -1 && errno != ETIME) {
|
||||
if (errno == EINTR) {
|
||||
return IOS_INTERRUPTED;
|
||||
} else {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "port_getn failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
}
|
||||
|
||||
return (jint)n;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,7 +38,7 @@ class PipeImpl
|
||||
private final SourceChannel source;
|
||||
private final SinkChannel sink;
|
||||
|
||||
PipeImpl(SelectorProvider sp) {
|
||||
PipeImpl(SelectorProvider sp) throws IOException {
|
||||
long pipeFds = IOUtil.makePipe(true);
|
||||
int readFd = (int) (pipeFds >>> 32);
|
||||
int writeFd = (int) pipeFds;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -51,7 +51,7 @@ class PollSelectorImpl
|
||||
* Package private constructor called by factory method in
|
||||
* the abstract superclass Selector.
|
||||
*/
|
||||
PollSelectorImpl(SelectorProvider sp) {
|
||||
PollSelectorImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp, 1, 1);
|
||||
long pipeFds = IOUtil.makePipe(false);
|
||||
fd0 = (int) (pipeFds >>> 32);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,15 +25,15 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Allows different platforms to call different native methods
|
||||
* for read and write operations.
|
||||
*/
|
||||
|
||||
class SocketDispatcher extends NativeDispatcher
|
||||
{
|
||||
class SocketDispatcher extends NativeDispatcher {
|
||||
|
||||
int read(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return FileDispatcherImpl.read0(fd, address, len);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -260,7 +260,7 @@ abstract class UnixFileStore
|
||||
private static Properties loadProperties() {
|
||||
Properties result = new Properties();
|
||||
String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties";
|
||||
Path file = Paths.get(fstypes);
|
||||
Path file = Path.of(fstypes);
|
||||
try {
|
||||
try (ReadableByteChannel rbc = Files.newByteChannel(file)) {
|
||||
result.load(Channels.newReader(rbc, "UTF-8"));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -104,10 +104,19 @@ Java_sun_nio_ch_IOUtil_makePipe(JNIEnv *env, jobject this, jboolean blocking)
|
||||
return ((jlong) fd[0] << 32) | (jlong) fd[1];
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_IOUtil_write1(JNIEnv *env, jclass cl, jint fd, jbyte b)
|
||||
{
|
||||
char c = (char)b;
|
||||
return convertReturnVal(env, write(fd, &c, 1), JNI_FALSE);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_ch_IOUtil_drain(JNIEnv *env, jclass cl, jint fd)
|
||||
{
|
||||
char buf[128];
|
||||
char buf[16];
|
||||
int tn = 0;
|
||||
|
||||
for (;;) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,23 +38,9 @@ import java.util.StringTokenizer;
|
||||
final class Platform {
|
||||
|
||||
// native library we need to load
|
||||
private static final String libNameMain = "jsound";
|
||||
private static final String libNameALSA = "jsoundalsa";
|
||||
private static final String libNameDSound = "jsoundds";
|
||||
private static final String libName = "jsound";
|
||||
|
||||
// extra libs handling: bit flags for each different library
|
||||
public static final int LIB_MAIN = 1;
|
||||
public static final int LIB_ALSA = 2;
|
||||
public static final int LIB_DSOUND = 4;
|
||||
|
||||
// bit field of the constants above. Willbe set in loadLibraries
|
||||
private static int loadedLibs = 0;
|
||||
|
||||
// features: the main native library jsound reports which feature is
|
||||
// contained in which lib
|
||||
public static final int FEATURE_MIDIIO = 1;
|
||||
public static final int FEATURE_PORTS = 2;
|
||||
public static final int FEATURE_DIRECT_AUDIO = 3;
|
||||
private static boolean isNativeLibLoaded;
|
||||
|
||||
// SYSTEM CHARACTERISTICS
|
||||
// vary according to hardware architecture
|
||||
@ -66,7 +52,6 @@ final class Platform {
|
||||
if(Printer.trace)Printer.trace(">> Platform.java: static");
|
||||
|
||||
loadLibraries();
|
||||
readProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,72 +80,37 @@ final class Platform {
|
||||
private static void loadLibraries() {
|
||||
if(Printer.trace)Printer.trace(">>Platform.loadLibraries");
|
||||
|
||||
// load the main library
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
System.loadLibrary(libNameMain);
|
||||
return null;
|
||||
});
|
||||
// just for the heck of it...
|
||||
loadedLibs |= LIB_MAIN;
|
||||
|
||||
// now try to load extra libs. They are defined at compile time in the Makefile
|
||||
// with the define EXTRA_SOUND_JNI_LIBS
|
||||
String extraLibs = nGetExtraLibraries();
|
||||
// the string is the libraries, separated by white space
|
||||
StringTokenizer st = new StringTokenizer(extraLibs);
|
||||
while (st.hasMoreTokens()) {
|
||||
final String lib = st.nextToken();
|
||||
try {
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
System.loadLibrary(lib);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (lib.equals(libNameALSA)) {
|
||||
loadedLibs |= LIB_ALSA;
|
||||
if (Printer.debug) Printer.debug("Loaded ALSA lib successfully.");
|
||||
} else if (lib.equals(libNameDSound)) {
|
||||
loadedLibs |= LIB_DSOUND;
|
||||
if (Printer.debug) Printer.debug("Loaded DirectSound lib successfully.");
|
||||
} else {
|
||||
if (Printer.err) Printer.err("Loaded unknown lib '"+lib+"' successfully.");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (Printer.err) Printer.err("Couldn't load library "+lib+": "+t.toString());
|
||||
}
|
||||
// load the native library
|
||||
isNativeLibLoaded = true;
|
||||
try {
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
System.loadLibrary(libName);
|
||||
return null;
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
if (Printer.err) Printer.err("Couldn't load library "+libName+": "+t.toString());
|
||||
isNativeLibLoaded = false;
|
||||
}
|
||||
if (isNativeLibLoaded) {
|
||||
bigEndian = nIsBigEndian();
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isMidiIOEnabled() {
|
||||
return isFeatureLibLoaded(FEATURE_MIDIIO);
|
||||
if (Printer.debug) Printer.debug("Platform: Checking for MidiIO; library is loaded=" + isNativeLibLoaded);
|
||||
return isNativeLibLoaded;
|
||||
}
|
||||
|
||||
static boolean isPortsEnabled() {
|
||||
return isFeatureLibLoaded(FEATURE_PORTS);
|
||||
if (Printer.debug) Printer.debug("Platform: Checking for Ports; library is loaded=" + isNativeLibLoaded);
|
||||
return isNativeLibLoaded;
|
||||
}
|
||||
|
||||
static boolean isDirectAudioEnabled() {
|
||||
return isFeatureLibLoaded(FEATURE_DIRECT_AUDIO);
|
||||
if (Printer.debug) Printer.debug("Platform: Checking for DirectAudio; library is loaded=" + isNativeLibLoaded);
|
||||
return isNativeLibLoaded;
|
||||
}
|
||||
|
||||
private static boolean isFeatureLibLoaded(int feature) {
|
||||
if (Printer.debug) Printer.debug("Platform: Checking for feature "+feature+"...");
|
||||
int requiredLib = nGetLibraryForFeature(feature);
|
||||
boolean isLoaded = (requiredLib != 0) && ((loadedLibs & requiredLib) == requiredLib);
|
||||
if (Printer.debug) Printer.debug(" ...needs library "+requiredLib+". Result is loaded="+isLoaded);
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
// the following native methods are implemented in Platform.c
|
||||
// the following native method is implemented in Platform.c
|
||||
private static native boolean nIsBigEndian();
|
||||
private static native String nGetExtraLibraries();
|
||||
private static native int nGetLibraryForFeature(int feature);
|
||||
|
||||
/**
|
||||
* Read the required system properties.
|
||||
*/
|
||||
private static void readProperties() {
|
||||
// $$fb 2002-03-06: implement check for endianness in native. Facilitates porting !
|
||||
bigEndian = nIsBigEndian();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -41,83 +41,3 @@ DEF_STATIC_JNI_OnLoad
|
||||
JNIEXPORT jboolean JNICALL Java_com_sun_media_sound_Platform_nIsBigEndian(JNIEnv *env, jclass clss) {
|
||||
return UTIL_IsBigEndianPlatform();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_sun_media_sound_Platform
|
||||
* Method: nGetExtraLibraries
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_sun_media_sound_Platform_nGetExtraLibraries(JNIEnv *env, jclass clss) {
|
||||
return (*env)->NewStringUTF(env, EXTRA_SOUND_JNI_LIBS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_sun_media_sound_Platform
|
||||
* Method: nGetLibraryForFeature
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_sun_media_sound_Platform_nGetLibraryForFeature
|
||||
(JNIEnv *env, jclass clazz, jint feature) {
|
||||
|
||||
// for every OS
|
||||
#if X_PLATFORM == X_WINDOWS
|
||||
switch (feature) {
|
||||
case com_sun_media_sound_Platform_FEATURE_MIDIIO:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
case com_sun_media_sound_Platform_FEATURE_PORTS:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
|
||||
return com_sun_media_sound_Platform_LIB_DSOUND;
|
||||
}
|
||||
#endif
|
||||
#if (X_PLATFORM == X_SOLARIS)
|
||||
switch (feature) {
|
||||
case com_sun_media_sound_Platform_FEATURE_MIDIIO:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
case com_sun_media_sound_Platform_FEATURE_PORTS:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
}
|
||||
#endif
|
||||
#if (X_PLATFORM == X_LINUX)
|
||||
switch (feature) {
|
||||
case com_sun_media_sound_Platform_FEATURE_MIDIIO:
|
||||
return com_sun_media_sound_Platform_LIB_ALSA;
|
||||
case com_sun_media_sound_Platform_FEATURE_PORTS:
|
||||
return com_sun_media_sound_Platform_LIB_ALSA;
|
||||
case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
|
||||
return com_sun_media_sound_Platform_LIB_ALSA;
|
||||
}
|
||||
#endif
|
||||
#if (X_PLATFORM == X_MACOSX)
|
||||
switch (feature) {
|
||||
case com_sun_media_sound_Platform_FEATURE_MIDIIO:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
case com_sun_media_sound_Platform_FEATURE_PORTS:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
}
|
||||
#endif
|
||||
#if (X_PLATFORM == X_BSD)
|
||||
switch (feature) {
|
||||
case com_sun_media_sound_Platform_FEATURE_MIDIIO:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
#ifdef __FreeBSD__
|
||||
case com_sun_media_sound_Platform_FEATURE_PORTS:
|
||||
return com_sun_media_sound_Platform_LIB_ALSA;
|
||||
case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
|
||||
return com_sun_media_sound_Platform_LIB_ALSA;
|
||||
#else
|
||||
case com_sun_media_sound_Platform_FEATURE_PORTS:
|
||||
return com_sun_media_sound_Platform_LIB_MAIN;
|
||||
case com_sun_media_sound_Platform_FEATURE_DIRECT_AUDIO:
|
||||
// XXXBSD: When native Direct Audio support is ported change
|
||||
// this back to returning com_sun_media_sound_Platform_LIB_MAIN
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
//#define USE_ERROR
|
||||
//#define USE_TRACE
|
||||
|
||||
#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
|
||||
|
||||
static void alsaDebugOutput(const char *file, int line, const char *function, int err, const char *fmt, ...) {
|
||||
#ifdef USE_ERROR
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printf("%s:%d function %s: error %d: %s\n", file, line, function, err, snd_strerror(err));
|
||||
if (strlen(fmt) > 0) {
|
||||
vprintf(fmt, args);
|
||||
}
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int alsa_inited = 0;
|
||||
static int alsa_enumerate_pcm_subdevices = FALSE; // default: no
|
||||
static int alsa_enumerate_midi_subdevices = FALSE; // default: no
|
||||
|
||||
void initAlsaSupport() {
|
||||
char* enumerate;
|
||||
if (!alsa_inited) {
|
||||
alsa_inited = TRUE;
|
||||
snd_lib_error_set_handler(&alsaDebugOutput);
|
||||
|
||||
enumerate = getenv(ENV_ENUMERATE_PCM_SUBDEVICES);
|
||||
if (enumerate != NULL && strlen(enumerate) > 0
|
||||
&& (enumerate[0] != 'f') // false
|
||||
&& (enumerate[0] != 'F') // False
|
||||
&& (enumerate[0] != 'n') // no
|
||||
&& (enumerate[0] != 'N')) { // NO
|
||||
alsa_enumerate_pcm_subdevices = TRUE;
|
||||
}
|
||||
#ifdef ALSA_MIDI_ENUMERATE_SUBDEVICES
|
||||
alsa_enumerate_midi_subdevices = TRUE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* if true (non-zero), ALSA sub devices should be listed as separate devices
|
||||
*/
|
||||
int needEnumerateSubdevices(int isMidi) {
|
||||
initAlsaSupport();
|
||||
return isMidi ? alsa_enumerate_midi_subdevices
|
||||
: alsa_enumerate_pcm_subdevices;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* deviceID contains packed card, device and subdevice numbers
|
||||
* each number takes 10 bits
|
||||
* "default" device has id == ALSA_DEFAULT_DEVICE_ID
|
||||
*/
|
||||
UINT32 encodeDeviceID(int card, int device, int subdevice) {
|
||||
return (((card & 0x3FF) << 20) | ((device & 0x3FF) << 10)
|
||||
| (subdevice & 0x3FF)) + 1;
|
||||
}
|
||||
|
||||
|
||||
void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice,
|
||||
int isMidi) {
|
||||
deviceID--;
|
||||
*card = (deviceID >> 20) & 0x3FF;
|
||||
*device = (deviceID >> 10) & 0x3FF;
|
||||
if (needEnumerateSubdevices(isMidi)) {
|
||||
*subdevice = deviceID & 0x3FF;
|
||||
} else {
|
||||
*subdevice = -1; // ALSA will choose any subdevices
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void getDeviceString(char* buffer, int card, int device, int subdevice,
|
||||
int usePlugHw, int isMidi) {
|
||||
if (needEnumerateSubdevices(isMidi)) {
|
||||
sprintf(buffer, "%s:%d,%d,%d",
|
||||
usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
|
||||
card, device, subdevice);
|
||||
} else {
|
||||
sprintf(buffer, "%s:%d,%d",
|
||||
usePlugHw ? ALSA_PLUGHARDWARE : ALSA_HARDWARE,
|
||||
card, device);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID,
|
||||
int usePlugHw, int isMidi) {
|
||||
int card, device, subdevice;
|
||||
|
||||
if (deviceID == ALSA_DEFAULT_DEVICE_ID) {
|
||||
strcpy(buffer, ALSA_DEFAULT_DEVICE_NAME);
|
||||
} else {
|
||||
decodeDeviceID(deviceID, &card, &device, &subdevice, isMidi);
|
||||
getDeviceString(buffer, card, device, subdevice, usePlugHw, isMidi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hasGottenALSAVersion = FALSE;
|
||||
#define ALSAVersionString_LENGTH 200
|
||||
static char ALSAVersionString[ALSAVersionString_LENGTH];
|
||||
|
||||
void getALSAVersion(char* buffer, int len) {
|
||||
if (!hasGottenALSAVersion) {
|
||||
// get alsa version from proc interface
|
||||
FILE* file;
|
||||
int curr, len, totalLen, inVersionString;
|
||||
file = fopen(ALSA_VERSION_PROC_FILE, "r");
|
||||
ALSAVersionString[0] = 0;
|
||||
if (file) {
|
||||
if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) {
|
||||
// parse for version number
|
||||
totalLen = strlen(ALSAVersionString);
|
||||
inVersionString = FALSE;
|
||||
len = 0;
|
||||
curr = 0;
|
||||
while (curr < totalLen) {
|
||||
if (!inVersionString) {
|
||||
// is this char the beginning of a version string ?
|
||||
if (ALSAVersionString[curr] >= '0'
|
||||
&& ALSAVersionString[curr] <= '9') {
|
||||
inVersionString = TRUE;
|
||||
}
|
||||
}
|
||||
if (inVersionString) {
|
||||
// the version string ends with white space
|
||||
if (ALSAVersionString[curr] <= 32) {
|
||||
break;
|
||||
}
|
||||
if (curr != len) {
|
||||
// copy this char to the beginning of the string
|
||||
ALSAVersionString[len] = ALSAVersionString[curr];
|
||||
}
|
||||
len++;
|
||||
}
|
||||
curr++;
|
||||
}
|
||||
// remove trailing dots
|
||||
while ((len > 0) && (ALSAVersionString[len - 1] == '.')) {
|
||||
len--;
|
||||
}
|
||||
// null terminate
|
||||
ALSAVersionString[len] = 0;
|
||||
}
|
||||
fclose(file);
|
||||
hasGottenALSAVersion = TRUE;
|
||||
}
|
||||
}
|
||||
strncpy(buffer, ALSAVersionString, len);
|
||||
}
|
||||
|
||||
|
||||
/* end */
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "Utilities.h"
|
||||
|
||||
#ifndef PLATFORM_API_BSDOS_ALSA_COMMONUTILS_H_INCLUDED
|
||||
#define PLATFORM_API_BSDOS_ALSA_COMMONUTILS_H_INCLUDED
|
||||
|
||||
#define ALSA_VERSION_PROC_FILE "/proc/asound/version"
|
||||
#define ALSA_HARDWARE "hw"
|
||||
#define ALSA_HARDWARE_CARD ALSA_HARDWARE":%d"
|
||||
#define ALSA_HARDWARE_DEVICE ALSA_HARDWARE_CARD",%d"
|
||||
#define ALSA_HARDWARE_SUBDEVICE ALSA_HARDWARE_DEVICE",%d"
|
||||
|
||||
#define ALSA_PLUGHARDWARE "plughw"
|
||||
#define ALSA_DEFAULT_DEVICE_NAME "default"
|
||||
|
||||
#define ALSA_DEFAULT_DEVICE_ID (0)
|
||||
|
||||
#define ALSA_PCM (0)
|
||||
#define ALSA_RAWMIDI (1)
|
||||
|
||||
// for use in info objects
|
||||
#define ALSA_VENDOR "ALSA (http://www.alsa-project.org)"
|
||||
|
||||
// Environment variable for inclusion of subdevices in device listing.
|
||||
// If this variable is unset or "no", then subdevices are ignored, and
|
||||
// it's ALSA's choice which one to use (enables hardware mixing)
|
||||
#define ENV_ENUMERATE_PCM_SUBDEVICES "ALSA_ENUMERATE_PCM_SUBDEVICES"
|
||||
|
||||
// if defined, subdevices are listed.
|
||||
//#undef ALSA_MIDI_ENUMERATE_SUBDEVICES
|
||||
#define ALSA_MIDI_ENUMERATE_SUBDEVICES
|
||||
|
||||
// must be called before any ALSA calls
|
||||
void initAlsaSupport();
|
||||
|
||||
/* if true (non-zero), ALSA sub devices should be listed as separate devices
|
||||
*/
|
||||
int needEnumerateSubdevices(int isMidi);
|
||||
|
||||
|
||||
/*
|
||||
* deviceID contains packed card, device and subdevice numbers
|
||||
* each number takes 10 bits
|
||||
* "default" device has id == ALSA_DEFAULT_DEVICE_ID
|
||||
*/
|
||||
UINT32 encodeDeviceID(int card, int device, int subdevice);
|
||||
|
||||
void decodeDeviceID(UINT32 deviceID, int* card, int* device, int* subdevice,
|
||||
int isMidi);
|
||||
|
||||
void getDeviceStringFromDeviceID(char* buffer, UINT32 deviceID,
|
||||
int usePlugHw, int isMidi);
|
||||
|
||||
void getALSAVersion(char* buffer, int len);
|
||||
|
||||
|
||||
#endif // PLATFORM_API_BSDOS_ALSA_COMMONUTILS_H_INCLUDED
|
@ -1,354 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#define USE_ERROR
|
||||
#define USE_TRACE
|
||||
|
||||
#if USE_PLATFORM_MIDI_IN == TRUE
|
||||
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "PlatformMidi.h"
|
||||
#include "PLATFORM_API_BsdOS_ALSA_MidiUtils.h"
|
||||
#if defined(i586)
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
|
||||
static inline UINT32 packMessage(int status, int data1, int data2) {
|
||||
return ((status & 0xFF) | ((data1 & 0xFF) << 8) | ((data2 & 0xFF) << 16));
|
||||
}
|
||||
|
||||
|
||||
static void setShortMessage(MidiMessage* message,
|
||||
int status, int data1, int data2) {
|
||||
message->type = SHORT_MESSAGE;
|
||||
message->data.s.packedMsg = packMessage(status, data1, data2);
|
||||
}
|
||||
|
||||
|
||||
static void setRealtimeMessage(MidiMessage* message, int status) {
|
||||
setShortMessage(message, status, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
static void set14bitMessage(MidiMessage* message, int status, int value) {
|
||||
TRACE3("14bit value: %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F);
|
||||
value &= 0x3FFF;
|
||||
TRACE3("14bit value (2): %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F);
|
||||
setShortMessage(message, status,
|
||||
value & 0x7F,
|
||||
(value >> 7) & 0x7F);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* implementation of the platform-dependent
|
||||
* MIDI in functions declared in PlatformMidi.h
|
||||
*/
|
||||
|
||||
char* MIDI_IN_GetErrorStr(INT32 err) {
|
||||
return (char*) getErrorStr(err);
|
||||
}
|
||||
|
||||
INT32 MIDI_IN_GetNumDevices() {
|
||||
/* Workaround for 6842956: 32bit app on 64bit bsd
|
||||
* gets assertion failure trying to open midiIn ports.
|
||||
* Untill the issue is fixed in ALSA
|
||||
* (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4807)
|
||||
* report no midi in devices in the configuration.
|
||||
*/
|
||||
#if defined(i586)
|
||||
static int jre32onbsd64 = -1;
|
||||
if (jre32onbsd64 < 0) {
|
||||
jre32onbsd64 = 0;
|
||||
/* The workaround may be disabled setting "JAVASOUND_ENABLE_MIDIIN"
|
||||
* environment variable.
|
||||
*/
|
||||
if (getenv("JAVASOUND_ENABLE_MIDIIN") == NULL) {
|
||||
struct utsname u;
|
||||
jre32onbsd64 = 0;
|
||||
if (uname(&u) == 0) {
|
||||
if (strstr(u.machine, "64") != NULL) {
|
||||
TRACE0("jre32 on bsd64 detected - report no midiIn devices\n");
|
||||
jre32onbsd64 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jre32onbsd64) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE0("MIDI_IN_GetNumDevices()\n");
|
||||
|
||||
return getMidiDeviceCount(SND_RAWMIDI_STREAM_INPUT);
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_IN_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
||||
int ret = getMidiDeviceName(SND_RAWMIDI_STREAM_INPUT, deviceIndex,
|
||||
name, nameLength);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_IN_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
||||
int ret = getMidiDeviceVendor(deviceIndex, name, nameLength);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_IN_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
||||
int ret = getMidiDeviceDescription(SND_RAWMIDI_STREAM_INPUT, deviceIndex,
|
||||
name, nameLength);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_IN_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
||||
int ret = getMidiDeviceVersion(deviceIndex, name, nameLength);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
INT32 MIDI_IN_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) {
|
||||
INT32 ret;
|
||||
TRACE0("> MIDI_IN_OpenDevice\n");
|
||||
ret = openMidiDevice(SND_RAWMIDI_STREAM_INPUT, deviceIndex, handle);
|
||||
TRACE1("< MIDI_IN_OpenDevice: returning %d\n", (int) ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_IN_CloseDevice(MidiDeviceHandle* handle) {
|
||||
INT32 ret;
|
||||
TRACE0("> MIDI_IN_CloseDevice\n");
|
||||
ret = closeMidiDevice(handle);
|
||||
TRACE1("< MIDI_IN_CloseDevice: returning %d\n", (int) ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_IN_StartDevice(MidiDeviceHandle* handle) {
|
||||
TRACE0("MIDI_IN_StartDevice\n");
|
||||
return MIDI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_IN_StopDevice(MidiDeviceHandle* handle) {
|
||||
TRACE0("MIDI_IN_StopDevice\n");
|
||||
return MIDI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
INT64 MIDI_IN_GetTimeStamp(MidiDeviceHandle* handle) {
|
||||
return getMidiTimestamp(handle);
|
||||
}
|
||||
|
||||
|
||||
/* read the next message from the queue */
|
||||
MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle) {
|
||||
snd_seq_event_t alsa_message;
|
||||
MidiMessage* jdk_message;
|
||||
int err;
|
||||
char buffer[1];
|
||||
int status;
|
||||
|
||||
TRACE0("> MIDI_IN_GetMessage\n");
|
||||
if (!handle) {
|
||||
ERROR0("< ERROR: MIDI_IN_GetMessage(): handle is NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!handle->deviceHandle) {
|
||||
ERROR0("< ERROR: MIDI_IN_GetMessage(): native handle is NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!handle->platformData) {
|
||||
ERROR0("< ERROR: MIDI_IN_GetMessage(): platformData is NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* For MIDI In, the device is left in non blocking mode. So if there is
|
||||
no data from the device, snd_rawmidi_read() returns with -11 (EAGAIN).
|
||||
This results in jumping back to the Java layer. */
|
||||
while (TRUE) {
|
||||
TRACE0("before snd_rawmidi_read()\n");
|
||||
err = snd_rawmidi_read((snd_rawmidi_t*) handle->deviceHandle, buffer, 1);
|
||||
TRACE0("after snd_rawmidi_read()\n");
|
||||
if (err != 1) {
|
||||
ERROR2("< ERROR: MIDI_IN_GetMessage(): snd_rawmidi_read() returned %d : %s\n", err, snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
// printf("received byte: %d\n", buffer[0]);
|
||||
err = snd_midi_event_encode_byte((snd_midi_event_t*) handle->platformData,
|
||||
(int) buffer[0],
|
||||
&alsa_message);
|
||||
if (err == 1) {
|
||||
break;
|
||||
} else if (err < 0) {
|
||||
ERROR1("< ERROR: MIDI_IN_GetMessage(): snd_midi_event_encode_byte() returned %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
jdk_message = (MidiMessage*) calloc(sizeof(MidiMessage), 1);
|
||||
if (!jdk_message) {
|
||||
ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
// TODO: tra
|
||||
switch (alsa_message.type) {
|
||||
case SND_SEQ_EVENT_NOTEON:
|
||||
case SND_SEQ_EVENT_NOTEOFF:
|
||||
case SND_SEQ_EVENT_KEYPRESS:
|
||||
status = (alsa_message.type == SND_SEQ_EVENT_KEYPRESS) ? 0xA0 :
|
||||
(alsa_message.type == SND_SEQ_EVENT_NOTEON) ? 0x90 : 0x80;
|
||||
status |= alsa_message.data.note.channel;
|
||||
setShortMessage(jdk_message, status,
|
||||
alsa_message.data.note.note,
|
||||
alsa_message.data.note.velocity);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_CONTROLLER:
|
||||
status = 0xB0 | alsa_message.data.control.channel;
|
||||
setShortMessage(jdk_message, status,
|
||||
alsa_message.data.control.param,
|
||||
alsa_message.data.control.value);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_PGMCHANGE:
|
||||
case SND_SEQ_EVENT_CHANPRESS:
|
||||
status = (alsa_message.type == SND_SEQ_EVENT_PGMCHANGE) ? 0xC0 : 0xD0;
|
||||
status |= alsa_message.data.control.channel;
|
||||
setShortMessage(jdk_message, status,
|
||||
alsa_message.data.control.value, 0);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_PITCHBEND:
|
||||
status = 0xE0 | alsa_message.data.control.channel;
|
||||
// $$mp 2003-09-23:
|
||||
// possible hack to work around a bug in ALSA. Necessary for
|
||||
// ALSA 0.9.2. May be fixed in newer versions of ALSA.
|
||||
// alsa_message.data.control.value ^= 0x2000;
|
||||
// TRACE1("pitchbend value: %d\n", alsa_message.data.control.value);
|
||||
set14bitMessage(jdk_message, status,
|
||||
alsa_message.data.control.value);
|
||||
break;
|
||||
|
||||
/* System exclusive messages */
|
||||
|
||||
case SND_SEQ_EVENT_SYSEX:
|
||||
jdk_message->type = LONG_MESSAGE;
|
||||
jdk_message->data.l.size = alsa_message.data.ext.len;
|
||||
jdk_message->data.l.data = malloc(alsa_message.data.ext.len);
|
||||
if (jdk_message->data.l.data == NULL) {
|
||||
ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n");
|
||||
free(jdk_message);
|
||||
jdk_message = NULL;
|
||||
} else {
|
||||
memcpy(jdk_message->data.l.data, alsa_message.data.ext.ptr, alsa_message.data.ext.len);
|
||||
}
|
||||
break;
|
||||
|
||||
/* System common messages */
|
||||
|
||||
case SND_SEQ_EVENT_QFRAME:
|
||||
setShortMessage(jdk_message, 0xF1,
|
||||
alsa_message.data.control.value & 0x7F, 0);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_SONGPOS:
|
||||
set14bitMessage(jdk_message, 0xF2,
|
||||
alsa_message.data.control.value);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_SONGSEL:
|
||||
setShortMessage(jdk_message, 0xF3,
|
||||
alsa_message.data.control.value & 0x7F, 0);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_TUNE_REQUEST:
|
||||
setRealtimeMessage(jdk_message, 0xF6);
|
||||
break;
|
||||
|
||||
/* System realtime messages */
|
||||
|
||||
case SND_SEQ_EVENT_CLOCK:
|
||||
setRealtimeMessage(jdk_message, 0xF8);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_START:
|
||||
setRealtimeMessage(jdk_message, 0xFA);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_CONTINUE:
|
||||
setRealtimeMessage(jdk_message, 0xFB);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_STOP:
|
||||
setRealtimeMessage(jdk_message, 0xFC);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_SENSING:
|
||||
setRealtimeMessage(jdk_message, 0xFE);
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_RESET:
|
||||
setRealtimeMessage(jdk_message, 0xFF);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR0("< ERROR: MIDI_IN_GetMessage(): unhandled ALSA MIDI message type\n");
|
||||
free(jdk_message);
|
||||
jdk_message = NULL;
|
||||
|
||||
}
|
||||
|
||||
// set timestamp
|
||||
if (jdk_message != NULL) {
|
||||
jdk_message->timestamp = getMidiTimestamp(handle);
|
||||
}
|
||||
TRACE1("< MIDI_IN_GetMessage: returning %p\n", jdk_message);
|
||||
return jdk_message;
|
||||
}
|
||||
|
||||
|
||||
void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg) {
|
||||
if (!msg) {
|
||||
ERROR0("< ERROR: MIDI_IN_ReleaseMessage(): message is NULL\n");
|
||||
return;
|
||||
}
|
||||
if (msg->type == LONG_MESSAGE && msg->data.l.data) {
|
||||
free(msg->data.l.data);
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
|
||||
#endif /* USE_PLATFORM_MIDI_IN */
|
@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#define USE_ERROR
|
||||
#define USE_TRACE
|
||||
|
||||
#if USE_PLATFORM_MIDI_OUT == TRUE
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "PlatformMidi.h"
|
||||
#include "PLATFORM_API_BsdOS_ALSA_MidiUtils.h"
|
||||
|
||||
|
||||
|
||||
static int CHANNEL_MESSAGE_LENGTH[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 3, 3, 2, 2, 3 };
|
||||
/* 8x 9x Ax Bx Cx Dx Ex */
|
||||
|
||||
static int SYSTEM_MESSAGE_LENGTH[] = {
|
||||
-1, 2, 3, 2, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1 };
|
||||
/* F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF */
|
||||
|
||||
|
||||
// the returned length includes the status byte.
|
||||
// for illegal messages, -1 is returned.
|
||||
static int getShortMessageLength(int status) {
|
||||
int dataLength = 0;
|
||||
if (status < 0xF0) { // channel voice message
|
||||
dataLength = CHANNEL_MESSAGE_LENGTH[(status >> 4) & 0xF];
|
||||
} else {
|
||||
dataLength = SYSTEM_MESSAGE_LENGTH[status & 0xF];
|
||||
}
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* implementation of the platform-dependent
|
||||
* MIDI out functions declared in PlatformMidi.h
|
||||
*/
|
||||
char* MIDI_OUT_GetErrorStr(INT32 err) {
|
||||
return (char*) getErrorStr(err);
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_OUT_GetNumDevices() {
|
||||
TRACE0("MIDI_OUT_GetNumDevices()\n");
|
||||
return getMidiDeviceCount(SND_RAWMIDI_STREAM_OUTPUT);
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_OUT_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
||||
TRACE0("MIDI_OUT_GetDeviceName()\n");
|
||||
return getMidiDeviceName(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex,
|
||||
name, nameLength);
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
||||
TRACE0("MIDI_OUT_GetDeviceVendor()\n");
|
||||
return getMidiDeviceVendor(deviceIndex, name, nameLength);
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
||||
TRACE0("MIDI_OUT_GetDeviceDescription()\n");
|
||||
return getMidiDeviceDescription(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex,
|
||||
name, nameLength);
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
||||
TRACE0("MIDI_OUT_GetDeviceVersion()\n");
|
||||
return getMidiDeviceVersion(deviceIndex, name, nameLength);
|
||||
}
|
||||
|
||||
|
||||
/* *************************** MidiOutDevice implementation *************** */
|
||||
|
||||
INT32 MIDI_OUT_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) {
|
||||
TRACE1("MIDI_OUT_OpenDevice(): deviceIndex: %d\n", (int) deviceIndex);
|
||||
return openMidiDevice(SND_RAWMIDI_STREAM_OUTPUT, deviceIndex, handle);
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) {
|
||||
TRACE0("MIDI_OUT_CloseDevice()\n");
|
||||
return closeMidiDevice(handle);
|
||||
}
|
||||
|
||||
|
||||
INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) {
|
||||
return getMidiTimestamp(handle);
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg,
|
||||
UINT32 timestamp) {
|
||||
int err;
|
||||
int status;
|
||||
int data1;
|
||||
int data2;
|
||||
char buffer[3];
|
||||
|
||||
TRACE2("> MIDI_OUT_SendShortMessage() %x, time: %u\n", packedMsg, (unsigned int) timestamp);
|
||||
if (!handle) {
|
||||
ERROR0("< ERROR: MIDI_OUT_SendShortMessage(): handle is NULL\n");
|
||||
return MIDI_INVALID_HANDLE;
|
||||
}
|
||||
if (!handle->deviceHandle) {
|
||||
ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): native handle is NULL\n");
|
||||
return MIDI_INVALID_HANDLE;
|
||||
}
|
||||
status = (packedMsg & 0xFF);
|
||||
buffer[0] = (char) status;
|
||||
buffer[1] = (char) ((packedMsg >> 8) & 0xFF);
|
||||
buffer[2] = (char) ((packedMsg >> 16) & 0xFF);
|
||||
TRACE4("status: %d, data1: %d, data2: %d, length: %d\n", (int) buffer[0], (int) buffer[1], (int) buffer[2], getShortMessageLength(status));
|
||||
err = snd_rawmidi_write((snd_rawmidi_t*) handle->deviceHandle, buffer, getShortMessageLength(status));
|
||||
if (err < 0) {
|
||||
ERROR1(" ERROR: MIDI_OUT_SendShortMessage(): snd_rawmidi_write() returned %d\n", err);
|
||||
}
|
||||
|
||||
TRACE0("< MIDI_OUT_SendShortMessage()\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data,
|
||||
UINT32 size, UINT32 timestamp) {
|
||||
int err;
|
||||
|
||||
TRACE2("> MIDI_OUT_SendLongMessage() size %u, time: %u\n", (unsigned int) size, (unsigned int) timestamp);
|
||||
if (!handle) {
|
||||
ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): handle is NULL\n");
|
||||
return MIDI_INVALID_HANDLE;
|
||||
}
|
||||
if (!handle->deviceHandle) {
|
||||
ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): native handle is NULL\n");
|
||||
return MIDI_INVALID_HANDLE;
|
||||
}
|
||||
if (!data) {
|
||||
ERROR0("< ERROR: MIDI_OUT_SendLongMessage(): data is NULL\n");
|
||||
return MIDI_INVALID_HANDLE;
|
||||
}
|
||||
err = snd_rawmidi_write((snd_rawmidi_t*) handle->deviceHandle,
|
||||
data, size);
|
||||
if (err < 0) {
|
||||
ERROR1(" ERROR: MIDI_OUT_SendLongMessage(): snd_rawmidi_write() returned %d\n", err);
|
||||
}
|
||||
|
||||
TRACE0("< MIDI_OUT_SendLongMessage()\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
#endif /* USE_PLATFORM_MIDI_OUT */
|
@ -1,481 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#define USE_ERROR
|
||||
#define USE_TRACE
|
||||
|
||||
#include "PLATFORM_API_BsdOS_ALSA_MidiUtils.h"
|
||||
#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static INT64 getTimeInMicroseconds() {
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * 1000000UL) + tv.tv_usec;
|
||||
}
|
||||
|
||||
|
||||
const char* getErrorStr(INT32 err) {
|
||||
return snd_strerror((int) err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// callback for iteration through devices
|
||||
// returns TRUE if iteration should continue
|
||||
typedef int (*DeviceIteratorPtr)(UINT32 deviceID,
|
||||
snd_rawmidi_info_t* rawmidi_info,
|
||||
snd_ctl_card_info_t* cardinfo,
|
||||
void *userData);
|
||||
|
||||
// for each ALSA device, call iterator. userData is passed to the iterator
|
||||
// returns total number of iterations
|
||||
static int iterateRawmidiDevices(snd_rawmidi_stream_t direction,
|
||||
DeviceIteratorPtr iterator,
|
||||
void* userData) {
|
||||
int count = 0;
|
||||
int subdeviceCount;
|
||||
int card, dev, subDev;
|
||||
char devname[16];
|
||||
int err;
|
||||
snd_ctl_t *handle;
|
||||
snd_rawmidi_t *rawmidi;
|
||||
snd_rawmidi_info_t *rawmidi_info;
|
||||
snd_ctl_card_info_t *card_info, *defcardinfo = NULL;
|
||||
UINT32 deviceID;
|
||||
int doContinue = TRUE;
|
||||
|
||||
snd_rawmidi_info_malloc(&rawmidi_info);
|
||||
snd_ctl_card_info_malloc(&card_info);
|
||||
|
||||
// 1st try "default" device
|
||||
if (direction == SND_RAWMIDI_STREAM_INPUT) {
|
||||
err = snd_rawmidi_open(&rawmidi, NULL, ALSA_DEFAULT_DEVICE_NAME,
|
||||
SND_RAWMIDI_NONBLOCK);
|
||||
} else if (direction == SND_RAWMIDI_STREAM_OUTPUT) {
|
||||
err = snd_rawmidi_open(NULL, &rawmidi, ALSA_DEFAULT_DEVICE_NAME,
|
||||
SND_RAWMIDI_NONBLOCK);
|
||||
} else {
|
||||
ERROR0("ERROR: iterateRawmidiDevices(): direction is neither"
|
||||
" SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n");
|
||||
err = MIDI_INVALID_ARGUMENT;
|
||||
}
|
||||
if (err < 0) {
|
||||
ERROR1("ERROR: snd_rawmidi_open (\"default\"): %s\n",
|
||||
snd_strerror(err));
|
||||
} else {
|
||||
err = snd_rawmidi_info(rawmidi, rawmidi_info);
|
||||
|
||||
snd_rawmidi_close(rawmidi);
|
||||
if (err < 0) {
|
||||
ERROR1("ERROR: snd_rawmidi_info (\"default\"): %s\n",
|
||||
snd_strerror(err));
|
||||
} else {
|
||||
// try to get card info
|
||||
card = snd_rawmidi_info_get_card(rawmidi_info);
|
||||
if (card >= 0) {
|
||||
sprintf(devname, ALSA_HARDWARE_CARD, card);
|
||||
if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) {
|
||||
if (snd_ctl_card_info(handle, card_info) >= 0) {
|
||||
defcardinfo = card_info;
|
||||
}
|
||||
snd_ctl_close(handle);
|
||||
}
|
||||
}
|
||||
// call calback function for the device
|
||||
if (iterator != NULL) {
|
||||
doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, rawmidi_info,
|
||||
defcardinfo, userData);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// iterate cards
|
||||
card = -1;
|
||||
TRACE0("testing for cards...\n");
|
||||
if (snd_card_next(&card) >= 0) {
|
||||
TRACE1("Found card %d\n", card);
|
||||
while (doContinue && (card >= 0)) {
|
||||
sprintf(devname, ALSA_HARDWARE_CARD, card);
|
||||
TRACE1("Opening control for alsa rawmidi device \"%s\"...\n", devname);
|
||||
err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK);
|
||||
if (err < 0) {
|
||||
ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err));
|
||||
} else {
|
||||
TRACE0("snd_ctl_open() SUCCESS\n");
|
||||
err = snd_ctl_card_info(handle, card_info);
|
||||
if (err < 0) {
|
||||
ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", card, snd_strerror(err));
|
||||
} else {
|
||||
TRACE0("snd_ctl_card_info() SUCCESS\n");
|
||||
dev = -1;
|
||||
while (doContinue) {
|
||||
if (snd_ctl_rawmidi_next_device(handle, &dev) < 0) {
|
||||
ERROR0("snd_ctl_rawmidi_next_device\n");
|
||||
}
|
||||
TRACE0("snd_ctl_rawmidi_next_device() SUCCESS\n");
|
||||
if (dev < 0) {
|
||||
break;
|
||||
}
|
||||
snd_rawmidi_info_set_device(rawmidi_info, dev);
|
||||
snd_rawmidi_info_set_subdevice(rawmidi_info, 0);
|
||||
snd_rawmidi_info_set_stream(rawmidi_info, direction);
|
||||
err = snd_ctl_rawmidi_info(handle, rawmidi_info);
|
||||
TRACE0("after snd_ctl_rawmidi_info()\n");
|
||||
if (err < 0) {
|
||||
if (err != -ENOENT) {
|
||||
ERROR2("ERROR: snd_ctl_rawmidi_info, card=%d: %s", card, snd_strerror(err));
|
||||
}
|
||||
} else {
|
||||
TRACE0("snd_ctl_rawmidi_info() SUCCESS\n");
|
||||
subdeviceCount = needEnumerateSubdevices(ALSA_RAWMIDI)
|
||||
? snd_rawmidi_info_get_subdevices_count(rawmidi_info)
|
||||
: 1;
|
||||
if (iterator!=NULL) {
|
||||
for (subDev = 0; subDev < subdeviceCount; subDev++) {
|
||||
TRACE3(" Iterating %d,%d,%d\n", card, dev, subDev);
|
||||
deviceID = encodeDeviceID(card, dev, subDev);
|
||||
doContinue = (*iterator)(deviceID, rawmidi_info,
|
||||
card_info, userData);
|
||||
count++;
|
||||
TRACE0("returned from iterator\n");
|
||||
if (!doContinue) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
count += subdeviceCount;
|
||||
}
|
||||
}
|
||||
} // of while(doContinue)
|
||||
}
|
||||
snd_ctl_close(handle);
|
||||
}
|
||||
if (snd_card_next(&card) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ERROR0("No cards found!\n");
|
||||
}
|
||||
snd_ctl_card_info_free(card_info);
|
||||
snd_rawmidi_info_free(rawmidi_info);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int getMidiDeviceCount(snd_rawmidi_stream_t direction) {
|
||||
int deviceCount;
|
||||
TRACE0("> getMidiDeviceCount()\n");
|
||||
initAlsaSupport();
|
||||
deviceCount = iterateRawmidiDevices(direction, NULL, NULL);
|
||||
TRACE0("< getMidiDeviceCount()\n");
|
||||
return deviceCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
userData is assumed to be a pointer to ALSA_MIDIDeviceDescription.
|
||||
ALSA_MIDIDeviceDescription->index has to be set to the index of the device
|
||||
we want to get information of before this method is called the first time via
|
||||
iterateRawmidiDevices(). On each call of this method,
|
||||
ALSA_MIDIDeviceDescription->index is decremented. If it is equal to zero,
|
||||
we have reached the desired device, so action is taken.
|
||||
So after successful completion of iterateRawmidiDevices(),
|
||||
ALSA_MIDIDeviceDescription->index is zero. If it isn't, this is an
|
||||
indication of an error.
|
||||
*/
|
||||
static int deviceInfoIterator(UINT32 deviceID, snd_rawmidi_info_t *rawmidi_info,
|
||||
snd_ctl_card_info_t *cardinfo, void *userData) {
|
||||
char buffer[300];
|
||||
ALSA_MIDIDeviceDescription* desc = (ALSA_MIDIDeviceDescription*)userData;
|
||||
#ifdef ALSA_MIDI_USE_PLUGHW
|
||||
int usePlugHw = 1;
|
||||
#else
|
||||
int usePlugHw = 0;
|
||||
#endif
|
||||
|
||||
TRACE0("deviceInfoIterator\n");
|
||||
initAlsaSupport();
|
||||
if (desc->index == 0) {
|
||||
// we found the device with correct index
|
||||
desc->deviceID = deviceID;
|
||||
|
||||
buffer[0]=' '; buffer[1]='[';
|
||||
// buffer[300] is enough to store the actual device string w/o overrun
|
||||
getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_RAWMIDI);
|
||||
strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1);
|
||||
strncpy(desc->name,
|
||||
(cardinfo != NULL)
|
||||
? snd_ctl_card_info_get_id(cardinfo)
|
||||
: snd_rawmidi_info_get_id(rawmidi_info),
|
||||
desc->strLen - strlen(buffer));
|
||||
strncat(desc->name, buffer, desc->strLen - strlen(desc->name));
|
||||
desc->description[0] = 0;
|
||||
if (cardinfo != NULL) {
|
||||
strncpy(desc->description, snd_ctl_card_info_get_name(cardinfo),
|
||||
desc->strLen);
|
||||
strncat(desc->description, ", ",
|
||||
desc->strLen - strlen(desc->description));
|
||||
}
|
||||
strncat(desc->description, snd_rawmidi_info_get_id(rawmidi_info),
|
||||
desc->strLen - strlen(desc->description));
|
||||
strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
|
||||
strncat(desc->description, snd_rawmidi_info_get_name(rawmidi_info),
|
||||
desc->strLen - strlen(desc->description));
|
||||
TRACE2("Returning %s, %s\n", desc->name, desc->description);
|
||||
return FALSE; // do not continue iteration
|
||||
}
|
||||
desc->index--;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static int getMIDIDeviceDescriptionByIndex(snd_rawmidi_stream_t direction,
|
||||
ALSA_MIDIDeviceDescription* desc) {
|
||||
initAlsaSupport();
|
||||
TRACE1(" getMIDIDeviceDescriptionByIndex (index = %d)\n", desc->index);
|
||||
iterateRawmidiDevices(direction, &deviceInfoIterator, desc);
|
||||
return (desc->index == 0) ? MIDI_SUCCESS : MIDI_INVALID_DEVICEID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int initMIDIDeviceDescription(ALSA_MIDIDeviceDescription* desc, int index) {
|
||||
int ret = MIDI_SUCCESS;
|
||||
desc->index = index;
|
||||
desc->strLen = 200;
|
||||
desc->name = (char*) calloc(desc->strLen + 1, 1);
|
||||
desc->description = (char*) calloc(desc->strLen + 1, 1);
|
||||
if (! desc->name ||
|
||||
! desc->description) {
|
||||
ret = MIDI_OUT_OF_MEMORY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void freeMIDIDeviceDescription(ALSA_MIDIDeviceDescription* desc) {
|
||||
if (desc->name) {
|
||||
free(desc->name);
|
||||
}
|
||||
if (desc->description) {
|
||||
free(desc->description);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int getMidiDeviceName(snd_rawmidi_stream_t direction, int index, char *name,
|
||||
UINT32 nameLength) {
|
||||
ALSA_MIDIDeviceDescription desc;
|
||||
int ret;
|
||||
|
||||
TRACE1("getMidiDeviceName: nameLength: %d\n", (int) nameLength);
|
||||
ret = initMIDIDeviceDescription(&desc, index);
|
||||
if (ret == MIDI_SUCCESS) {
|
||||
TRACE0("getMidiDeviceName: initMIDIDeviceDescription() SUCCESS\n");
|
||||
ret = getMIDIDeviceDescriptionByIndex(direction, &desc);
|
||||
if (ret == MIDI_SUCCESS) {
|
||||
TRACE1("getMidiDeviceName: desc.name: %s\n", desc.name);
|
||||
strncpy(name, desc.name, nameLength - 1);
|
||||
name[nameLength - 1] = 0;
|
||||
}
|
||||
}
|
||||
freeMIDIDeviceDescription(&desc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int getMidiDeviceVendor(int index, char *name, UINT32 nameLength) {
|
||||
strncpy(name, ALSA_VENDOR, nameLength - 1);
|
||||
name[nameLength - 1] = 0;
|
||||
return MIDI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int getMidiDeviceDescription(snd_rawmidi_stream_t direction,
|
||||
int index, char *name, UINT32 nameLength) {
|
||||
ALSA_MIDIDeviceDescription desc;
|
||||
int ret;
|
||||
|
||||
ret = initMIDIDeviceDescription(&desc, index);
|
||||
if (ret == MIDI_SUCCESS) {
|
||||
ret = getMIDIDeviceDescriptionByIndex(direction, &desc);
|
||||
if (ret == MIDI_SUCCESS) {
|
||||
strncpy(name, desc.description, nameLength - 1);
|
||||
name[nameLength - 1] = 0;
|
||||
}
|
||||
}
|
||||
freeMIDIDeviceDescription(&desc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int getMidiDeviceVersion(int index, char *name, UINT32 nameLength) {
|
||||
getALSAVersion(name, nameLength);
|
||||
return MIDI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int getMidiDeviceID(snd_rawmidi_stream_t direction, int index,
|
||||
UINT32* deviceID) {
|
||||
ALSA_MIDIDeviceDescription desc;
|
||||
int ret;
|
||||
|
||||
ret = initMIDIDeviceDescription(&desc, index);
|
||||
if (ret == MIDI_SUCCESS) {
|
||||
ret = getMIDIDeviceDescriptionByIndex(direction, &desc);
|
||||
if (ret == MIDI_SUCCESS) {
|
||||
// TRACE1("getMidiDeviceName: desc.name: %s\n", desc.name);
|
||||
*deviceID = desc.deviceID;
|
||||
}
|
||||
}
|
||||
freeMIDIDeviceDescription(&desc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
direction has to be either SND_RAWMIDI_STREAM_INPUT or
|
||||
SND_RAWMIDI_STREAM_OUTPUT.
|
||||
Returns 0 on success. Otherwise, MIDI_OUT_OF_MEMORY, MIDI_INVALID_ARGUMENT
|
||||
or a negative ALSA error code is returned.
|
||||
*/
|
||||
INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex,
|
||||
MidiDeviceHandle** handle) {
|
||||
snd_rawmidi_t* native_handle;
|
||||
snd_midi_event_t* event_parser = NULL;
|
||||
int err;
|
||||
UINT32 deviceID = 0;
|
||||
char devicename[100];
|
||||
#ifdef ALSA_MIDI_USE_PLUGHW
|
||||
int usePlugHw = 1;
|
||||
#else
|
||||
int usePlugHw = 0;
|
||||
#endif
|
||||
|
||||
TRACE0("> openMidiDevice()\n");
|
||||
|
||||
(*handle) = (MidiDeviceHandle*) calloc(sizeof(MidiDeviceHandle), 1);
|
||||
if (!(*handle)) {
|
||||
ERROR0("ERROR: openDevice: out of memory\n");
|
||||
return MIDI_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// TODO: iterate to get dev ID from index
|
||||
err = getMidiDeviceID(direction, deviceIndex, &deviceID);
|
||||
TRACE1(" openMidiDevice(): deviceID: %d\n", (int) deviceID);
|
||||
getDeviceStringFromDeviceID(devicename, deviceID,
|
||||
usePlugHw, ALSA_RAWMIDI);
|
||||
TRACE1(" openMidiDevice(): deviceString: %s\n", devicename);
|
||||
|
||||
// finally open the device
|
||||
if (direction == SND_RAWMIDI_STREAM_INPUT) {
|
||||
err = snd_rawmidi_open(&native_handle, NULL, devicename,
|
||||
SND_RAWMIDI_NONBLOCK);
|
||||
} else if (direction == SND_RAWMIDI_STREAM_OUTPUT) {
|
||||
err = snd_rawmidi_open(NULL, &native_handle, devicename,
|
||||
SND_RAWMIDI_NONBLOCK);
|
||||
} else {
|
||||
ERROR0(" ERROR: openMidiDevice(): direction is neither SND_RAWMIDI_STREAM_INPUT nor SND_RAWMIDI_STREAM_OUTPUT\n");
|
||||
err = MIDI_INVALID_ARGUMENT;
|
||||
}
|
||||
if (err < 0) {
|
||||
ERROR1("< ERROR: openMidiDevice(): snd_rawmidi_open() returned %d\n", err);
|
||||
free(*handle);
|
||||
(*handle) = NULL;
|
||||
return err;
|
||||
}
|
||||
/* We opened with non-blocking behaviour to not get hung if the device
|
||||
is used by a different process. Writing, however, should
|
||||
be blocking. So we change it here. */
|
||||
if (direction == SND_RAWMIDI_STREAM_OUTPUT) {
|
||||
err = snd_rawmidi_nonblock(native_handle, 0);
|
||||
if (err < 0) {
|
||||
ERROR1(" ERROR: openMidiDevice(): snd_rawmidi_nonblock() returned %d\n", err);
|
||||
snd_rawmidi_close(native_handle);
|
||||
free(*handle);
|
||||
(*handle) = NULL;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (direction == SND_RAWMIDI_STREAM_INPUT) {
|
||||
err = snd_midi_event_new(EVENT_PARSER_BUFSIZE, &event_parser);
|
||||
if (err < 0) {
|
||||
ERROR1(" ERROR: openMidiDevice(): snd_midi_event_new() returned %d\n", err);
|
||||
snd_rawmidi_close(native_handle);
|
||||
free(*handle);
|
||||
(*handle) = NULL;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
(*handle)->deviceHandle = (void*) native_handle;
|
||||
(*handle)->startTime = getTimeInMicroseconds();
|
||||
(*handle)->platformData = event_parser;
|
||||
TRACE0("< openMidiDevice(): succeeded\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
INT32 closeMidiDevice(MidiDeviceHandle* handle) {
|
||||
int err;
|
||||
|
||||
TRACE0("> closeMidiDevice()\n");
|
||||
if (!handle) {
|
||||
ERROR0("< ERROR: closeMidiDevice(): handle is NULL\n");
|
||||
return MIDI_INVALID_HANDLE;
|
||||
}
|
||||
if (!handle->deviceHandle) {
|
||||
ERROR0("< ERROR: closeMidiDevice(): native handle is NULL\n");
|
||||
return MIDI_INVALID_HANDLE;
|
||||
}
|
||||
err = snd_rawmidi_close((snd_rawmidi_t*) handle->deviceHandle);
|
||||
TRACE1(" snd_rawmidi_close() returns %d\n", err);
|
||||
if (handle->platformData) {
|
||||
snd_midi_event_free((snd_midi_event_t*) handle->platformData);
|
||||
}
|
||||
free(handle);
|
||||
TRACE0("< closeMidiDevice: succeeded\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
INT64 getMidiTimestamp(MidiDeviceHandle* handle) {
|
||||
if (!handle) {
|
||||
ERROR0("< ERROR: closeMidiDevice(): handle is NULL\n");
|
||||
return MIDI_INVALID_HANDLE;
|
||||
}
|
||||
return getTimeInMicroseconds() - handle->startTime;
|
||||
}
|
||||
|
||||
|
||||
/* end */
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "Utilities.h"
|
||||
#include "PlatformMidi.h"
|
||||
|
||||
|
||||
#ifndef PLATFORM_API_BSDOS_ALSA_MIDIUTILS_H_INCLUDED
|
||||
#define PLATFORM_API_BSDOS_ALSA_MIDIUTILS_H_INCLUDED
|
||||
|
||||
#define EVENT_PARSER_BUFSIZE (2048)
|
||||
|
||||
// if this is defined, use plughw: devices
|
||||
//#define ALSA_MIDI_USE_PLUGHW
|
||||
#undef ALSA_MIDI_USE_PLUGHW
|
||||
|
||||
typedef struct tag_ALSA_MIDIDeviceDescription {
|
||||
int index; // in
|
||||
int strLen; // in
|
||||
INT32 deviceID; // out
|
||||
char* name; // out
|
||||
char* description; // out
|
||||
} ALSA_MIDIDeviceDescription;
|
||||
|
||||
|
||||
const char* getErrorStr(INT32 err);
|
||||
|
||||
/* Returns the number of devices. */
|
||||
/* direction is either SND_RAWMIDI_STREAM_OUTPUT or
|
||||
SND_RAWMIDI_STREAM_INPUT. */
|
||||
int getMidiDeviceCount(snd_rawmidi_stream_t direction);
|
||||
|
||||
/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */
|
||||
/* direction is either SND_RAWMIDI_STREAM_OUTPUT or
|
||||
SND_RAWMIDI_STREAM_INPUT. */
|
||||
int getMidiDeviceName(snd_rawmidi_stream_t direction, int index,
|
||||
char *name, UINT32 nameLength);
|
||||
|
||||
/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */
|
||||
int getMidiDeviceVendor(int index, char *name, UINT32 nameLength);
|
||||
|
||||
/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */
|
||||
/* direction is either SND_RAWMIDI_STREAM_OUTPUT or
|
||||
SND_RAWMIDI_STREAM_INPUT. */
|
||||
int getMidiDeviceDescription(snd_rawmidi_stream_t direction, int index,
|
||||
char *name, UINT32 nameLength);
|
||||
|
||||
/* Returns MIDI_SUCCESS or MIDI_INVALID_DEVICEID */
|
||||
int getMidiDeviceVersion(int index, char *name, UINT32 nameLength);
|
||||
|
||||
// returns 0 on success, otherwise MIDI_OUT_OF_MEMORY or ALSA error code
|
||||
/* direction is either SND_RAWMIDI_STREAM_OUTPUT or
|
||||
SND_RAWMIDI_STREAM_INPUT. */
|
||||
INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex,
|
||||
MidiDeviceHandle** handle);
|
||||
|
||||
// returns 0 on success, otherwise a (negative) ALSA error code
|
||||
INT32 closeMidiDevice(MidiDeviceHandle* handle);
|
||||
|
||||
INT64 getMidiTimestamp(MidiDeviceHandle* handle);
|
||||
|
||||
#endif // PLATFORM_API_BSDOS_ALSA_MIDIUTILS_H_INCLUDED
|
@ -1,941 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#define USE_ERROR
|
||||
#define USE_TRACE
|
||||
|
||||
#include "PLATFORM_API_BsdOS_ALSA_PCMUtils.h"
|
||||
#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
|
||||
#include "DirectAudio.h"
|
||||
|
||||
#if USE_DAUDIO == TRUE
|
||||
|
||||
// GetPosition method 1: based on how many bytes are passed to the kernel driver
|
||||
// + does not need much processor resources
|
||||
// - not very exact, "jumps"
|
||||
// GetPosition method 2: ask kernel about actual position of playback.
|
||||
// - very exact
|
||||
// - switch to kernel layer for each call
|
||||
// GetPosition method 3: use snd_pcm_avail() call - not yet in official ALSA
|
||||
// quick tests on a Pentium 200MMX showed max. 1.5% processor usage
|
||||
// for playing back a CD-quality file and printing 20x per second a line
|
||||
// on the console with the current time. So I guess performance is not such a
|
||||
// factor here.
|
||||
//#define GET_POSITION_METHOD1
|
||||
#define GET_POSITION_METHOD2
|
||||
|
||||
|
||||
// The default time for a period in microseconds.
|
||||
// For very small buffers, only 2 periods are used.
|
||||
#define DEFAULT_PERIOD_TIME 20000 /* 20ms */
|
||||
|
||||
///// implemented functions of DirectAudio.h
|
||||
|
||||
INT32 DAUDIO_GetDirectAudioDeviceCount() {
|
||||
return (INT32) getAudioDeviceCount();
|
||||
}
|
||||
|
||||
|
||||
INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* description) {
|
||||
ALSA_AudioDeviceDescription adesc;
|
||||
|
||||
adesc.index = (int) mixerIndex;
|
||||
adesc.strLen = DAUDIO_STRING_LENGTH;
|
||||
|
||||
adesc.maxSimultaneousLines = (int*) (&(description->maxSimulLines));
|
||||
adesc.deviceID = &(description->deviceID);
|
||||
adesc.name = description->name;
|
||||
adesc.vendor = description->vendor;
|
||||
adesc.description = description->description;
|
||||
adesc.version = description->version;
|
||||
|
||||
return getAudioDeviceDescriptionByIndex(&adesc);
|
||||
}
|
||||
|
||||
#define MAX_BIT_INDEX 6
|
||||
// returns
|
||||
// 6: for anything above 24-bit
|
||||
// 5: for 4 bytes sample size, 24-bit
|
||||
// 4: for 3 bytes sample size, 24-bit
|
||||
// 3: for 3 bytes sample size, 20-bit
|
||||
// 2: for 2 bytes sample size, 16-bit
|
||||
// 1: for 1 byte sample size, 8-bit
|
||||
// 0: for anything else
|
||||
int getBitIndex(int sampleSizeInBytes, int significantBits) {
|
||||
if (significantBits > 24) return 6;
|
||||
if (sampleSizeInBytes == 4 && significantBits == 24) return 5;
|
||||
if (sampleSizeInBytes == 3) {
|
||||
if (significantBits == 24) return 4;
|
||||
if (significantBits == 20) return 3;
|
||||
}
|
||||
if (sampleSizeInBytes == 2 && significantBits == 16) return 2;
|
||||
if (sampleSizeInBytes == 1 && significantBits == 8) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getSampleSizeInBytes(int bitIndex, int sampleSizeInBytes) {
|
||||
switch(bitIndex) {
|
||||
case 1: return 1;
|
||||
case 2: return 2;
|
||||
case 3: /* fall through */
|
||||
case 4: return 3;
|
||||
case 5: return 4;
|
||||
}
|
||||
return sampleSizeInBytes;
|
||||
}
|
||||
|
||||
int getSignificantBits(int bitIndex, int significantBits) {
|
||||
switch(bitIndex) {
|
||||
case 1: return 8;
|
||||
case 2: return 16;
|
||||
case 3: return 20;
|
||||
case 4: /* fall through */
|
||||
case 5: return 24;
|
||||
}
|
||||
return significantBits;
|
||||
}
|
||||
|
||||
void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
|
||||
snd_pcm_t* handle;
|
||||
snd_pcm_format_mask_t* formatMask;
|
||||
snd_pcm_format_t format;
|
||||
snd_pcm_hw_params_t* hwParams;
|
||||
int handledBits[MAX_BIT_INDEX+1];
|
||||
|
||||
int ret;
|
||||
int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc;
|
||||
int origSampleSizeInBytes, origSignificantBits;
|
||||
unsigned int channels, minChannels, maxChannels;
|
||||
int rate, bitIndex;
|
||||
|
||||
for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE;
|
||||
if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) {
|
||||
return;
|
||||
}
|
||||
ret = snd_pcm_format_mask_malloc(&formatMask);
|
||||
if (ret != 0) {
|
||||
ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret);
|
||||
} else {
|
||||
ret = snd_pcm_hw_params_malloc(&hwParams);
|
||||
if (ret != 0) {
|
||||
ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
|
||||
} else {
|
||||
ret = snd_pcm_hw_params_any(handle, hwParams);
|
||||
/* snd_pcm_hw_params_any can return a positive value on success too */
|
||||
if (ret < 0) {
|
||||
ERROR1("snd_pcm_hw_params_any returned error %d\n", ret);
|
||||
} else {
|
||||
/* for the logic following this code, set ret to 0 to indicate success */
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
snd_pcm_hw_params_get_format_mask(hwParams, formatMask);
|
||||
if (ret == 0) {
|
||||
ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels);
|
||||
if (ret != 0) {
|
||||
ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret);
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels);
|
||||
if (ret != 0) {
|
||||
ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
// since we queried the hw: device, for many soundcards, it will only
|
||||
// report the maximum number of channels (which is the only way to talk
|
||||
// to the hw: device). Since we will, however, open the plughw: device
|
||||
// when opening the Source/TargetDataLine, we can safely assume that
|
||||
// also the channels 1..maxChannels are available.
|
||||
#ifdef ALSA_PCM_USE_PLUGHW
|
||||
minChannels = 1;
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
// plughw: supports any sample rate
|
||||
rate = -1;
|
||||
for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
|
||||
if (snd_pcm_format_mask_test(formatMask, format)) {
|
||||
// format exists
|
||||
if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes,
|
||||
&origSignificantBits,
|
||||
&isSigned, &isBigEndian, &enc)) {
|
||||
// now if we use plughw:, we can use any bit size below the
|
||||
// natively supported ones. Some ALSA drivers only support the maximum
|
||||
// bit size, so we add any sample rates below the reported one.
|
||||
// E.g. this iteration reports support for 16-bit.
|
||||
// getBitIndex will return 2, so it will add entries for
|
||||
// 16-bit (bitIndex=2) and in the next do-while loop iteration,
|
||||
// it will decrease bitIndex and will therefore add 8-bit support.
|
||||
bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits);
|
||||
do {
|
||||
if (bitIndex == 0
|
||||
|| bitIndex == MAX_BIT_INDEX
|
||||
|| !handledBits[bitIndex]) {
|
||||
handledBits[bitIndex] = TRUE;
|
||||
sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes);
|
||||
significantBits = getSignificantBits(bitIndex, origSignificantBits);
|
||||
if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) {
|
||||
// avoid too many channels explicitly listed
|
||||
// just add -1, min, and max
|
||||
DAUDIO_AddAudioFormat(creator, significantBits,
|
||||
-1, -1, rate,
|
||||
enc, isSigned, isBigEndian);
|
||||
DAUDIO_AddAudioFormat(creator, significantBits,
|
||||
sampleSizeInBytes * minChannels,
|
||||
minChannels, rate,
|
||||
enc, isSigned, isBigEndian);
|
||||
DAUDIO_AddAudioFormat(creator, significantBits,
|
||||
sampleSizeInBytes * maxChannels,
|
||||
maxChannels, rate,
|
||||
enc, isSigned, isBigEndian);
|
||||
} else {
|
||||
for (channels = minChannels; channels <= maxChannels; channels++) {
|
||||
DAUDIO_AddAudioFormat(creator, significantBits,
|
||||
sampleSizeInBytes * channels,
|
||||
channels, rate,
|
||||
enc, isSigned, isBigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef ALSA_PCM_USE_PLUGHW
|
||||
// without plugin, do not add fake formats
|
||||
break;
|
||||
#endif
|
||||
} while (--bitIndex > 0);
|
||||
} else {
|
||||
TRACE1("could not get format from alsa for format %d\n", format);
|
||||
}
|
||||
} else {
|
||||
//TRACE1("Format %d not supported\n", format);
|
||||
}
|
||||
} // for loop
|
||||
snd_pcm_hw_params_free(hwParams);
|
||||
}
|
||||
snd_pcm_format_mask_free(formatMask);
|
||||
}
|
||||
snd_pcm_close(handle);
|
||||
}
|
||||
|
||||
/** Workaround for cr 7033899, 7030629:
|
||||
* dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty
|
||||
* (just opened, underruned or already flushed).
|
||||
* Sometimes it causes PCM falls to -EBADFD error,
|
||||
* sometimes causes bufferSize change.
|
||||
* To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used.
|
||||
*/
|
||||
/* ******* ALSA PCM INFO ******************** */
|
||||
typedef struct tag_AlsaPcmInfo {
|
||||
snd_pcm_t* handle;
|
||||
snd_pcm_hw_params_t* hwParams;
|
||||
snd_pcm_sw_params_t* swParams;
|
||||
int bufferSizeInBytes;
|
||||
int frameSize; // storage size in Bytes
|
||||
unsigned int periods;
|
||||
snd_pcm_uframes_t periodSize;
|
||||
short int isRunning; // see comment above
|
||||
short int isFlushed; // see comment above
|
||||
#ifdef GET_POSITION_METHOD2
|
||||
// to be used exclusively by getBytePosition!
|
||||
snd_pcm_status_t* positionStatus;
|
||||
#endif
|
||||
} AlsaPcmInfo;
|
||||
|
||||
|
||||
int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) {
|
||||
int ret;
|
||||
int threshold;
|
||||
|
||||
if (useThreshold) {
|
||||
// start device whenever anything is written to the buffer
|
||||
threshold = 1;
|
||||
} else {
|
||||
// never start the device automatically
|
||||
threshold = 2000000000; /* near UINT_MAX */
|
||||
}
|
||||
ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold);
|
||||
if (ret < 0) {
|
||||
ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int setStartThreshold(AlsaPcmInfo* info, int useThreshold) {
|
||||
int ret = 0;
|
||||
|
||||
if (!setStartThresholdNoCommit(info, useThreshold)) {
|
||||
ret = -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
// commit it
|
||||
ret = snd_pcm_sw_params(info->handle, info->swParams);
|
||||
if (ret < 0) {
|
||||
ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
|
||||
}
|
||||
}
|
||||
return (ret == 0)?TRUE:FALSE;
|
||||
}
|
||||
|
||||
|
||||
// returns TRUE if successful
|
||||
int setHWParams(AlsaPcmInfo* info,
|
||||
float sampleRate,
|
||||
int channels,
|
||||
int bufferSizeInFrames,
|
||||
snd_pcm_format_t format) {
|
||||
unsigned int rrate, periodTime, periods;
|
||||
int ret, dir;
|
||||
snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames;
|
||||
|
||||
/* choose all parameters */
|
||||
ret = snd_pcm_hw_params_any(info->handle, info->hwParams);
|
||||
if (ret < 0) {
|
||||
ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
/* set the interleaved read/write format */
|
||||
ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if (ret < 0) {
|
||||
ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
/* set the sample format */
|
||||
ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format);
|
||||
if (ret < 0) {
|
||||
ERROR1("Sample format not available: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
/* set the count of channels */
|
||||
ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels);
|
||||
if (ret < 0) {
|
||||
ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
/* set the stream rate */
|
||||
rrate = (int) (sampleRate + 0.5f);
|
||||
dir = 0;
|
||||
ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir);
|
||||
if (ret < 0) {
|
||||
ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) {
|
||||
ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate);
|
||||
return FALSE;
|
||||
}
|
||||
/* set the buffer time */
|
||||
ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames);
|
||||
if (ret < 0) {
|
||||
ERROR2("Unable to set buffer size to %d frames: %s\n",
|
||||
(int) alsaBufferSizeInFrames, snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
bufferSizeInFrames = (int) alsaBufferSizeInFrames;
|
||||
/* set the period time */
|
||||
if (bufferSizeInFrames > 1024) {
|
||||
dir = 0;
|
||||
periodTime = DEFAULT_PERIOD_TIME;
|
||||
ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir);
|
||||
if (ret < 0) {
|
||||
ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
/* set the period count for very small buffer sizes to 2 */
|
||||
dir = 0;
|
||||
periods = 2;
|
||||
ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir);
|
||||
if (ret < 0) {
|
||||
ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
/* write the parameters to device */
|
||||
ret = snd_pcm_hw_params(info->handle, info->hwParams);
|
||||
if (ret < 0) {
|
||||
ERROR1("Unable to set hw params: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// returns 1 if successful
|
||||
int setSWParams(AlsaPcmInfo* info) {
|
||||
int ret;
|
||||
|
||||
/* get the current swparams */
|
||||
ret = snd_pcm_sw_params_current(info->handle, info->swParams);
|
||||
if (ret < 0) {
|
||||
ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
/* never start the transfer automatically */
|
||||
if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* allow the transfer when at least period_size samples can be processed */
|
||||
ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize);
|
||||
if (ret < 0) {
|
||||
ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
/* write the parameters to the playback device */
|
||||
ret = snd_pcm_sw_params(info->handle, info->swParams);
|
||||
if (ret < 0) {
|
||||
ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static snd_output_t* ALSA_OUTPUT = NULL;
|
||||
|
||||
void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
|
||||
int encoding, float sampleRate, int sampleSizeInBits,
|
||||
int frameSize, int channels,
|
||||
int isSigned, int isBigEndian, int bufferSizeInBytes) {
|
||||
snd_pcm_format_mask_t* formatMask;
|
||||
snd_pcm_format_t format;
|
||||
int dir;
|
||||
int ret = 0;
|
||||
AlsaPcmInfo* info = NULL;
|
||||
/* snd_pcm_uframes_t is 64 bit on 64-bit systems */
|
||||
snd_pcm_uframes_t alsaBufferSizeInFrames = 0;
|
||||
|
||||
|
||||
TRACE0("> DAUDIO_Open\n");
|
||||
#ifdef USE_TRACE
|
||||
// for using ALSA debug dump methods
|
||||
if (ALSA_OUTPUT == NULL) {
|
||||
snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0);
|
||||
}
|
||||
#endif
|
||||
if (channels <= 0) {
|
||||
ERROR1("ERROR: Invalid number of channels=%d!\n", channels);
|
||||
return NULL;
|
||||
}
|
||||
info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo));
|
||||
if (!info) {
|
||||
ERROR0("Out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(info, 0, sizeof(AlsaPcmInfo));
|
||||
// initial values are: stopped, flushed
|
||||
info->isRunning = 0;
|
||||
info->isFlushed = 1;
|
||||
|
||||
ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/);
|
||||
if (ret == 0) {
|
||||
// set to blocking mode
|
||||
snd_pcm_nonblock(info->handle, 0);
|
||||
ret = snd_pcm_hw_params_malloc(&(info->hwParams));
|
||||
if (ret != 0) {
|
||||
ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret);
|
||||
} else {
|
||||
ret = -1;
|
||||
if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits,
|
||||
isSigned, isBigEndian, encoding)) {
|
||||
if (setHWParams(info,
|
||||
sampleRate,
|
||||
channels,
|
||||
bufferSizeInBytes / frameSize,
|
||||
format)) {
|
||||
info->frameSize = frameSize;
|
||||
ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir);
|
||||
if (ret < 0) {
|
||||
ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret));
|
||||
}
|
||||
snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir);
|
||||
snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames);
|
||||
info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize;
|
||||
TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n",
|
||||
(int) info->periodSize, info->periods, info->bufferSizeInBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
// set software parameters
|
||||
ret = snd_pcm_sw_params_malloc(&(info->swParams));
|
||||
if (ret != 0) {
|
||||
ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
|
||||
} else {
|
||||
if (!setSWParams(info)) {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
// prepare device
|
||||
ret = snd_pcm_prepare(info->handle);
|
||||
if (ret < 0) {
|
||||
ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GET_POSITION_METHOD2
|
||||
if (ret == 0) {
|
||||
ret = snd_pcm_status_malloc(&(info->positionStatus));
|
||||
if (ret != 0) {
|
||||
ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (ret != 0) {
|
||||
DAUDIO_Close((void*) info, isSource);
|
||||
info = NULL;
|
||||
} else {
|
||||
// set to non-blocking mode
|
||||
snd_pcm_nonblock(info->handle, 1);
|
||||
TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n",
|
||||
(void*) info->handle);
|
||||
}
|
||||
return (void*) info;
|
||||
}
|
||||
|
||||
#ifdef USE_TRACE
|
||||
void printState(snd_pcm_state_t state) {
|
||||
if (state == SND_PCM_STATE_OPEN) {
|
||||
TRACE0("State: SND_PCM_STATE_OPEN\n");
|
||||
}
|
||||
else if (state == SND_PCM_STATE_SETUP) {
|
||||
TRACE0("State: SND_PCM_STATE_SETUP\n");
|
||||
}
|
||||
else if (state == SND_PCM_STATE_PREPARED) {
|
||||
TRACE0("State: SND_PCM_STATE_PREPARED\n");
|
||||
}
|
||||
else if (state == SND_PCM_STATE_RUNNING) {
|
||||
TRACE0("State: SND_PCM_STATE_RUNNING\n");
|
||||
}
|
||||
else if (state == SND_PCM_STATE_XRUN) {
|
||||
TRACE0("State: SND_PCM_STATE_XRUN\n");
|
||||
}
|
||||
else if (state == SND_PCM_STATE_DRAINING) {
|
||||
TRACE0("State: SND_PCM_STATE_DRAINING\n");
|
||||
}
|
||||
else if (state == SND_PCM_STATE_PAUSED) {
|
||||
TRACE0("State: SND_PCM_STATE_PAUSED\n");
|
||||
}
|
||||
else if (state == SND_PCM_STATE_SUSPENDED) {
|
||||
TRACE0("State: SND_PCM_STATE_SUSPENDED\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int DAUDIO_Start(void* id, int isSource) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
int ret;
|
||||
snd_pcm_state_t state;
|
||||
|
||||
TRACE0("> DAUDIO_Start\n");
|
||||
// set to blocking mode
|
||||
snd_pcm_nonblock(info->handle, 0);
|
||||
// set start mode so that it always starts as soon as data is there
|
||||
setStartThreshold(info, TRUE /* use threshold */);
|
||||
state = snd_pcm_state(info->handle);
|
||||
if (state == SND_PCM_STATE_PAUSED) {
|
||||
// in case it was stopped previously
|
||||
TRACE0(" Un-pausing...\n");
|
||||
ret = snd_pcm_pause(info->handle, FALSE);
|
||||
if (ret != 0) {
|
||||
ERROR2(" NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret));
|
||||
}
|
||||
}
|
||||
if (state == SND_PCM_STATE_SUSPENDED) {
|
||||
TRACE0(" Resuming...\n");
|
||||
ret = snd_pcm_resume(info->handle);
|
||||
if (ret < 0) {
|
||||
if ((ret != -EAGAIN) && (ret != -ENOSYS)) {
|
||||
ERROR2(" ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state == SND_PCM_STATE_SETUP) {
|
||||
TRACE0("need to call prepare again...\n");
|
||||
// prepare device
|
||||
ret = snd_pcm_prepare(info->handle);
|
||||
if (ret < 0) {
|
||||
ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
|
||||
}
|
||||
}
|
||||
// in case there is still data in the buffers
|
||||
ret = snd_pcm_start(info->handle);
|
||||
if (ret != 0) {
|
||||
if (ret != -EPIPE) {
|
||||
ERROR2(" NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret));
|
||||
}
|
||||
}
|
||||
// set to non-blocking mode
|
||||
ret = snd_pcm_nonblock(info->handle, 1);
|
||||
if (ret != 0) {
|
||||
ERROR1(" ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret));
|
||||
}
|
||||
state = snd_pcm_state(info->handle);
|
||||
#ifdef USE_TRACE
|
||||
printState(state);
|
||||
#endif
|
||||
ret = (state == SND_PCM_STATE_PREPARED)
|
||||
|| (state == SND_PCM_STATE_RUNNING)
|
||||
|| (state == SND_PCM_STATE_XRUN)
|
||||
|| (state == SND_PCM_STATE_SUSPENDED);
|
||||
if (ret) {
|
||||
info->isRunning = 1;
|
||||
// source line should keep isFlushed value until Write() is called;
|
||||
// for target data line reset it right now.
|
||||
if (!isSource) {
|
||||
info->isFlushed = 0;
|
||||
}
|
||||
}
|
||||
TRACE1("< DAUDIO_Start %s\n", ret?"success":"error");
|
||||
return ret?TRUE:FALSE;
|
||||
}
|
||||
|
||||
int DAUDIO_Stop(void* id, int isSource) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
int ret;
|
||||
|
||||
TRACE0("> DAUDIO_Stop\n");
|
||||
// set to blocking mode
|
||||
snd_pcm_nonblock(info->handle, 0);
|
||||
setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun
|
||||
ret = snd_pcm_pause(info->handle, 1);
|
||||
// set to non-blocking mode
|
||||
snd_pcm_nonblock(info->handle, 1);
|
||||
if (ret != 0) {
|
||||
ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
info->isRunning = 0;
|
||||
TRACE0("< DAUDIO_Stop success\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void DAUDIO_Close(void* id, int isSource) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
|
||||
TRACE0("DAUDIO_Close\n");
|
||||
if (info != NULL) {
|
||||
if (info->handle != NULL) {
|
||||
snd_pcm_close(info->handle);
|
||||
}
|
||||
if (info->hwParams) {
|
||||
snd_pcm_hw_params_free(info->hwParams);
|
||||
}
|
||||
if (info->swParams) {
|
||||
snd_pcm_sw_params_free(info->swParams);
|
||||
}
|
||||
#ifdef GET_POSITION_METHOD2
|
||||
if (info->positionStatus) {
|
||||
snd_pcm_status_free(info->positionStatus);
|
||||
}
|
||||
#endif
|
||||
free(info);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Underrun and suspend recovery
|
||||
* returns
|
||||
* 0: exit native and return 0
|
||||
* 1: try again to write/read
|
||||
* -1: error - exit native with return value -1
|
||||
*/
|
||||
int xrun_recovery(AlsaPcmInfo* info, int err) {
|
||||
int ret;
|
||||
|
||||
if (err == -EPIPE) { /* underrun / overflow */
|
||||
TRACE0("xrun_recovery: underrun/overflow.\n");
|
||||
ret = snd_pcm_prepare(info->handle);
|
||||
if (ret < 0) {
|
||||
ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
} else if (err == -ESTRPIPE) {
|
||||
TRACE0("xrun_recovery: suspended.\n");
|
||||
ret = snd_pcm_resume(info->handle);
|
||||
if (ret < 0) {
|
||||
if (ret == -EAGAIN) {
|
||||
return 0; /* wait until the suspend flag is released */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
ret = snd_pcm_prepare(info->handle);
|
||||
if (ret < 0) {
|
||||
ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
} else if (err == -EAGAIN) {
|
||||
TRACE0("xrun_recovery: EAGAIN try again flag.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// returns -1 on error
|
||||
int DAUDIO_Write(void* id, char* data, int byteSize) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
int ret, count;
|
||||
snd_pcm_sframes_t frameSize, writtenFrames;
|
||||
|
||||
TRACE1("> DAUDIO_Write %d bytes\n", byteSize);
|
||||
|
||||
/* sanity */
|
||||
if (byteSize <= 0 || info->frameSize <= 0) {
|
||||
ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n",
|
||||
(int) byteSize, (int) info->frameSize);
|
||||
TRACE0("< DAUDIO_Write returning -1\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = 2; // maximum number of trials to recover from underrun
|
||||
//frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
|
||||
frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
|
||||
do {
|
||||
writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize);
|
||||
|
||||
if (writtenFrames < 0) {
|
||||
ret = xrun_recovery(info, (int) writtenFrames);
|
||||
if (ret <= 0) {
|
||||
TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (count-- <= 0) {
|
||||
ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (TRUE);
|
||||
//ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames);
|
||||
|
||||
if (writtenFrames > 0) {
|
||||
// reset "flushed" flag
|
||||
info->isFlushed = 0;
|
||||
}
|
||||
|
||||
ret = (int) (writtenFrames * info->frameSize);
|
||||
TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// returns -1 on error
|
||||
int DAUDIO_Read(void* id, char* data, int byteSize) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
int ret, count;
|
||||
snd_pcm_sframes_t frameSize, readFrames;
|
||||
|
||||
TRACE1("> DAUDIO_Read %d bytes\n", byteSize);
|
||||
/*TRACE3(" info=%p, data=%p, byteSize=%d\n",
|
||||
(void*) info, (void*) data, (int) byteSize);
|
||||
TRACE2(" info->frameSize=%d, info->handle=%p\n",
|
||||
(int) info->frameSize, (void*) info->handle);
|
||||
*/
|
||||
/* sanity */
|
||||
if (byteSize <= 0 || info->frameSize <= 0) {
|
||||
ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n",
|
||||
(int) byteSize, (int) info->frameSize);
|
||||
TRACE0("< DAUDIO_Read returning -1\n");
|
||||
return -1;
|
||||
}
|
||||
if (!info->isRunning && info->isFlushed) {
|
||||
// PCM has nothing to read
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = 2; // maximum number of trials to recover from error
|
||||
//frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
|
||||
frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
|
||||
do {
|
||||
readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize);
|
||||
if (readFrames < 0) {
|
||||
ret = xrun_recovery(info, (int) readFrames);
|
||||
if (ret <= 0) {
|
||||
TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (count-- <= 0) {
|
||||
ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (TRUE);
|
||||
//ret = snd_pcm_frames_to_bytes(info->handle, readFrames);
|
||||
ret = (int) (readFrames * info->frameSize);
|
||||
TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int DAUDIO_GetBufferSize(void* id, int isSource) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
|
||||
return info->bufferSizeInBytes;
|
||||
}
|
||||
|
||||
int DAUDIO_StillDraining(void* id, int isSource) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
snd_pcm_state_t state;
|
||||
|
||||
state = snd_pcm_state(info->handle);
|
||||
//printState(state);
|
||||
//TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE");
|
||||
return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE;
|
||||
}
|
||||
|
||||
|
||||
int DAUDIO_Flush(void* id, int isSource) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
int ret;
|
||||
|
||||
TRACE0("DAUDIO_Flush\n");
|
||||
|
||||
if (info->isFlushed) {
|
||||
// nothing to drop
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = snd_pcm_drop(info->handle);
|
||||
if (ret != 0) {
|
||||
ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info->isFlushed = 1;
|
||||
if (info->isRunning) {
|
||||
ret = DAUDIO_Start(id, isSource);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DAUDIO_GetAvailable(void* id, int isSource) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
snd_pcm_sframes_t availableInFrames;
|
||||
snd_pcm_state_t state;
|
||||
int ret;
|
||||
|
||||
state = snd_pcm_state(info->handle);
|
||||
if (info->isFlushed || state == SND_PCM_STATE_XRUN) {
|
||||
// if in xrun state then we have the entire buffer available,
|
||||
// not 0 as alsa reports
|
||||
ret = info->bufferSizeInBytes;
|
||||
} else {
|
||||
availableInFrames = snd_pcm_avail_update(info->handle);
|
||||
if (availableInFrames < 0) {
|
||||
ret = 0;
|
||||
} else {
|
||||
//ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames);
|
||||
ret = (int) (availableInFrames * info->frameSize);
|
||||
}
|
||||
}
|
||||
TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INT64 estimatePositionFromAvail(AlsaPcmInfo* info, int isSource, INT64 javaBytePos, int availInBytes) {
|
||||
// estimate the current position with the buffer size and
|
||||
// the available bytes to read or write in the buffer.
|
||||
// not an elegant solution - bytePos will stop on xruns,
|
||||
// and in race conditions it may jump backwards
|
||||
// Advantage is that it is indeed based on the samples that go through
|
||||
// the system (rather than time-based methods)
|
||||
if (isSource) {
|
||||
// javaBytePos is the position that is reached when the current
|
||||
// buffer is played completely
|
||||
return (INT64) (javaBytePos - info->bufferSizeInBytes + availInBytes);
|
||||
} else {
|
||||
// javaBytePos is the position that was when the current buffer was empty
|
||||
return (INT64) (javaBytePos + availInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) {
|
||||
AlsaPcmInfo* info = (AlsaPcmInfo*) id;
|
||||
int ret;
|
||||
INT64 result = javaBytePos;
|
||||
snd_pcm_state_t state;
|
||||
state = snd_pcm_state(info->handle);
|
||||
|
||||
if (!info->isFlushed && state != SND_PCM_STATE_XRUN) {
|
||||
#ifdef GET_POSITION_METHOD2
|
||||
snd_timestamp_t* ts;
|
||||
snd_pcm_uframes_t framesAvail;
|
||||
|
||||
// note: slight race condition if this is called simultaneously from 2 threads
|
||||
ret = snd_pcm_status(info->handle, info->positionStatus);
|
||||
if (ret != 0) {
|
||||
ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret));
|
||||
result = javaBytePos;
|
||||
} else {
|
||||
// calculate from time value, or from available bytes
|
||||
framesAvail = snd_pcm_status_get_avail(info->positionStatus);
|
||||
result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize);
|
||||
}
|
||||
#endif
|
||||
#ifdef GET_POSITION_METHOD3
|
||||
snd_pcm_uframes_t framesAvail;
|
||||
ret = snd_pcm_avail(info->handle, &framesAvail);
|
||||
if (ret != 0) {
|
||||
ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret));
|
||||
result = javaBytePos;
|
||||
} else {
|
||||
result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize);
|
||||
}
|
||||
#endif
|
||||
#ifdef GET_POSITION_METHOD1
|
||||
result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource));
|
||||
#endif
|
||||
}
|
||||
//printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
|
||||
/* save to ignore, since GetBytePosition
|
||||
* takes the javaBytePos param into account
|
||||
*/
|
||||
}
|
||||
|
||||
int DAUDIO_RequiresServicing(void* id, int isSource) {
|
||||
// never need servicing on Bsd
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void DAUDIO_Service(void* id, int isSource) {
|
||||
// never need servicing on Bsd
|
||||
}
|
||||
|
||||
|
||||
#endif // USE_DAUDIO
|
@ -1,292 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
//#define USE_ERROR
|
||||
//#define USE_TRACE
|
||||
|
||||
#include "PLATFORM_API_BsdOS_ALSA_PCMUtils.h"
|
||||
#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
|
||||
|
||||
|
||||
|
||||
// callback for iteration through devices
|
||||
// returns TRUE if iteration should continue
|
||||
// NOTE: cardinfo may be NULL (for "default" device)
|
||||
typedef int (*DeviceIteratorPtr)(UINT32 deviceID, snd_pcm_info_t* pcminfo,
|
||||
snd_ctl_card_info_t* cardinfo, void *userData);
|
||||
|
||||
// for each ALSA device, call iterator. userData is passed to the iterator
|
||||
// returns total number of iterations
|
||||
int iteratePCMDevices(DeviceIteratorPtr iterator, void* userData) {
|
||||
int count = 0;
|
||||
int subdeviceCount;
|
||||
int card, dev, subDev;
|
||||
char devname[16];
|
||||
int err;
|
||||
snd_ctl_t *handle;
|
||||
snd_pcm_t *pcm;
|
||||
snd_pcm_info_t* pcminfo;
|
||||
snd_ctl_card_info_t *cardinfo, *defcardinfo = NULL;
|
||||
UINT32 deviceID;
|
||||
int doContinue = TRUE;
|
||||
|
||||
snd_pcm_info_malloc(&pcminfo);
|
||||
snd_ctl_card_info_malloc(&cardinfo);
|
||||
|
||||
// 1st try "default" device
|
||||
err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME,
|
||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||
if (err < 0) {
|
||||
// try with the other direction
|
||||
err = snd_pcm_open(&pcm, ALSA_DEFAULT_DEVICE_NAME,
|
||||
SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
||||
}
|
||||
if (err < 0) {
|
||||
ERROR1("ERROR: snd_pcm_open (\"default\"): %s\n", snd_strerror(err));
|
||||
} else {
|
||||
err = snd_pcm_info(pcm, pcminfo);
|
||||
snd_pcm_close(pcm);
|
||||
if (err < 0) {
|
||||
ERROR1("ERROR: snd_pcm_info (\"default\"): %s\n",
|
||||
snd_strerror(err));
|
||||
} else {
|
||||
// try to get card info
|
||||
card = snd_pcm_info_get_card(pcminfo);
|
||||
if (card >= 0) {
|
||||
sprintf(devname, ALSA_HARDWARE_CARD, card);
|
||||
if (snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK) >= 0) {
|
||||
if (snd_ctl_card_info(handle, cardinfo) >= 0) {
|
||||
defcardinfo = cardinfo;
|
||||
}
|
||||
snd_ctl_close(handle);
|
||||
}
|
||||
}
|
||||
// call callback function for the device
|
||||
if (iterator != NULL) {
|
||||
doContinue = (*iterator)(ALSA_DEFAULT_DEVICE_ID, pcminfo,
|
||||
defcardinfo, userData);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// iterate cards
|
||||
card = -1;
|
||||
while (doContinue) {
|
||||
if (snd_card_next(&card) < 0) {
|
||||
break;
|
||||
}
|
||||
if (card < 0) {
|
||||
break;
|
||||
}
|
||||
sprintf(devname, ALSA_HARDWARE_CARD, card);
|
||||
TRACE1("Opening alsa device \"%s\"...\n", devname);
|
||||
err = snd_ctl_open(&handle, devname, SND_CTL_NONBLOCK);
|
||||
if (err < 0) {
|
||||
ERROR2("ERROR: snd_ctl_open, card=%d: %s\n",
|
||||
card, snd_strerror(err));
|
||||
} else {
|
||||
err = snd_ctl_card_info(handle, cardinfo);
|
||||
if (err < 0) {
|
||||
ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n",
|
||||
card, snd_strerror(err));
|
||||
} else {
|
||||
dev = -1;
|
||||
while (doContinue) {
|
||||
if (snd_ctl_pcm_next_device(handle, &dev) < 0) {
|
||||
ERROR0("snd_ctl_pcm_next_device\n");
|
||||
}
|
||||
if (dev < 0) {
|
||||
break;
|
||||
}
|
||||
snd_pcm_info_set_device(pcminfo, dev);
|
||||
snd_pcm_info_set_subdevice(pcminfo, 0);
|
||||
snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
|
||||
err = snd_ctl_pcm_info(handle, pcminfo);
|
||||
if (err == -ENOENT) {
|
||||
// try with the other direction
|
||||
snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
|
||||
err = snd_ctl_pcm_info(handle, pcminfo);
|
||||
}
|
||||
if (err < 0) {
|
||||
if (err != -ENOENT) {
|
||||
ERROR2("ERROR: snd_ctl_pcm_info, card=%d: %s",
|
||||
card, snd_strerror(err));
|
||||
}
|
||||
} else {
|
||||
subdeviceCount = needEnumerateSubdevices(ALSA_PCM) ?
|
||||
snd_pcm_info_get_subdevices_count(pcminfo) : 1;
|
||||
if (iterator!=NULL) {
|
||||
for (subDev = 0; subDev < subdeviceCount; subDev++) {
|
||||
deviceID = encodeDeviceID(card, dev, subDev);
|
||||
doContinue = (*iterator)(deviceID, pcminfo,
|
||||
cardinfo, userData);
|
||||
count++;
|
||||
if (!doContinue) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
count += subdeviceCount;
|
||||
}
|
||||
}
|
||||
} // of while(doContinue)
|
||||
}
|
||||
snd_ctl_close(handle);
|
||||
}
|
||||
}
|
||||
snd_ctl_card_info_free(cardinfo);
|
||||
snd_pcm_info_free(pcminfo);
|
||||
return count;
|
||||
}
|
||||
|
||||
int getAudioDeviceCount() {
|
||||
initAlsaSupport();
|
||||
return iteratePCMDevices(NULL, NULL);
|
||||
}
|
||||
|
||||
int deviceInfoIterator(UINT32 deviceID, snd_pcm_info_t* pcminfo,
|
||||
snd_ctl_card_info_t* cardinfo, void* userData) {
|
||||
char buffer[300];
|
||||
ALSA_AudioDeviceDescription* desc = (ALSA_AudioDeviceDescription*)userData;
|
||||
#ifdef ALSA_PCM_USE_PLUGHW
|
||||
int usePlugHw = 1;
|
||||
#else
|
||||
int usePlugHw = 0;
|
||||
#endif
|
||||
|
||||
initAlsaSupport();
|
||||
if (desc->index == 0) {
|
||||
// we found the device with correct index
|
||||
*(desc->maxSimultaneousLines) = needEnumerateSubdevices(ALSA_PCM) ?
|
||||
1 : snd_pcm_info_get_subdevices_count(pcminfo);
|
||||
*desc->deviceID = deviceID;
|
||||
buffer[0]=' '; buffer[1]='[';
|
||||
// buffer[300] is enough to store the actual device string w/o overrun
|
||||
getDeviceStringFromDeviceID(&buffer[2], deviceID, usePlugHw, ALSA_PCM);
|
||||
strncat(buffer, "]", sizeof(buffer) - strlen(buffer) - 1);
|
||||
strncpy(desc->name,
|
||||
(cardinfo != NULL)
|
||||
? snd_ctl_card_info_get_id(cardinfo)
|
||||
: snd_pcm_info_get_id(pcminfo),
|
||||
desc->strLen - strlen(buffer));
|
||||
strncat(desc->name, buffer, desc->strLen - strlen(desc->name));
|
||||
strncpy(desc->vendor, "ALSA (http://www.alsa-project.org)", desc->strLen);
|
||||
strncpy(desc->description,
|
||||
(cardinfo != NULL)
|
||||
? snd_ctl_card_info_get_name(cardinfo)
|
||||
: snd_pcm_info_get_name(pcminfo),
|
||||
desc->strLen);
|
||||
strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
|
||||
strncat(desc->description, snd_pcm_info_get_id(pcminfo), desc->strLen - strlen(desc->description));
|
||||
strncat(desc->description, ", ", desc->strLen - strlen(desc->description));
|
||||
strncat(desc->description, snd_pcm_info_get_name(pcminfo), desc->strLen - strlen(desc->description));
|
||||
getALSAVersion(desc->version, desc->strLen);
|
||||
TRACE4("Returning %s, %s, %s, %s\n", desc->name, desc->vendor, desc->description, desc->version);
|
||||
return FALSE; // do not continue iteration
|
||||
}
|
||||
desc->index--;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// returns 0 if successful
|
||||
int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware) {
|
||||
char buffer[200];
|
||||
int ret;
|
||||
|
||||
initAlsaSupport();
|
||||
getDeviceStringFromDeviceID(buffer, deviceID, !hardware, ALSA_PCM);
|
||||
|
||||
TRACE1("Opening ALSA device %s\n", buffer);
|
||||
ret = snd_pcm_open(handle, buffer,
|
||||
isSource?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE,
|
||||
SND_PCM_NONBLOCK);
|
||||
if (ret != 0) {
|
||||
ERROR1("snd_pcm_open returned error code %d \n", ret);
|
||||
*handle = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc) {
|
||||
initAlsaSupport();
|
||||
TRACE1(" getAudioDeviceDescriptionByIndex(mixerIndex = %d\n", desc->index);
|
||||
iteratePCMDevices(&deviceInfoIterator, desc);
|
||||
return (desc->index == 0)?TRUE:FALSE;
|
||||
}
|
||||
|
||||
// returns 1 if successful
|
||||
// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h)
|
||||
int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat,
|
||||
int* sampleSizeInBytes, int* significantBits,
|
||||
int* isSigned, int* isBigEndian, int* enc) {
|
||||
|
||||
*sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8;
|
||||
*significantBits = snd_pcm_format_width(alsaFormat);
|
||||
|
||||
// defaults
|
||||
*enc = 0; // PCM
|
||||
*isSigned = (snd_pcm_format_signed(alsaFormat) > 0);
|
||||
*isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0);
|
||||
|
||||
// non-PCM formats
|
||||
if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law
|
||||
*sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes;
|
||||
}
|
||||
else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law
|
||||
*sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes;
|
||||
}
|
||||
else if (snd_pcm_format_linear(alsaFormat) < 1) {
|
||||
return 0;
|
||||
}
|
||||
return (*sampleSizeInBytes > 0);
|
||||
}
|
||||
|
||||
// returns 1 if successful
|
||||
int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat,
|
||||
int sampleSizeInBytes, int significantBits,
|
||||
int isSigned, int isBigEndian, int enc) {
|
||||
*alsaFormat = SND_PCM_FORMAT_UNKNOWN;
|
||||
|
||||
if (enc == 0) {
|
||||
*alsaFormat = snd_pcm_build_linear_format(significantBits,
|
||||
sampleSizeInBytes * 8,
|
||||
isSigned?0:1,
|
||||
isBigEndian?1:0);
|
||||
}
|
||||
else if ((sampleSizeInBytes == 1) && (significantBits == 8)) {
|
||||
if (enc == 1) { // ULAW
|
||||
*alsaFormat = SND_PCM_FORMAT_MU_LAW;
|
||||
}
|
||||
else if (enc == 2) { // ALAW
|
||||
*alsaFormat = SND_PCM_FORMAT_A_LAW;
|
||||
}
|
||||
}
|
||||
return (*alsaFormat == SND_PCM_FORMAT_UNKNOWN)?0:1;
|
||||
}
|
||||
|
||||
|
||||
/* end */
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// define this with a later version of ALSA than 0.9.0rc3
|
||||
// (starting from 1.0.0 it became default behaviour)
|
||||
#define ALSA_PCM_NEW_HW_PARAMS_API
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "Utilities.h"
|
||||
|
||||
#ifndef PLATFORM_API_BSDOS_ALSA_PCMUTILS_H_INCLUDED
|
||||
#define PLATFORM_API_BSDOS_ALSA_PCMUTILS_H_INCLUDED
|
||||
|
||||
// if this is defined, use plughw: devices
|
||||
#define ALSA_PCM_USE_PLUGHW
|
||||
//#undef ALSA_PCM_USE_PLUGHW
|
||||
|
||||
|
||||
// maximum number of channels that is listed in the formats. If more, than
|
||||
// just -1 for channel count is used.
|
||||
#define MAXIMUM_LISTED_CHANNELS 32
|
||||
|
||||
typedef struct tag_ALSA_AudioDeviceDescription {
|
||||
int index; // in
|
||||
int strLen; // in
|
||||
INT32* deviceID; // out
|
||||
int* maxSimultaneousLines; // out
|
||||
char* name; // out
|
||||
char* vendor; // out
|
||||
char* description; // out
|
||||
char* version; // out
|
||||
} ALSA_AudioDeviceDescription;
|
||||
|
||||
|
||||
|
||||
int getAudioDeviceCount();
|
||||
int getAudioDeviceDescriptionByIndex(ALSA_AudioDeviceDescription* desc);
|
||||
|
||||
// returns ALSA error code, or 0 if successful
|
||||
int openPCMfromDeviceID(int deviceID, snd_pcm_t** handle, int isSource, int hardware);
|
||||
|
||||
// returns 1 if successful
|
||||
// enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h)
|
||||
int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat,
|
||||
int* sampleSizeInBytes, int* significantBits,
|
||||
int* isSigned, int* isBigEndian, int* enc);
|
||||
|
||||
int getAlsaFormatFromFormat(snd_pcm_format_t* alsaFormat,
|
||||
int sampleSizeInBytes, int significantBits,
|
||||
int isSigned, int isBigEndian, int enc);
|
||||
|
||||
#endif // PLATFORM_API_BSDOS_ALSA_PCMUTILS_H_INCLUDED
|
@ -1,724 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#define USE_ERROR
|
||||
//#define USE_TRACE
|
||||
|
||||
#include "Ports.h"
|
||||
#include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h"
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#if USE_PORTS == TRUE
|
||||
|
||||
#define MAX_ELEMS (300)
|
||||
#define MAX_CONTROLS (MAX_ELEMS * 4)
|
||||
|
||||
#define CHANNELS_MONO (SND_MIXER_SCHN_LAST + 1)
|
||||
#define CHANNELS_STEREO (SND_MIXER_SCHN_LAST + 2)
|
||||
|
||||
typedef struct {
|
||||
snd_mixer_elem_t* elem;
|
||||
INT32 portType; /* one of PORT_XXX_xx */
|
||||
char* controlType; /* one of CONTROL_TYPE_xx */
|
||||
/* Values: either SND_MIXER_SCHN_FRONT_xx, CHANNELS_MONO or CHANNELS_STEREO.
|
||||
For SND_MIXER_SCHN_FRONT_xx, exactly this channel is set/retrieved directly.
|
||||
For CHANNELS_MONO, ALSA channel SND_MIXER_SCHN_MONO is set/retrieved directly.
|
||||
For CHANNELS_STEREO, ALSA channels SND_MIXER_SCHN_FRONT_LEFT and SND_MIXER_SCHN_FRONT_RIGHT
|
||||
are set after a calculation that takes balance into account. Retrieved? Average of both
|
||||
channels? (Using a cached value is not a good idea since the value in the HW may have been
|
||||
altered.) */
|
||||
INT32 channel;
|
||||
} PortControl;
|
||||
|
||||
|
||||
typedef struct tag_PortMixer {
|
||||
snd_mixer_t* mixer_handle;
|
||||
/* Number of array elements used in elems and types. */
|
||||
int numElems;
|
||||
snd_mixer_elem_t** elems;
|
||||
/* Array of port types (PORT_SRC_UNKNOWN etc.). Indices are the same as in elems. */
|
||||
INT32* types;
|
||||
/* Number of array elements used in controls. */
|
||||
int numControls;
|
||||
PortControl* controls;
|
||||
} PortMixer;
|
||||
|
||||
|
||||
///// implemented functions of Ports.h
|
||||
|
||||
INT32 PORT_GetPortMixerCount() {
|
||||
INT32 mixerCount;
|
||||
int card;
|
||||
char devname[16];
|
||||
int err;
|
||||
snd_ctl_t *handle;
|
||||
snd_ctl_card_info_t* info;
|
||||
|
||||
TRACE0("> PORT_GetPortMixerCount\n");
|
||||
|
||||
initAlsaSupport();
|
||||
|
||||
snd_ctl_card_info_malloc(&info);
|
||||
card = -1;
|
||||
mixerCount = 0;
|
||||
if (snd_card_next(&card) >= 0) {
|
||||
while (card >= 0) {
|
||||
sprintf(devname, ALSA_HARDWARE_CARD, card);
|
||||
TRACE1("PORT_GetPortMixerCount: Opening alsa device \"%s\"...\n", devname);
|
||||
err = snd_ctl_open(&handle, devname, 0);
|
||||
if (err < 0) {
|
||||
ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", card, snd_strerror(err));
|
||||
} else {
|
||||
mixerCount++;
|
||||
snd_ctl_close(handle);
|
||||
}
|
||||
if (snd_card_next(&card) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
snd_ctl_card_info_free(info);
|
||||
TRACE0("< PORT_GetPortMixerCount\n");
|
||||
return mixerCount;
|
||||
}
|
||||
|
||||
|
||||
INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) {
|
||||
snd_ctl_t* handle;
|
||||
snd_ctl_card_info_t* card_info;
|
||||
char devname[16];
|
||||
int err;
|
||||
char buffer[100];
|
||||
|
||||
TRACE0("> PORT_GetPortMixerDescription\n");
|
||||
snd_ctl_card_info_malloc(&card_info);
|
||||
|
||||
sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex);
|
||||
TRACE1("Opening alsa device \"%s\"...\n", devname);
|
||||
err = snd_ctl_open(&handle, devname, 0);
|
||||
if (err < 0) {
|
||||
ERROR2("ERROR: snd_ctl_open, card=%d: %s\n", (int) mixerIndex, snd_strerror(err));
|
||||
return FALSE;
|
||||
}
|
||||
err = snd_ctl_card_info(handle, card_info);
|
||||
if (err < 0) {
|
||||
ERROR2("ERROR: snd_ctl_card_info, card=%d: %s\n", (int) mixerIndex, snd_strerror(err));
|
||||
}
|
||||
strncpy(description->name, snd_ctl_card_info_get_id(card_info), PORT_STRING_LENGTH - 1);
|
||||
sprintf(buffer, " [%s]", devname);
|
||||
strncat(description->name, buffer, PORT_STRING_LENGTH - 1 - strlen(description->name));
|
||||
strncpy(description->vendor, "ALSA (http://www.alsa-project.org)", PORT_STRING_LENGTH - 1);
|
||||
strncpy(description->description, snd_ctl_card_info_get_name(card_info), PORT_STRING_LENGTH - 1);
|
||||
strncat(description->description, ", ", PORT_STRING_LENGTH - 1 - strlen(description->description));
|
||||
strncat(description->description, snd_ctl_card_info_get_mixername(card_info), PORT_STRING_LENGTH - 1 - strlen(description->description));
|
||||
getALSAVersion(description->version, PORT_STRING_LENGTH - 1);
|
||||
|
||||
snd_ctl_close(handle);
|
||||
snd_ctl_card_info_free(card_info);
|
||||
TRACE0("< PORT_GetPortMixerDescription\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void* PORT_Open(INT32 mixerIndex) {
|
||||
char devname[16];
|
||||
snd_mixer_t* mixer_handle;
|
||||
int err;
|
||||
PortMixer* handle;
|
||||
|
||||
TRACE0("> PORT_Open\n");
|
||||
sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex);
|
||||
if ((err = snd_mixer_open(&mixer_handle, 0)) < 0) {
|
||||
ERROR2("Mixer %s open error: %s", devname, snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
if ((err = snd_mixer_attach(mixer_handle, devname)) < 0) {
|
||||
ERROR2("Mixer attach %s error: %s", devname, snd_strerror(err));
|
||||
snd_mixer_close(mixer_handle);
|
||||
return NULL;
|
||||
}
|
||||
if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0) {
|
||||
ERROR1("Mixer register error: %s", snd_strerror(err));
|
||||
snd_mixer_close(mixer_handle);
|
||||
return NULL;
|
||||
}
|
||||
err = snd_mixer_load(mixer_handle);
|
||||
if (err < 0) {
|
||||
ERROR2("Mixer %s load error: %s", devname, snd_strerror(err));
|
||||
snd_mixer_close(mixer_handle);
|
||||
return NULL;
|
||||
}
|
||||
handle = (PortMixer*) calloc(1, sizeof(PortMixer));
|
||||
if (handle == NULL) {
|
||||
ERROR0("malloc() failed.");
|
||||
snd_mixer_close(mixer_handle);
|
||||
return NULL;
|
||||
}
|
||||
handle->numElems = 0;
|
||||
handle->elems = (snd_mixer_elem_t**) calloc(MAX_ELEMS, sizeof(snd_mixer_elem_t*));
|
||||
if (handle->elems == NULL) {
|
||||
ERROR0("malloc() failed.");
|
||||
snd_mixer_close(mixer_handle);
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
handle->types = (INT32*) calloc(MAX_ELEMS, sizeof(INT32));
|
||||
if (handle->types == NULL) {
|
||||
ERROR0("malloc() failed.");
|
||||
snd_mixer_close(mixer_handle);
|
||||
free(handle->elems);
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
handle->controls = (PortControl*) calloc(MAX_CONTROLS, sizeof(PortControl));
|
||||
if (handle->controls == NULL) {
|
||||
ERROR0("malloc() failed.");
|
||||
snd_mixer_close(mixer_handle);
|
||||
free(handle->elems);
|
||||
free(handle->types);
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
handle->mixer_handle = mixer_handle;
|
||||
// necessary to initialize data structures
|
||||
PORT_GetPortCount(handle);
|
||||
TRACE0("< PORT_Open\n");
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
void PORT_Close(void* id) {
|
||||
TRACE0("> PORT_Close\n");
|
||||
if (id != NULL) {
|
||||
PortMixer* handle = (PortMixer*) id;
|
||||
if (handle->mixer_handle != NULL) {
|
||||
snd_mixer_close(handle->mixer_handle);
|
||||
}
|
||||
if (handle->elems != NULL) {
|
||||
free(handle->elems);
|
||||
}
|
||||
if (handle->types != NULL) {
|
||||
free(handle->types);
|
||||
}
|
||||
if (handle->controls != NULL) {
|
||||
free(handle->controls);
|
||||
}
|
||||
free(handle);
|
||||
}
|
||||
TRACE0("< PORT_Close\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
INT32 PORT_GetPortCount(void* id) {
|
||||
PortMixer* portMixer;
|
||||
snd_mixer_elem_t *elem;
|
||||
|
||||
TRACE0("> PORT_GetPortCount\n");
|
||||
if (id == NULL) {
|
||||
// $$mp: Should become a descriptive error code (invalid handle).
|
||||
return -1;
|
||||
}
|
||||
portMixer = (PortMixer*) id;
|
||||
if (portMixer->numElems == 0) {
|
||||
for (elem = snd_mixer_first_elem(portMixer->mixer_handle); elem; elem = snd_mixer_elem_next(elem)) {
|
||||
if (!snd_mixer_selem_is_active(elem))
|
||||
continue;
|
||||
TRACE2("Simple mixer control '%s',%i\n",
|
||||
snd_mixer_selem_get_name(elem),
|
||||
snd_mixer_selem_get_index(elem));
|
||||
if (snd_mixer_selem_has_playback_volume(elem)) {
|
||||
portMixer->elems[portMixer->numElems] = elem;
|
||||
portMixer->types[portMixer->numElems] = PORT_DST_UNKNOWN;
|
||||
portMixer->numElems++;
|
||||
}
|
||||
// to prevent buffer overflow
|
||||
if (portMixer->numElems >= MAX_ELEMS) {
|
||||
break;
|
||||
}
|
||||
/* If an element has both playback an capture volume, it is put into the arrays
|
||||
twice. */
|
||||
if (snd_mixer_selem_has_capture_volume(elem)) {
|
||||
portMixer->elems[portMixer->numElems] = elem;
|
||||
portMixer->types[portMixer->numElems] = PORT_SRC_UNKNOWN;
|
||||
portMixer->numElems++;
|
||||
}
|
||||
// to prevent buffer overflow
|
||||
if (portMixer->numElems >= MAX_ELEMS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE0("< PORT_GetPortCount\n");
|
||||
return portMixer->numElems;
|
||||
}
|
||||
|
||||
|
||||
INT32 PORT_GetPortType(void* id, INT32 portIndex) {
|
||||
PortMixer* portMixer;
|
||||
INT32 type;
|
||||
TRACE0("> PORT_GetPortType\n");
|
||||
if (id == NULL) {
|
||||
// $$mp: Should become a descriptive error code (invalid handle).
|
||||
return -1;
|
||||
}
|
||||
portMixer = (PortMixer*) id;
|
||||
if (portIndex < 0 || portIndex >= portMixer->numElems) {
|
||||
// $$mp: Should become a descriptive error code (index out of bounds).
|
||||
return -1;
|
||||
}
|
||||
type = portMixer->types[portIndex];
|
||||
TRACE0("< PORT_GetPortType\n");
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) {
|
||||
PortMixer* portMixer;
|
||||
const char* nam;
|
||||
|
||||
TRACE0("> PORT_GetPortName\n");
|
||||
if (id == NULL) {
|
||||
// $$mp: Should become a descriptive error code (invalid handle).
|
||||
return -1;
|
||||
}
|
||||
portMixer = (PortMixer*) id;
|
||||
if (portIndex < 0 || portIndex >= portMixer->numElems) {
|
||||
// $$mp: Should become a descriptive error code (index out of bounds).
|
||||
return -1;
|
||||
}
|
||||
nam = snd_mixer_selem_get_name(portMixer->elems[portIndex]);
|
||||
strncpy(name, nam, len - 1);
|
||||
name[len - 1] = 0;
|
||||
TRACE0("< PORT_GetPortName\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static int isPlaybackFunction(INT32 portType) {
|
||||
return (portType & PORT_DST_MASK);
|
||||
}
|
||||
|
||||
|
||||
/* Sets portControl to a pointer to the next free array element in the PortControl (pointer)
|
||||
array of the passed portMixer. Returns TRUE if successful. May return FALSE if there is no
|
||||
free slot. In this case, portControl is not altered */
|
||||
static int getControlSlot(PortMixer* portMixer, PortControl** portControl) {
|
||||
if (portMixer->numControls >= MAX_CONTROLS) {
|
||||
return FALSE;
|
||||
} else {
|
||||
*portControl = &(portMixer->controls[portMixer->numControls]);
|
||||
portMixer->numControls++;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Protect against illegal min-max values, preventing divisions by zero.
|
||||
*/
|
||||
inline static long getRange(long min, long max) {
|
||||
if (max > min) {
|
||||
return max - min;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Idea: we may specify that if unit is an empty string, the values are linear and if unit is "dB",
|
||||
the values are logarithmic.
|
||||
*/
|
||||
static void* createVolumeControl(PortControlCreator* creator,
|
||||
PortControl* portControl,
|
||||
snd_mixer_elem_t* elem, int isPlayback) {
|
||||
void* control;
|
||||
float precision;
|
||||
long min, max;
|
||||
|
||||
if (isPlayback) {
|
||||
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
|
||||
} else {
|
||||
snd_mixer_selem_get_capture_volume_range(elem, &min, &max);
|
||||
}
|
||||
/* $$mp: The volume values retrieved with the ALSA API are strongly supposed to be logarithmic.
|
||||
So the following calculation is wrong. However, there is no correct calculation, since
|
||||
for equal-distant logarithmic steps, the precision expressed in linear varies over the
|
||||
scale. */
|
||||
precision = 1.0F / getRange(min, max);
|
||||
control = (creator->newFloatControl)(creator, portControl, CONTROL_TYPE_VOLUME, 0.0F, +1.0F, precision, "");
|
||||
return control;
|
||||
}
|
||||
|
||||
|
||||
void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
|
||||
PortMixer* portMixer;
|
||||
snd_mixer_elem_t* elem;
|
||||
void* control;
|
||||
PortControl* portControl;
|
||||
void* controls[10];
|
||||
int numControls;
|
||||
char* portName;
|
||||
int isPlayback = 0;
|
||||
int isMono;
|
||||
int isStereo;
|
||||
char* type;
|
||||
snd_mixer_selem_channel_id_t channel;
|
||||
memset(controls, 0, sizeof(controls));
|
||||
|
||||
TRACE0("> PORT_GetControls\n");
|
||||
if (id == NULL) {
|
||||
ERROR0("Invalid handle!");
|
||||
// $$mp: an error code should be returned.
|
||||
return;
|
||||
}
|
||||
portMixer = (PortMixer*) id;
|
||||
if (portIndex < 0 || portIndex >= portMixer->numElems) {
|
||||
ERROR0("Port index out of range!");
|
||||
// $$mp: an error code should be returned.
|
||||
return;
|
||||
}
|
||||
numControls = 0;
|
||||
elem = portMixer->elems[portIndex];
|
||||
if (snd_mixer_selem_has_playback_volume(elem) || snd_mixer_selem_has_capture_volume(elem)) {
|
||||
/* Since we've split/duplicated elements with both playback and capture on the recovery
|
||||
of elements, we now can assume that we handle only to deal with either playback or
|
||||
capture. */
|
||||
isPlayback = isPlaybackFunction(portMixer->types[portIndex]);
|
||||
isMono = (isPlayback && snd_mixer_selem_is_playback_mono(elem)) ||
|
||||
(!isPlayback && snd_mixer_selem_is_capture_mono(elem));
|
||||
isStereo = (isPlayback &&
|
||||
snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) &&
|
||||
snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_FRONT_RIGHT)) ||
|
||||
(!isPlayback &&
|
||||
snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_FRONT_LEFT) &&
|
||||
snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_FRONT_RIGHT));
|
||||
// single volume control
|
||||
if (isMono || isStereo) {
|
||||
if (getControlSlot(portMixer, &portControl)) {
|
||||
portControl->elem = elem;
|
||||
portControl->portType = portMixer->types[portIndex];
|
||||
portControl->controlType = CONTROL_TYPE_VOLUME;
|
||||
if (isMono) {
|
||||
portControl->channel = CHANNELS_MONO;
|
||||
} else {
|
||||
portControl->channel = CHANNELS_STEREO;
|
||||
}
|
||||
control = createVolumeControl(creator, portControl, elem, isPlayback);
|
||||
if (control != NULL) {
|
||||
controls[numControls++] = control;
|
||||
}
|
||||
}
|
||||
} else { // more than two channels, each channels has its own control.
|
||||
for (channel = SND_MIXER_SCHN_FRONT_LEFT; channel <= SND_MIXER_SCHN_LAST; channel++) {
|
||||
if (isPlayback && snd_mixer_selem_has_playback_channel(elem, channel) ||
|
||||
!isPlayback && snd_mixer_selem_has_capture_channel(elem, channel)) {
|
||||
if (getControlSlot(portMixer, &portControl)) {
|
||||
portControl->elem = elem;
|
||||
portControl->portType = portMixer->types[portIndex];
|
||||
portControl->controlType = CONTROL_TYPE_VOLUME;
|
||||
portControl->channel = channel;
|
||||
control = createVolumeControl(creator, portControl, elem, isPlayback);
|
||||
// We wrap in a compound control to provide the channel name.
|
||||
if (control != NULL) {
|
||||
/* $$mp 2003-09-14: The following cast shouln't be necessary. Instead, the
|
||||
declaration of PORT_NewCompoundControlPtr in Ports.h should be changed
|
||||
to take a const char* parameter. */
|
||||
control = (creator->newCompoundControl)(creator, (char*) snd_mixer_selem_channel_name(channel), &control, 1);
|
||||
}
|
||||
if (control != NULL) {
|
||||
controls[numControls++] = control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// BALANCE control
|
||||
if (isStereo) {
|
||||
if (getControlSlot(portMixer, &portControl)) {
|
||||
portControl->elem = elem;
|
||||
portControl->portType = portMixer->types[portIndex];
|
||||
portControl->controlType = CONTROL_TYPE_BALANCE;
|
||||
portControl->channel = CHANNELS_STEREO;
|
||||
/* $$mp: The value for precision is chosen more or less arbitrarily. */
|
||||
control = (creator->newFloatControl)(creator, portControl, CONTROL_TYPE_BALANCE, -1.0F, 1.0F, 0.01F, "");
|
||||
if (control != NULL) {
|
||||
controls[numControls++] = control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (snd_mixer_selem_has_playback_switch(elem) || snd_mixer_selem_has_capture_switch(elem)) {
|
||||
if (getControlSlot(portMixer, &portControl)) {
|
||||
type = isPlayback ? CONTROL_TYPE_MUTE : CONTROL_TYPE_SELECT;
|
||||
portControl->elem = elem;
|
||||
portControl->portType = portMixer->types[portIndex];
|
||||
portControl->controlType = type;
|
||||
control = (creator->newBooleanControl)(creator, portControl, type);
|
||||
if (control != NULL) {
|
||||
controls[numControls++] = control;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* $$mp 2003-09-14: The following cast shouln't be necessary. Instead, the
|
||||
declaration of PORT_NewCompoundControlPtr in Ports.h should be changed
|
||||
to take a const char* parameter. */
|
||||
portName = (char*) snd_mixer_selem_get_name(elem);
|
||||
control = (creator->newCompoundControl)(creator, portName, controls, numControls);
|
||||
if (control != NULL) {
|
||||
(creator->addControl)(creator, control);
|
||||
}
|
||||
TRACE0("< PORT_GetControls\n");
|
||||
}
|
||||
|
||||
|
||||
INT32 PORT_GetIntValue(void* controlIDV) {
|
||||
PortControl* portControl = (PortControl*) controlIDV;
|
||||
int value = 0;
|
||||
snd_mixer_selem_channel_id_t channel;
|
||||
|
||||
if (portControl != NULL) {
|
||||
switch (portControl->channel) {
|
||||
case CHANNELS_MONO:
|
||||
channel = SND_MIXER_SCHN_MONO;
|
||||
break;
|
||||
|
||||
case CHANNELS_STEREO:
|
||||
channel = SND_MIXER_SCHN_FRONT_LEFT;
|
||||
break;
|
||||
|
||||
default:
|
||||
channel = portControl->channel;
|
||||
}
|
||||
if (portControl->controlType == CONTROL_TYPE_MUTE ||
|
||||
portControl->controlType == CONTROL_TYPE_SELECT) {
|
||||
if (isPlaybackFunction(portControl->portType)) {
|
||||
snd_mixer_selem_get_playback_switch(portControl->elem, channel, &value);
|
||||
} else {
|
||||
snd_mixer_selem_get_capture_switch(portControl->elem, channel, &value);
|
||||
}
|
||||
if (portControl->controlType == CONTROL_TYPE_MUTE) {
|
||||
value = ! value;
|
||||
}
|
||||
} else {
|
||||
ERROR1("PORT_GetIntValue(): inappropriate control type: %s\n",
|
||||
portControl->controlType);
|
||||
}
|
||||
}
|
||||
return (INT32) value;
|
||||
}
|
||||
|
||||
|
||||
void PORT_SetIntValue(void* controlIDV, INT32 value) {
|
||||
PortControl* portControl = (PortControl*) controlIDV;
|
||||
snd_mixer_selem_channel_id_t channel;
|
||||
|
||||
if (portControl != NULL) {
|
||||
if (portControl->controlType == CONTROL_TYPE_MUTE) {
|
||||
value = ! value;
|
||||
}
|
||||
if (portControl->controlType == CONTROL_TYPE_MUTE ||
|
||||
portControl->controlType == CONTROL_TYPE_SELECT) {
|
||||
if (isPlaybackFunction(portControl->portType)) {
|
||||
snd_mixer_selem_set_playback_switch_all(portControl->elem, value);
|
||||
} else {
|
||||
snd_mixer_selem_set_capture_switch_all(portControl->elem, value);
|
||||
}
|
||||
} else {
|
||||
ERROR1("PORT_SetIntValue(): inappropriate control type: %s\n",
|
||||
portControl->controlType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static float scaleVolumeValueToNormalized(long value, long min, long max) {
|
||||
return (float) (value - min) / getRange(min, max);
|
||||
}
|
||||
|
||||
|
||||
static long scaleVolumeValueToHardware(float value, long min, long max) {
|
||||
return (long)(value * getRange(min, max) + min);
|
||||
}
|
||||
|
||||
|
||||
float getRealVolume(PortControl* portControl,
|
||||
snd_mixer_selem_channel_id_t channel) {
|
||||
float fValue;
|
||||
long lValue = 0;
|
||||
long min = 0;
|
||||
long max = 0;
|
||||
|
||||
if (isPlaybackFunction(portControl->portType)) {
|
||||
snd_mixer_selem_get_playback_volume_range(portControl->elem,
|
||||
&min, &max);
|
||||
snd_mixer_selem_get_playback_volume(portControl->elem,
|
||||
channel, &lValue);
|
||||
} else {
|
||||
snd_mixer_selem_get_capture_volume_range(portControl->elem,
|
||||
&min, &max);
|
||||
snd_mixer_selem_get_capture_volume(portControl->elem,
|
||||
channel, &lValue);
|
||||
}
|
||||
fValue = scaleVolumeValueToNormalized(lValue, min, max);
|
||||
return fValue;
|
||||
}
|
||||
|
||||
|
||||
void setRealVolume(PortControl* portControl,
|
||||
snd_mixer_selem_channel_id_t channel, float value) {
|
||||
long lValue = 0;
|
||||
long min = 0;
|
||||
long max = 0;
|
||||
|
||||
if (isPlaybackFunction(portControl->portType)) {
|
||||
snd_mixer_selem_get_playback_volume_range(portControl->elem,
|
||||
&min, &max);
|
||||
lValue = scaleVolumeValueToHardware(value, min, max);
|
||||
snd_mixer_selem_set_playback_volume(portControl->elem,
|
||||
channel, lValue);
|
||||
} else {
|
||||
snd_mixer_selem_get_capture_volume_range(portControl->elem,
|
||||
&min, &max);
|
||||
lValue = scaleVolumeValueToHardware(value, min, max);
|
||||
snd_mixer_selem_set_capture_volume(portControl->elem,
|
||||
channel, lValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static float getFakeBalance(PortControl* portControl) {
|
||||
float volL, volR;
|
||||
|
||||
// pan is the ratio of left and right
|
||||
volL = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT);
|
||||
volR = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT);
|
||||
if (volL > volR) {
|
||||
return -1.0f + (volR / volL);
|
||||
}
|
||||
else if (volR > volL) {
|
||||
return 1.0f - (volL / volR);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
static float getFakeVolume(PortControl* portControl) {
|
||||
float valueL;
|
||||
float valueR;
|
||||
float value;
|
||||
|
||||
valueL = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT);
|
||||
valueR = getRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT);
|
||||
// volume is the greater value of both
|
||||
value = valueL > valueR ? valueL : valueR ;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sets the unsigned values for left and right volume according to
|
||||
* the given volume (0...1) and balance (-1..0..+1)
|
||||
*/
|
||||
static void setFakeVolume(PortControl* portControl, float vol, float bal) {
|
||||
float volumeLeft;
|
||||
float volumeRight;
|
||||
|
||||
if (bal < 0.0f) {
|
||||
volumeLeft = vol;
|
||||
volumeRight = vol * (bal + 1.0f);
|
||||
} else {
|
||||
volumeLeft = vol * (1.0f - bal);
|
||||
volumeRight = vol;
|
||||
}
|
||||
setRealVolume(portControl, SND_MIXER_SCHN_FRONT_LEFT, volumeLeft);
|
||||
setRealVolume(portControl, SND_MIXER_SCHN_FRONT_RIGHT, volumeRight);
|
||||
}
|
||||
|
||||
|
||||
float PORT_GetFloatValue(void* controlIDV) {
|
||||
PortControl* portControl = (PortControl*) controlIDV;
|
||||
float value = 0.0F;
|
||||
|
||||
if (portControl != NULL) {
|
||||
if (portControl->controlType == CONTROL_TYPE_VOLUME) {
|
||||
switch (portControl->channel) {
|
||||
case CHANNELS_MONO:
|
||||
value = getRealVolume(portControl, SND_MIXER_SCHN_MONO);
|
||||
break;
|
||||
|
||||
case CHANNELS_STEREO:
|
||||
value = getFakeVolume(portControl);
|
||||
break;
|
||||
|
||||
default:
|
||||
value = getRealVolume(portControl, portControl->channel);
|
||||
}
|
||||
} else if (portControl->controlType == CONTROL_TYPE_BALANCE) {
|
||||
if (portControl->channel == CHANNELS_STEREO) {
|
||||
value = getFakeBalance(portControl);
|
||||
} else {
|
||||
ERROR0("PORT_GetFloatValue(): Balance only allowed for stereo channels!\n");
|
||||
}
|
||||
} else {
|
||||
ERROR1("PORT_GetFloatValue(): inappropriate control type: %s!\n",
|
||||
portControl->controlType);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void PORT_SetFloatValue(void* controlIDV, float value) {
|
||||
PortControl* portControl = (PortControl*) controlIDV;
|
||||
|
||||
if (portControl != NULL) {
|
||||
if (portControl->controlType == CONTROL_TYPE_VOLUME) {
|
||||
switch (portControl->channel) {
|
||||
case CHANNELS_MONO:
|
||||
setRealVolume(portControl, SND_MIXER_SCHN_MONO, value);
|
||||
break;
|
||||
|
||||
case CHANNELS_STEREO:
|
||||
setFakeVolume(portControl, value, getFakeBalance(portControl));
|
||||
break;
|
||||
|
||||
default:
|
||||
setRealVolume(portControl, portControl->channel, value);
|
||||
}
|
||||
} else if (portControl->controlType == CONTROL_TYPE_BALANCE) {
|
||||
if (portControl->channel == CHANNELS_STEREO) {
|
||||
setFakeVolume(portControl, getFakeVolume(portControl), value);
|
||||
} else {
|
||||
ERROR0("PORT_SetFloatValue(): Balance only allowed for stereo channels!\n");
|
||||
}
|
||||
} else {
|
||||
ERROR1("PORT_SetFloatValue(): inappropriate control type: %s!\n",
|
||||
portControl->controlType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // USE_PORTS
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -231,7 +231,7 @@ static const char* translate_error(jint err) {
|
||||
int table_size = sizeof(error_messages) / sizeof(error_messages[0]);
|
||||
int i;
|
||||
|
||||
for (i=0; i<table_size; i++) {
|
||||
for (i = 0; i < table_size; i++) {
|
||||
if (err == error_messages[i].err) {
|
||||
return error_messages[i].msg;
|
||||
}
|
||||
@ -293,7 +293,7 @@ JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue
|
||||
*/
|
||||
arg_count = (*env)->GetArrayLength(env, args);
|
||||
|
||||
for (i=0; i<arg_count; i++) {
|
||||
for (i = 0; i < arg_count; i++) {
|
||||
jobject obj = (*env)->GetObjectArrayElement(env, args, i);
|
||||
if (obj != NULL) {
|
||||
cstr = JNU_GetStringPlatformChars(env, obj, &isCopy);
|
||||
@ -314,6 +314,15 @@ JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char* newbuf = (char*)realloc(buf, size + 1);
|
||||
if (newbuf == NULL) {
|
||||
free(buf);
|
||||
JNU_ThrowOutOfMemoryError(env, "realloc failed");
|
||||
return -1;
|
||||
}
|
||||
buf = newbuf;
|
||||
buf[size++] = 0;
|
||||
}
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
free(buf);
|
||||
|
@ -828,7 +828,7 @@ public class Check {
|
||||
return buf.toList();
|
||||
}
|
||||
|
||||
boolean checkDenotable(Type t) {
|
||||
public boolean checkDenotable(Type t) {
|
||||
return denotableChecker.visit(t, null);
|
||||
}
|
||||
// where
|
||||
|
@ -43,6 +43,7 @@ import com.sun.tools.javac.code.Directive.*;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.Type.*;
|
||||
import com.sun.tools.javac.code.Types.UniqueType;
|
||||
import com.sun.tools.javac.comp.Check;
|
||||
import com.sun.tools.javac.file.PathFileObject;
|
||||
import com.sun.tools.javac.jvm.Pool.DynamicMethod;
|
||||
import com.sun.tools.javac.jvm.Pool.Method;
|
||||
@ -101,6 +102,8 @@ public class ClassWriter extends ClassFile {
|
||||
/** Type utilities. */
|
||||
private Types types;
|
||||
|
||||
private Check check;
|
||||
|
||||
/**
|
||||
* If true, class files will be written in module-specific subdirectories
|
||||
* of the CLASS_OUTPUT location.
|
||||
@ -178,6 +181,7 @@ public class ClassWriter extends ClassFile {
|
||||
target = Target.instance(context);
|
||||
source = Source.instance(context);
|
||||
types = Types.instance(context);
|
||||
check = Check.instance(context);
|
||||
fileManager = context.get(JavaFileManager.class);
|
||||
signatureGen = new CWSignatureGenerator(types);
|
||||
|
||||
@ -1294,10 +1298,10 @@ public class ClassWriter extends ClassFile {
|
||||
//where
|
||||
private boolean needsLocalVariableTypeEntry(Type t) {
|
||||
//a local variable needs a type-entry if its type T is generic
|
||||
//(i.e. |T| != T) and if it's not an intersection type (not supported
|
||||
//in signature attribute grammar)
|
||||
return (!types.isSameType(t, types.erasure(t)) &&
|
||||
!t.isCompound());
|
||||
//(i.e. |T| != T) and if it's not an non-denotable type (non-denotable
|
||||
// types are not supported in signature attribute grammar!)
|
||||
return !types.isSameType(t, types.erasure(t)) &&
|
||||
check.checkDenotable(t);
|
||||
}
|
||||
|
||||
void writeStackMap(Code code) {
|
||||
|
@ -44,6 +44,7 @@ compiler/ciReplay/TestSAServer.java 8029528 generic-all
|
||||
compiler/codecache/stress/OverloadCompileQueueTest.java 8166554 generic-all
|
||||
compiler/codegen/Test6896617.java 8193479 generic-all
|
||||
compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8140405 generic-all
|
||||
compiler/jvmci/compilerToVM/GetExceptionTableTest.java 8200135 generic-all
|
||||
compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java 8158860 generic-all
|
||||
compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java 8163894 generic-all
|
||||
compiler/tiered/LevelTransitionTest.java 8067651 generic-all
|
||||
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import jdk.test.lib.RandomFactory;
|
||||
|
||||
/* @test
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @run main ReadAllReadNTransferTo
|
||||
* @bug 8180451
|
||||
* @summary Verify ByteArrayInputStream readAllBytes, readNBytes, and transferTo
|
||||
* @key randomness
|
||||
*/
|
||||
public class ReadAllReadNTransferTo {
|
||||
private static final int SIZE = 0x4d4d;
|
||||
|
||||
private static Random random = RandomFactory.getRandom();
|
||||
|
||||
public static void main(String... args) throws IOException {
|
||||
byte[] buf = new byte[SIZE];
|
||||
random.nextBytes(buf);
|
||||
int position = random.nextInt(SIZE/2);
|
||||
int size = random.nextInt(SIZE - position);
|
||||
|
||||
ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(buf, position, size);
|
||||
int off = random.nextInt(size / 2);
|
||||
int len = random.nextInt(size - off);
|
||||
|
||||
byte[] bN = new byte[off + len];
|
||||
if (bais.readNBytes(bN, off, len) != len) {
|
||||
throw new RuntimeException("readNBytes return value");
|
||||
}
|
||||
if (!Arrays.equals(bN, off, off + len,
|
||||
buf, position, position + len)) {
|
||||
throw new RuntimeException("readNBytes content");
|
||||
}
|
||||
|
||||
byte[] bAll = bais.readAllBytes();
|
||||
Objects.requireNonNull(bAll, "readAllBytes return value");
|
||||
if (bAll.length != size - len) {
|
||||
throw new RuntimeException("readAllBytes return value length");
|
||||
}
|
||||
if (!Arrays.equals(bAll, 0, bAll.length,
|
||||
buf, position + len, position + len + bAll.length)) {
|
||||
throw new RuntimeException("readAllBytes content");
|
||||
}
|
||||
|
||||
// XXX transferTo()
|
||||
bais = new ByteArrayInputStream(buf);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(buf.length);
|
||||
if (bais.transferTo(baos) != buf.length) {
|
||||
throw new RuntimeException("transferTo return value length");
|
||||
}
|
||||
if (!Arrays.equals(buf, baos.toByteArray())) {
|
||||
throw new RuntimeException("transferTo content");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -102,7 +102,7 @@ public class Connect {
|
||||
try {
|
||||
dc.send(bb, bogus);
|
||||
throw new RuntimeException("Allowed bogus send while connected");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
} catch (AlreadyConnectedException ace) {
|
||||
// Correct behavior
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8198753
|
||||
* @summary Test DatagramChannel connect exceptions
|
||||
* @library ..
|
||||
* @run testng ConnectExceptions
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class ConnectExceptions {
|
||||
static DatagramChannel sndChannel;
|
||||
static DatagramChannel rcvChannel;
|
||||
static InetSocketAddress sender;
|
||||
static InetSocketAddress receiver;
|
||||
|
||||
@BeforeTest
|
||||
public static void setup() throws Exception {
|
||||
sndChannel = DatagramChannel.open();
|
||||
sndChannel.bind(null);
|
||||
InetAddress address = InetAddress.getLocalHost();
|
||||
if (address.isLoopbackAddress()) {
|
||||
address = InetAddress.getLoopbackAddress();
|
||||
}
|
||||
sender = new InetSocketAddress(address,
|
||||
sndChannel.socket().getLocalPort());
|
||||
|
||||
rcvChannel = DatagramChannel.open();
|
||||
rcvChannel.bind(null);
|
||||
receiver = new InetSocketAddress(address,
|
||||
rcvChannel.socket().getLocalPort());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = UnsupportedAddressTypeException.class)
|
||||
public static void unsupportedAddressTypeException() throws Exception {
|
||||
rcvChannel.connect(sender);
|
||||
sndChannel.connect(new SocketAddress() {});
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = UnresolvedAddressException.class)
|
||||
public static void unresolvedAddressException() throws Exception {
|
||||
String host = TestUtil.UNRESOLVABLE_HOST;
|
||||
InetSocketAddress unresolvable = new InetSocketAddress (host, 37);
|
||||
sndChannel.connect(unresolvable);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AlreadyConnectedException.class)
|
||||
public static void alreadyConnectedException() throws Exception {
|
||||
sndChannel.connect(receiver);
|
||||
InetSocketAddress random = new InetSocketAddress(0);
|
||||
sndChannel.connect(random);
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
public static void cleanup() throws Exception {
|
||||
rcvChannel.close();
|
||||
sndChannel.close();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user