Merge pull request #1347 from ermshiperete/ImproveEllipsisHandling
authorMiguel de Icaza <miguel@gnome.org>
Sun, 2 Nov 2014 17:36:49 +0000 (12:36 -0500)
committerMiguel de Icaza <miguel@gnome.org>
Sun, 2 Nov 2014 17:36:49 +0000 (12:36 -0500)
[MWF] Improve ellipsis handling

89 files changed:
acinclude.m4
appveyor.yml [new file with mode: 0644]
configure.ac
eglib/acinclude.m4
libgc/acinclude.m4
libgc/include/gc_config_macros.h
mcs/class/Managed.Windows.Forms/System.Windows.Forms/Help.cs
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds70.cs
mcs/class/System.Core/Makefile
mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs
mcs/class/System.Core/System/TimeZoneInfo.Android.cs
mcs/class/System.Core/System/TimeZoneInfo.Serialization.cs
mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs
mcs/class/System.Core/System/TimeZoneInfo.cs
mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs
mcs/class/System.IdentityModel/System.IdentityModel-net_4_5.csproj
mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenExpiredException.cs [new file with mode: 0644]
mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenNotYetValidException.cs [new file with mode: 0644]
mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenReplayDetectedException.cs [new file with mode: 0644]
mcs/class/System.IdentityModel/System.IdentityModel.dll.sources
mcs/class/System.IdentityModel/System.IdentityModel/SignatureVerificationFailedException.cs [new file with mode: 0644]
mcs/class/System.Web.Abstractions/System.Web/HttpContextWrapper.cs
mcs/class/System.Web.Abstractions/System.Web/HttpRequestBase.cs
mcs/class/System.Web.Abstractions/System.Web/HttpRequestWrapper.cs
mcs/class/System.Web.Abstractions/System.Web/HttpResponseBase.cs
mcs/class/System.Web.Abstractions/System.Web/HttpResponseWrapper.cs
mcs/class/System.Web.Extensions/System.Web.Script.Serialization/JavaScriptSerializer.cs
mcs/class/System.Web.Extensions/Test/System.Web.Script.Serialization/JavaScriptSerializerTest.cs
mcs/class/System.Web/System.Web-net_4_5.csproj
mcs/class/System.Web/System.Web-plainweb-net_4_5.csproj
mcs/class/System.Web/System.Web-tests-net_4_5.csproj
mcs/class/System.Web/System.Web.Security/FormsAuthenticationModule.cs
mcs/class/System.Web/System.Web/EventHandlerTaskAsyncHelper.cs [new file with mode: 0644]
mcs/class/System.Web/System.Web/HttpRequest.cs
mcs/class/System.Web/System.Web/HttpResponse.cs
mcs/class/System.Web/System.Web/HttpTaskAsyncHandler.cs [new file with mode: 0644]
mcs/class/System.Web/System.Web/TaskAsyncResult.cs [new file with mode: 0644]
mcs/class/System.Web/System.Web/TaskEventHandler.cs [new file with mode: 0644]
mcs/class/System.Web/System.Web/UnvalidatedRequestValues.cs [new file with mode: 0644]
mcs/class/System.Web/System.Web/UnvalidatedRequestValuesBase.cs [new file with mode: 0644]
mcs/class/System.Web/System.Web/UnvalidatedRequestValuesWrapper.cs [new file with mode: 0644]
mcs/class/System.Web/System.Web_test.dll.sources
mcs/class/System.Web/Test/System.Web/EventHandlerTaskAsyncHelperTest.cs [new file with mode: 0644]
mcs/class/System.Web/Test/System.Web/HttpTaskAsyncHandlerTest.cs [new file with mode: 0644]
mcs/class/System.Web/Test/System.Web/TaskAsyncResultTest.cs [new file with mode: 0644]
mcs/class/System.Web/net_4_5_System.Web.dll.sources
mcs/class/System.XML/System.Xml/XmlDocument.cs
mcs/class/System.XML/Test/System.Xml/XmlTextReaderTests.cs
mcs/class/System/System.IO/FileSystemWatcher.cs
mcs/class/System/System.IO/KeventWatcher.cs
mcs/class/System/System.IO/SearchPattern.cs
mcs/class/System/System.Media/AudioDevice.cs
mcs/class/System/System.Net.Sockets/SocketAsyncEventArgs.cs
mcs/class/System/System.Net.Sockets/Socket_2_1.cs
mcs/class/System/System.Net/WebClient.cs
mcs/class/System/System/UriParseComponents.cs
mcs/class/System/Test/System.Net/WebClientTest.cs
mcs/class/System/Test/System/UriTest2.cs
mcs/class/corlib/DateTime.Now_Test.sh [new file with mode: 0755]
mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs
mcs/class/corlib/System.Runtime.InteropServices/IErrorInfo.cs [new file with mode: 0644]
mcs/class/corlib/System.Runtime.InteropServices/ManagedErrorInfo.cs [new file with mode: 0644]
mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs
mcs/class/corlib/System.Security.Claims/Claim.cs
mcs/class/corlib/System/InvalidTimeZoneException.cs
mcs/class/corlib/System/TimeZone.cs
mcs/class/corlib/System/TimeZoneNotFoundException.cs
mcs/class/corlib/corlib.dll.sources
mono/metadata/class.c
mono/metadata/sgen-alloc.c
mono/metadata/sgen-gc.c
mono/metadata/sgen-gc.h
mono/metadata/sgen-marksweep.c
mono/metadata/sgen-nursery-allocator.c
mono/metadata/sgen-pinning.c
mono/metadata/sgen-pinning.h
mono/metadata/socket-io.c
mono/metadata/threadpool.c
mono/mini/Makefile.am.in
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/cpu-s390x.md
mono/mini/decompose.c
mono/mini/mini-llvm-cpp.cpp
mono/mini/mini-llvm.c
mono/mini/mini-s390x.c
mono/mini/mini.h
mono/mini/support-s390x.h
mono/utils/mono-sigcontext.h

index 5216cd14a5ef88245107fe9f27c1821914e14025..bbc2781eab00efaa492b7d458dd88aa1d8d1561e 100644 (file)
@@ -26,7 +26,7 @@ i?86-*-linux*|i?86-apple-darwin*|x86_64-*-linux*|powerpc-*-linux*|powerpc64-*-li
 |amd64-*-freebsd*|i?86-*-freebsd*|ia64-*-freebsd*|arm*-*-linux*|sparc*-*-linux*|mips*-*-linux*|x86_64-apple-darwin*|aarch64*)
     pic_options='-fPIC'
     ;;
-?86-pc-cygwin*|i?86-pc-cygwin*)
+?86-pc-cygwin*|i?86-pc-cygwin*|i?86-pc-mingw32*)
     pic_options='-DDLL_EXPORT'
     ;;
 i?86-apple-darwin*|arm-apple-darwin*)
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644 (file)
index 0000000..58c9a3a
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# Appveyor configuration file for CI build of Mono on Windows (under Cygwin)
+#
+# For further details see http://www.appveyor.com
+#
+
+# Use 'unstable' Appveyor build worker image as Appveyor have added Cygwin to this for us
+os: Unstable
+
+#
+# Custom environment variables
+#
+environment:
+    global:
+        CYG_ROOT: C:/cygwin
+        CYG_MIRROR: http://cygwin.mirror.constant.com
+        CYG_CACHE: C:/cygwin/var/cache/setup
+        NSIS_ROOT: C:\nsis
+   
+#
+# Initialisation prior to pulling the Mono repository
+#
+init:
+    - 'echo Building Mono for Windows'
+    - 'echo System architecture: %PLATFORM%'
+    - 'echo Repo build branch is: %APPVEYOR_REPO_BRANCH%'
+    - 'echo Build folder is: %APPVEYOR_BUILD_FOLDER%'
+# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail
+    - 'git config --global core.autocrlf input'
+
+#
+# Install needed build dependencies
+# 
+install:
+# NOTE: Already installed on current Appveyor unstable image
+#    - 'echo Retrieving Cygwin'
+#   - 'appveyor DownloadFile http://cygwin.com/setup-x86.exe -FileName %CYGROOT%/setup-x86.exe'
+    - 'echo Setting up Cygwin dependencies'
+    - '%CYG_ROOT%\setup-x86.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P autoconf -P automake -P bison -P gcc-core -P gcc-g++ -P mingw-runtime -P mingw-binutils -P mingw-gcc-core -P mingw-gcc-g++ -P mingw-pthreads -P mingw-w32api -P libtool -P make -P python -P gettext-devel -P gettext -P intltool -P libiconv -P pkg-config -P git -P wget -P curl > NUL' 
+    - 'echo Check Cygwin setup'
+    - '%CYG_ROOT%/bin/bash -lc "cygcheck -dc cygwin"'
+    - 'echo Done setting up Cygwin'
+    - 'echo Retrieving NSIS'
+    - 'appveyor DownloadFile "http://sunet.dl.sourceforge.net/project/nsis/NSIS 2/2.46/nsis-2.46-setup.exe" -FileName nsissetup.exe'
+    - 'echo Setting up NSIS'
+    - 'nsissetup.exe /S /D=%NSIS_ROOT%'
+    - 'echo Done setting up NSIS'
+
+#
+# NOTE: msbuild doesn't work at present so use Cygwin to build
+#
+#build:
+#    project: C:\projects\mono\msvc\mono.sln 
+#    verbosity: detailed
+
+# Cygwin build script
+#
+# NOTES:
+#
+# The stdin/stdout file descriptor appears not to be valid for the Appveyor
+# build which causes failures as certain functions attempt to redirect 
+# default file handles. Ensure a dummy file descriptor is opened with exec.
+#
+build_script:
+    - cmd: 'echo Cygwin root is: %CYG_ROOT%'
+    - cmd: 'echo Build folder is: %APPVEYOR_BUILD_FOLDER%'
+    - cmd: 'echo Repo build branch is: %APPVEYOR_REPO_BRANCH%'
+    - cmd: 'echo Repo build commit is: %APPVEYOR_REPO_COMMIT%'
+    - cmd: 'echo Autogen running...'
+    - cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; NOCONFIGURE=1 ./autogen.sh --prefix=/usr/local --with-preview=yes"'
+    - cmd: 'echo Configure running...'
+    - cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; ./configure --host=i686-pc-mingw32"'
+    - cmd: 'echo Pulling monolite latest...'
+    - cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make get-monolite-latest"'
+    - cmd: 'echo Make running...'
+    - cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make"'
+    - cmd: 'echo Installing...'
+    - cmd: 'mkdir %APPVEYOR_BUILD_FOLDER%\install'
+    - cmd: '%CYG_ROOT%/bin/bash --login -lc "export CYGWIN=winsymlinks:native; mount \"$APPVEYOR_BUILD_FOLDER\install\" /usr/local; cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make install; umount /usr/local"'
+#    - cmd: 'echo Building package...'
+#    - cmd: 'cd %APPVEYOR_BUILD_FOLDER%'
+#    - cmd: '%NSIS_ROOT%\makensis /DMILESTONE=%APPVEYOR_REPO_BRANCH% /DSOURCE_INSTALL_DIR=%APPVEYOR_BUILD_FOLDER\install\*.* /DBUILDNUM=%APPVEYOR_BUILD_VERSION% monowiz.win32.nsi'
+#    - cmd: 'Building distribution...'
+#    - cmd: '%CYG_ROOT%/bin/bash -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make dist"'
+
+#
+# Disable tests for now
+# 
+test: off
+
+#
+# NOTE: Currently this is the Mono installation tree. In future we will create an installation package artifact.
+#       It has to be relative to the project path. Thus we have installed to within the build tree.
+#
+artifacts:
+    - path: install
+      name: mono-binaries
+      type: zip
index 7e8f26199ad671a789abc1f32925281d0a9ed230..2bc3c0d08f50253386858ba297895eadfae6e96f 100644 (file)
@@ -1,7 +1,7 @@
 # Process this file with autoconf to produce a configure script.
 #AC_PREREQ([2.62])
 
-AC_INIT(mono, [3.10.1],
+AC_INIT(mono, [3.12.1],
         [http://bugzilla.xamarin.com/enter_bug.cgi?classification=Mono])
 
 AC_CONFIG_SRCDIR([README.md])
@@ -578,6 +578,7 @@ else
 fi
 CFLAGS="$CFLAGS -g $WARN"
 CFLAGS_FOR_LIBGC="$CFLAGS_FOR_LIBGC -g"
+CPPFLAGS="$CPPFLAGS -g $WARN"
 
 # Where's the 'mcs' source tree?
 if test -d $srcdir/mcs; then
@@ -2459,8 +2460,6 @@ if test "x$enable_llvm" = "xyes"; then
 
    # Should be something like '2.6' or '2.7svn'
    llvm_version=`$LLVM_CONFIG --version`
-   major_version=`echo $llvm_version | cut -c 1`
-   minor_version=`echo $llvm_version | cut -c 3`
    llvm_api_version=`$LLVM_CONFIG --mono-api-version 2>/dev/null`
    AC_MSG_CHECKING(LLVM version)
    AC_MSG_RESULT($llvm_version)
@@ -2481,14 +2480,8 @@ if test "x$enable_llvm" = "xyes"; then
          AC_MSG_ERROR([Compiling with stock LLVM is not supported, please use the Mono LLVM repo at https://github.com/mono/llvm, with the GIT branch which matches this version of mono, i.e. 'mono-2-10' for Mono 2.10.])
    fi
 
-   AC_DEFINE_UNQUOTED(LLVM_MAJOR_VERSION, $major_version, [Major version of LLVM libraries])
-   AC_DEFINE_UNQUOTED(LLVM_MINOR_VERSION, $minor_version, [Minor version of LLVM libraries])
    AC_DEFINE_UNQUOTED(LLVM_VERSION, "$llvm_version", [Full version of LLVM libraties])
 
-   # Have to pass these on the command line since mini-llvm-cpp.h already includes
-   # llvm's config.h
-   LLVM_CXXFLAGS="$LLVM_CXXFLAGS -DLLVM_MAJOR_VERSION=$major_version -DLLVM_MINOR_VERSION=$minor_version"
-
    AC_SUBST(LLVM_CFLAGS)
    AC_SUBST(LLVM_CXXFLAGS)
    AC_SUBST(LLVM_LIBS)
index 5216cd14a5ef88245107fe9f27c1821914e14025..bbc2781eab00efaa492b7d458dd88aa1d8d1561e 100644 (file)
@@ -26,7 +26,7 @@ i?86-*-linux*|i?86-apple-darwin*|x86_64-*-linux*|powerpc-*-linux*|powerpc64-*-li
 |amd64-*-freebsd*|i?86-*-freebsd*|ia64-*-freebsd*|arm*-*-linux*|sparc*-*-linux*|mips*-*-linux*|x86_64-apple-darwin*|aarch64*)
     pic_options='-fPIC'
     ;;
-?86-pc-cygwin*|i?86-pc-cygwin*)
+?86-pc-cygwin*|i?86-pc-cygwin*|i?86-pc-mingw32*)
     pic_options='-DDLL_EXPORT'
     ;;
 i?86-apple-darwin*|arm-apple-darwin*)
index 5216cd14a5ef88245107fe9f27c1821914e14025..bbc2781eab00efaa492b7d458dd88aa1d8d1561e 100644 (file)
@@ -26,7 +26,7 @@ i?86-*-linux*|i?86-apple-darwin*|x86_64-*-linux*|powerpc-*-linux*|powerpc64-*-li
 |amd64-*-freebsd*|i?86-*-freebsd*|ia64-*-freebsd*|arm*-*-linux*|sparc*-*-linux*|mips*-*-linux*|x86_64-apple-darwin*|aarch64*)
     pic_options='-fPIC'
     ;;
-?86-pc-cygwin*|i?86-pc-cygwin*)
+?86-pc-cygwin*|i?86-pc-cygwin*|i?86-pc-mingw32*)
     pic_options='-DDLL_EXPORT'
     ;;
 i?86-apple-darwin*|arm-apple-darwin*)
index c11caa7748e0a7c2baff69d7bfcd9478f5a675e3..caf8de527c32b8056e8e42a6077b4df0b5b0928e 100644 (file)
@@ -32,7 +32,7 @@
 # define GC_LINUX_THREADS
 #endif
 #if defined(WIN32_THREADS)
-# define GC_WIN32_THREADS
+# define GC_WIN32_THREADS 1
 #endif
 #if defined(USE_LD_WRAP)
 # define GC_USE_LD_WRAP
index a7d355bc1a52888bc1fd22a68006f209062d3e0b..46065f0d7240e46728da412b4e51034bb2d4ba4f 100644 (file)
 
 using System;
 using System.Drawing;
+using System.Diagnostics;
+using System.IO;
 
 namespace System.Windows.Forms
 {
+       /// <summary>
+       /// http://msdn.microsoft.com/en-us/library/System.Windows.Forms.Help(v=vs.110).aspx
+       /// </summary>
        public class Help
        {
                #region Constructor
@@ -42,7 +47,7 @@ namespace System.Windows.Forms
                #region Public Static Methods
                public static void ShowHelp (Control parent, string url)
                {
-                       ShowHelp(parent, url, HelpNavigator.TableOfContents, null);
+                       ShowHelp (parent, url, null);
                }
 
                public static void ShowHelp (Control parent, string url, HelpNavigator navigator)
@@ -57,9 +62,7 @@ namespace System.Windows.Forms
 
                public static void ShowHelp (Control parent, string url, string keyword)
                {
-                       if (keyword == null || keyword == String.Empty)
-                               ShowHelp (parent, url, HelpNavigator.TableOfContents, null);
-                       ShowHelp (parent, url, HelpNavigator.Topic, keyword);
+                       ShowHelpTopic (url, keyword);
                }
 
                public static void ShowHelpIndex (Control parent, string url)
@@ -72,5 +75,55 @@ namespace System.Windows.Forms
                {
                }
                #endregion      // Public Static Methods
+
+               /// <summary>
+               /// Show a help file and topic using a help viewer
+               /// </summary>
+               /// <param name="helpFile">path to a .chm help file</param>
+               /// <param name="helpTopic">path to a topic in helpFile, or null</param>
+               private static void ShowHelpTopic (string helpFile, string helpTopic)
+               {
+                       if (helpFile == null)
+                               throw new ArgumentNullException ();
+                       if (helpFile == String.Empty)
+                               throw new ArgumentException ();
+
+                       // Use forward slashes in helpFile path if needed
+                       helpFile = helpFile.Replace (@"\", Path.DirectorySeparatorChar.ToString ());
+
+                       string helpViewer = Environment.GetEnvironmentVariable ("MONO_HELP_VIEWER") ?? "chmsee";
+                       string arguments = String.Format ("\"{0}\"", helpFile);
+                       if (!String.IsNullOrEmpty (helpTopic)) {
+                               if (!helpTopic.StartsWith ("/"))
+                                       helpTopic = "/" + helpTopic;
+                               helpTopic = helpTopic.TrimEnd (' ');
+                               arguments = String.Format ("\"{0}::{1}\"", helpFile, helpTopic);
+                       }
+
+                       try {
+                               RunNonblockingProcess (helpViewer, arguments);
+                       } catch (Exception e) {
+                               // Don't crash if the help viewer couldn't be launched. There
+                               // won't be an exception thrown if the help viewer can't find
+                               // the help file; it's up to the help viewer to display such an error.
+                               string message = String.Format ("The help viewer could not load. Maybe you don't have {0} installed or haven't set MONO_HELP_VIEWER. The specific error message was: {1}", helpViewer, e.Message);
+                               Console.Error.WriteLine (message);
+                               MessageBox.Show (message);
+                       }
+               }
+
+               /// <remarks>
+               /// throws exception from Process.Start() if there was a problem starting
+               /// </remarks>
+               private static void RunNonblockingProcess (string command, string arguments)
+               {
+                       using (Process process = new Process ()) {
+                               process.StartInfo.FileName = command;
+                               process.StartInfo.Arguments = arguments;
+                               process.StartInfo.UseShellExecute = false;
+
+                               process.Start ();
+                       }
+               }
        }
 }
index 991727bbc00779b3441c2c7020c03f405aa85f76..2f4fef03e1946ca0ac018306ce1da8f946fb5d53 100644 (file)
@@ -489,6 +489,19 @@ namespace Mono.Data.Tds.Protocol
                        
                        Comm.Append ((byte) 0x00); // no param meta data name
                        Comm.Append ((byte) 0x00); // no status flags
+
+                       // Convert BigNVarChar values larger than 4000 chars to nvarchar(max)
+                       // Need to do this here so WritePreparedParameterInfo emit the
+                       // correct data type
+                       foreach (TdsMetaParameter param2 in parameters) {
+                               var colType = param2.GetMetaType ();
+
+                               if (colType == TdsColumnType.BigNVarChar) {
+                                       int size = param2.GetActualSize ();
+                                       if ((size >> 1) > 4000)
+                                               param2.Size = -1;
+                               }
+                       }
                        
                        // Write sql as a parameter value - UCS2
                        TdsMetaParameter param = new TdsMetaParameter ("sql", 
index f8cc33c7e8b94afff4a3eb58bfa11aa6c8cc1c0d..eeca6391a148100f8f228a3eaf03059b546f4320 100644 (file)
@@ -72,3 +72,22 @@ csproj-local:
        $(MAKE) csproj-local intermediate=plaincore/
 endif
 endif
+
+#
+# Android TimeZoneInfo testing....
+#
+
+tzi.exe: ../corlib/System/AndroidPlatform.cs $(wildcard System/TimeZone*.cs) ../../build/common/Consts.cs ../Mono.Options/Mono.Options/Options.cs
+       mcs /debug+ /out:$@ /unsafe "/d:INSIDE_CORLIB;MONODROID;NET_4_0;LIBC;SELF_TEST" $^
+
+android-pull-tzdb:
+       mkdir -p android/tzdb/usr/share/zoneinfo
+       mkdir -p android/tzdb/misc/zoneinfo/zoneinfo
+       android_root=`adb shell echo '$$ANDROID_ROOT' | tr -d "\r"` ; \
+       android_data=`adb shell echo '$$ANDROID_DATA' | tr -d "\r"` ; \
+       adb $(ADB_TARGET) pull $$android_root/usr/share/zoneinfo    android/tzdb/usr/share/zoneinfo ; \
+       adb $(ADB_TARGET) pull $$android_data/misc/zoneinfo/tzdata  android/tzdb/misc/zoneinfo
+       mkdir -p android/tzdb/
+
+android-dump-tzdata: tzi.exe android-pull-tzdb
+       __XA_OVERRIDE_TIMEZONE_ID__=America/New_York ANDROID_ROOT=`pwd` ANDROID_DATA=`pwd` mono --debug tzi.exe -o android/tzdata
index 637d0c400dffd8384193b9dd29ed72f867654d6c..37f21464dcfc9067d489e354a70b857907755364 100644 (file)
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE)
 using System.Runtime.CompilerServices;
 using System.Runtime.Serialization;
 
 namespace System
 {
-       public sealed partial class TimeZoneInfo {
+#if NET_4_0 || !INSIDE_CORLIB
+       public
+#endif
+       sealed partial class TimeZoneInfo {
                [SerializableAttribute]
 #if MOBILE
        [TypeForwardedFrom (Consts.AssemblySystem_Core)]
index 079af3722d6cc9b4882304c15ee1a750aad7bc31..72285cc0dabadf6032c97d63bafac2674df74c65 100644 (file)
@@ -246,6 +246,7 @@ namespace System {
                                                                tzdataPath, offset, length, r, buffer.Length));
                        }
 
+                       TimeZoneInfo.DumpTimeZoneDataToFile (id, buffer);
                        return buffer;
                }
        }
@@ -581,21 +582,37 @@ namespace System {
                         * Compile:
                         *    mcs /debug+ /out:tzi.exe /unsafe "/d:INSIDE_CORLIB;MONODROID;NET_4_0;LIBC;SELF_TEST" ../corlib/System/AndroidPlatform.cs System/TimeZone*.cs ../../build/common/Consts.cs ../Mono.Options/Mono.Options/Options.cs
                         * Prep:
-                        *    mkdir -p usr/share/zoneinfo
-                        *    mkdir -p misc/zoneinfo/zoneinfo
+                        *    mkdir -p android/tzdb/usr/share/zoneinfo
+                        *    mkdir -p android/tzdb/misc/zoneinfo/zoneinfo
                         *    android_root=`adb shell echo '$ANDROID_ROOT' | tr -d "\r"`
                         *    android_data=`adb shell echo '$ANDROID_DATA' | tr -d "\r"`
-                        *    adb pull $android_root/usr/share/zoneinfo usr/share/zoneinfo
-                        *    adb pull $android_data/misc/zoneinfo/tzdata misc/zoneinfo
+                        *    adb pull $android_root/usr/share/zoneinfo   android/tzdb/usr/share/zoneinfo
+                        *    adb pull $android_data/misc/zoneinfo/tzdata android/tzdb/misc/zoneinfo
                         * Run:
+                        *    # Dump all timezone names
                         *    __XA_OVERRIDE_TIMEZONE_ID__=America/New_York ANDROID_ROOT=`pwd` ANDROID_DATA=`pwd` mono --debug tzi.exe --offset=1969-01-01
+                        *
+                        *    # Dump TimeZone data to files under path `tzdata`
+                        *    __XA_OVERRIDE_TIMEZONE_ID__=America/New_York ANDROID_ROOT=`pwd` ANDROID_DATA=`pwd` mono --debug tzi.exe -o android/tzdata
+                        *
+                        *    # Dump TimeZone rules for specific timezone data (as dumped above)
+                        *    mono tzi.exe --offset=2012-10-24 -i=tzdata/Asia/Amman
                         */
                        static void Main (string[] args)
                        {
                                DateTime? offset           = null;
                                Func<IAndroidTimeZoneDB> c = () => GetDefaultTimeZoneDB ();
+                               bool dump_rules            = false;
                                Mono.Options.OptionSet p = null;
                                p = new Mono.Options.OptionSet () {
+                                       { "i=",
+                                         "TimeZone data {FILE} to parse and dump",
+                                         v => DumpTimeZoneFile (v, offset)
+                                       },
+                                       { "o=",
+                                         "Write TimeZone data files to {PATH}",
+                                         v => TimeZoneInfo.TimeZoneDataExportPath = v
+                                       },
                                        { "T=", "Create AndroidTzData from {PATH}.", v => {
                                                        c = () => new AndroidTzData (v);
                                        } },
@@ -606,6 +623,9 @@ namespace System {
                                                offset = DateTime.Parse (v);
                                                Console.WriteLine ("Using DateTime Offset: {0}", offset);
                                        } },
+                                       { "R|dump-rules",
+                                         "Show timezone info offset for DateTime {OFFSET}.",
+                                         v => dump_rules = v != null },
                                        { "help", "Show this message and exit", v => {
                                                        p.WriteOptionDescriptions (Console.Out);
                                                        Environment.Exit (0);
@@ -623,6 +643,9 @@ namespace System {
                                                        if (offset.HasValue) {
                                                                Console.Write ("From Offset: {0}", zone.GetUtcOffset (offset.Value));
                                                        }
+                                                       if (dump_rules) {
+                                                               WriteZoneRules (zone);
+                                                       }
                                                }
                                                else {
                                                        Console.Write (" ERROR:null");
@@ -634,6 +657,53 @@ namespace System {
                                        Console.WriteLine ();
                                }
                        }
+
+                       static void WriteZoneRules (TimeZoneInfo zone)
+                       {
+                               var rules = zone.GetAdjustmentRules ();
+                               for (int i = 0; i < rules.Length; ++i) {
+                                       var rule = rules [i];
+                                       Console.WriteLine ();
+                                       Console.Write ("\tAdjustmentRules[{0,3}]: DaylightDelta={1}; DateStart={2:yyyy-MM}; DateEnd={3:yyyy-MM}; DaylightTransitionStart={4:D2}-{5:D2}T{6}; DaylightTransitionEnd={7:D2}-{8:D2}T{9}",
+                                               i,
+                                               rule.DaylightDelta,
+                                               rule.DateStart, rule.DateEnd,
+                                               rule.DaylightTransitionStart.Month, rule.DaylightTransitionStart.Day, rule.DaylightTransitionStart.TimeOfDay.TimeOfDay,
+                                               rule.DaylightTransitionEnd.Month, rule.DaylightTransitionEnd.Day, rule.DaylightTransitionEnd.TimeOfDay.TimeOfDay);
+                               }
+                       }
+
+                       static void DumpTimeZoneFile (string path, DateTime? time)
+                       {
+                               var buffer = File.ReadAllBytes (path);
+                               var zone = ParseTZBuffer (path, buffer, buffer.Length);
+                               Console.Write ("Rules for: {0}", path);
+                               WriteZoneRules (zone);
+                               Console.WriteLine ();
+                               if (time.HasValue) {
+                                       var offset = zone.GetUtcOffset (time.Value);
+                                       var isDst  = zone.IsDaylightSavingTime (time.Value);
+                                       Console.WriteLine ("\tDate({0}): Offset({1}) IsDST({2})", time.Value, offset, isDst);
+                               }
+                       }
+#endif
+               }
+
+#if SELF_TEST
+               static string TimeZoneDataExportPath;
+#endif
+
+               internal static void DumpTimeZoneDataToFile (string id, byte[] buffer)
+               {
+#if SELF_TEST
+                       int p = id.LastIndexOf ('/');
+                       var o = Path.Combine (TimeZoneDataExportPath,
+                                       p >= 0 ? id.Substring (0, p) : id);
+                       if (p >= 0)
+                               o = Path.Combine (o, id.Substring (p+1));
+                       Directory.CreateDirectory (Path.GetDirectoryName (o));
+                       using (var f = File.OpenWrite (o))
+                               f.Write (buffer, 0, buffer.Length);
 #endif
                }
        }
index 22aa38c5fa62f95c7328adc53b07c98804f25225..3a7da39ec7fe52baad83a1d0c5543e9a3658787c 100644 (file)
@@ -24,7 +24,7 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE)
 
 using System.Collections.Generic;
 using System.Globalization;
@@ -33,7 +33,10 @@ using System.Text;
 
 namespace System
 {
-       public partial class TimeZoneInfo
+#if NET_4_0 || !INSIDE_CORLIB
+       public
+#endif
+       partial class TimeZoneInfo
        {
                public static TimeZoneInfo FromSerializedString (string source)
                {
index d57df150f0554bb1d318dd787d2b71225cc726f6..719bb9d51f382c4be9c8277ac17126df2ec8502c 100644 (file)
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE)
 
 using System.Runtime.CompilerServices;
 using System.Runtime.Serialization;
 
 namespace System
 {
-       public sealed partial class TimeZoneInfo 
+#if NET_4_0 || !INSIDE_CORLIB
+       public
+#endif
+       sealed partial class TimeZoneInfo
        {
                [SerializableAttribute]
 #if MOBILE
index 9994b125c79a47e7e8d4b501a477817cad94d4e7..f6fa19c0d34e182fd43b44a98bfddb524e98cb96 100644 (file)
@@ -35,7 +35,7 @@ using System.Threading;
 
 [assembly:TypeForwardedTo (typeof(TimeZoneInfo))]
 
-#elif (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE))
+#elif INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE)
 
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
@@ -57,7 +57,10 @@ namespace System
        [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)]
 #endif
        [SerializableAttribute]
-       public sealed partial class TimeZoneInfo : IEquatable<TimeZoneInfo>, ISerializable, IDeserializationCallback
+#if NET_4_0 || !INSIDE_CORLIB
+       public
+#endif
+       sealed partial class TimeZoneInfo : IEquatable<TimeZoneInfo>, ISerializable, IDeserializationCallback
        {
                TimeSpan baseUtcOffset;
                public TimeSpan BaseUtcOffset {
@@ -100,6 +103,11 @@ namespace System
                        }
                }
 
+               /*
+                       TimeZone transitions are stored when there is a change on the base offset.
+               */
+               private List<KeyValuePair<DateTime, TimeType>> transitions;
+
                static TimeZoneInfo CreateLocal ()
                {
 #if MONODROID
@@ -109,6 +117,17 @@ namespace System
                                return BuildFromStream ("Local", stream);
                        }
 #elif LIBC
+                       var tz = Environment.GetEnvironmentVariable ("TZ");
+                       if (tz != null) {
+                               if (tz == String.Empty)
+                                       return Utc;
+                               try {
+                                       return FindSystemTimeZoneByFileName (tz, Path.Combine (TimeZoneDirectory, tz));
+                               } catch {
+                                       return Utc;
+                               }
+                       }
+
                        try {
                                return FindSystemTimeZoneByFileName ("Local", "/etc/localtime");        
                        } catch {
@@ -332,8 +351,7 @@ namespace System
                        if (dateTime.Kind == DateTimeKind.Utc)
                                return dateTime;
 
-                       //FIXME: do not rely on DateTime implementation !
-                       return DateTime.SpecifyKind (dateTime.ToUniversalTime (), DateTimeKind.Utc);
+                       return ConvertTimeToUtc (dateTime, TimeZoneInfo.Local);
                }
 
                public static DateTime ConvertTimeToUtc (DateTime dateTime, TimeZoneInfo sourceTimeZone)
@@ -350,15 +368,9 @@ namespace System
                        if (sourceTimeZone.IsInvalidTime (dateTime))
                                throw new ArgumentException ("dateTime parameter is an invalid time");
 
-                       if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone == TimeZoneInfo.Utc)
-                               return dateTime;
-
                        if (dateTime.Kind == DateTimeKind.Utc)
                                return dateTime;
 
-                       if (dateTime.Kind == DateTimeKind.Local)
-                               return ConvertTimeToUtc (dateTime);
-
                        if (sourceTimeZone.IsAmbiguousTime (dateTime) || !sourceTimeZone.IsDaylightSavingTime (dateTime))
                                return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc);
                        else {
@@ -684,13 +696,8 @@ namespace System
 
                public TimeSpan GetUtcOffset (DateTime dateTime)
                {
-                       if (IsDaylightSavingTime (dateTime)) {
-                               AdjustmentRule rule = GetApplicableRule (dateTime);
-                               if (rule != null)
-                                       return BaseUtcOffset + rule.DaylightDelta;
-                       }
-                       
-                       return BaseUtcOffset;
+                       bool isDST;
+                       return GetUtcOffset (dateTime, out isDST);
                }
 
                public TimeSpan GetUtcOffset (DateTimeOffset dateTimeOffset)
@@ -698,6 +705,82 @@ namespace System
                        throw new NotImplementedException ();
                }
 
+               private TimeSpan GetUtcOffset (DateTime dateTime, out bool isDST)
+               {
+                       isDST = false;
+
+                       TimeZoneInfo tz = this;
+                       if (dateTime.Kind == DateTimeKind.Utc)
+                               tz = TimeZoneInfo.Utc;
+
+                       if (dateTime.Kind == DateTimeKind.Local)
+                               tz = TimeZoneInfo.Local;
+
+                       bool isTzDst;
+                       var tzOffset = GetUtcOffset (dateTime, tz, out isTzDst);
+
+                       if (tz == this) {
+                               isDST = isTzDst;
+                               return tzOffset;
+                       }
+
+                       var utcTicks = dateTime.Ticks - tzOffset.Ticks;
+                       if (utcTicks < 0 || utcTicks > DateTime.MaxValue.Ticks)
+                               return BaseUtcOffset;
+
+                       var utcDateTime = new DateTime (utcTicks, DateTimeKind.Utc);
+
+                       return GetUtcOffset (utcDateTime, this, out isDST);
+               }
+
+               private static TimeSpan GetUtcOffset (DateTime dateTime, TimeZoneInfo tz, out bool isDST)
+               {
+                       if (dateTime.Kind == DateTimeKind.Local && tz != TimeZoneInfo.Local)
+                               throw new Exception ();
+
+                       isDST = false;
+
+                       if (tz == TimeZoneInfo.Utc)
+                               return TimeSpan.Zero;
+
+                       TimeSpan offset;
+                       if (tz.TryGetTransitionOffset(dateTime, out offset, out isDST))
+                               return offset;
+
+                       if (dateTime.Kind == DateTimeKind.Utc) {
+                               var utcRule = tz.GetApplicableRule (dateTime);
+                               if (utcRule != null && tz.IsInDST (utcRule, dateTime)) {
+                                       isDST = true;
+                                       return tz.BaseUtcOffset + utcRule.DaylightDelta;
+                               }
+
+                               return tz.BaseUtcOffset;
+                       }
+
+                       var stdTicks = dateTime.Ticks - tz.BaseUtcOffset.Ticks;
+                       if (stdTicks < 0 || stdTicks > DateTime.MaxValue.Ticks)
+                               return tz.BaseUtcOffset;
+
+                       var stdUtcDateTime = new DateTime (stdTicks, DateTimeKind.Utc);
+                       var tzRule = tz.GetApplicableRule (stdUtcDateTime);
+
+                       DateTime dstUtcDateTime = DateTime.MinValue;
+                       if (tzRule != null) {
+                               var dstTicks = stdUtcDateTime.Ticks - tzRule.DaylightDelta.Ticks;
+                               if (dstTicks < 0 || dstTicks > DateTime.MaxValue.Ticks)
+                                       return tz.BaseUtcOffset;
+
+                               dstUtcDateTime = new DateTime (dstTicks, DateTimeKind.Utc);
+                       }
+
+                       if (tzRule != null && tz.IsInDST (tzRule, stdUtcDateTime) && tz.IsInDST (tzRule, dstUtcDateTime)) {
+                               isDST = true;
+                               return tz.BaseUtcOffset + tzRule.DaylightDelta;
+                       }
+
+                       return tz.BaseUtcOffset;
+               }
+
                public bool HasSameRules (TimeZoneInfo other)
                {
                        if (other == null)
@@ -752,6 +835,16 @@ namespace System
                        throw new NotImplementedException ();
                }
 
+               private bool IsInDST (AdjustmentRule rule, DateTime dateTime)
+               {
+                       // Check whether we're in the dateTime year's DST period
+                       if (IsInDSTForYear (rule, dateTime, dateTime.Year))
+                               return true;
+
+                       // We might be in the dateTime previous year's DST period
+                       return IsInDSTForYear (rule, dateTime, dateTime.Year - 1);
+               }
+
                bool IsInDSTForYear (AdjustmentRule rule, DateTime dateTime, int year)
                {
                        DateTime DST_start = TransitionPoint (rule.DaylightTransitionStart, year);
@@ -774,25 +867,11 @@ namespace System
                        
                        if (!SupportsDaylightSavingTime)
                                return false;
-                       
-                       //FIXME: do not rely on DateTime implementation !
-                       if ((dateTime.Kind == DateTimeKind.Local || dateTime.Kind == DateTimeKind.Unspecified) && this == TimeZoneInfo.Local)
-                               return dateTime.IsDaylightSavingTime ();
-                       
-                       //FIXME: do not rely on DateTime implementation !
-                       if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Utc)
-                               return IsDaylightSavingTime (DateTime.SpecifyKind (dateTime.ToUniversalTime (), DateTimeKind.Utc));
-                       
-                       AdjustmentRule rule = GetApplicableRule (dateTime.Date);
-                       if (rule == null)
-                               return false;
 
-                       // Check whether we're in the dateTime year's DST period
-                       if (IsInDSTForYear (rule, dateTime, dateTime.Year))
-                               return true;
+                       bool isDst;
+                       GetUtcOffset (dateTime, out isDst);
 
-                       // We might be in the dateTime previous year's DST period
-                       return IsInDSTForYear (rule, dateTime, dateTime.Year - 1);
+                       return isDst;
                }
 
                public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset)
@@ -969,6 +1048,40 @@ namespace System
                        return null;
                }
 
+               private bool TryGetTransitionOffset (DateTime dateTime, out TimeSpan offset,out bool isDst)
+               {
+                       offset = BaseUtcOffset;
+                       isDst = false;
+
+                       if (transitions == null)
+                               return false;
+
+                       //Transitions are always in standard time
+                       DateTime date = dateTime;
+
+                       if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local)
+                               date = date.ToUniversalTime () + BaseUtcOffset;
+
+                       if (dateTime.Kind == DateTimeKind.Utc && this != TimeZoneInfo.Utc)
+                               date = date + BaseUtcOffset;
+
+                       for (var i =  transitions.Count - 1; i >= 0; i--) {
+                               var pair = transitions [i];
+                               DateTime ttime = pair.Key;
+                               TimeType ttype = pair.Value;
+
+                               if (ttime > date)
+                                       continue;
+
+                               offset =  new TimeSpan (0, 0, ttype.Offset);
+                               isDst = ttype.IsDst;
+
+                               return true;
+                       }
+
+                       return false;
+               }
+
                private static DateTime TransitionPoint (TransitionTime transition, int year)
                {
                        if (transition.IsFixedDateRule)
@@ -1059,6 +1172,7 @@ namespace System
                        bool dst_observed = false;
                        DateTime dst_start = DateTime.MinValue;
                        List<AdjustmentRule> adjustmentRules = new List<AdjustmentRule> ();
+                       bool storeTransition = false;
 
                        for (int i = 0; i < transitions.Count; i++) {
                                var pair = transitions [i];
@@ -1069,6 +1183,8 @@ namespace System
                                                standardDisplayName = ttype.Name;
                                                daylightDisplayName = null;
                                                baseUtcOffset = new TimeSpan (0, 0, ttype.Offset);
+                                               if (adjustmentRules.Count > 0) // We ignore AdjustmentRules but store transitions.
+                                                       storeTransition = true;
                                                adjustmentRules = new List<AdjustmentRule> ();
                                                dst_observed = false;
                                        }
@@ -1110,16 +1226,22 @@ namespace System
                                }
                        }
 
-                       if (adjustmentRules.Count == 0) {
+                       TimeZoneInfo tz;
+                       if (adjustmentRules.Count == 0 && !storeTransition) {
                                TimeType t = (TimeType)time_types [0];
                                if (standardDisplayName == null) {
                                        standardDisplayName = t.Name;
                                        baseUtcOffset = new TimeSpan (0, 0, t.Offset);
                                }
-                               return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName);
+                               tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName);
                        } else {
-                               return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules).ToArray ());
+                               tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules).ToArray ());
                        }
+
+                       if (storeTransition)
+                               tz.transitions = transitions;
+
+                       return tz;
                }
 
                static Dictionary<int, string> ParseAbbreviations (byte [] buffer, int index, int count)
index f6ea66e98c69321b32c060c184913b9fb3a832fe..c3972e747c17df0e79a2f83a92bac99c8667f98a 100644 (file)
@@ -232,7 +232,7 @@ namespace MonoTests.System
                                DateTime afterDST = new DateTime (2007, 10, 28, 2, 0, 0, DateTimeKind.Unspecified);
                                Assert.IsFalse (london.IsDaylightSavingTime (beforeDST), "Just before DST");
                                Assert.IsTrue (london.IsDaylightSavingTime (startDST), "the first seconds of DST");
-                               Assert.IsTrue (london.IsDaylightSavingTime (endDST), "The last seconds of DST");
+                               Assert.IsFalse (london.IsDaylightSavingTime (endDST), "The last seconds of DST");
                                Assert.IsFalse (london.IsDaylightSavingTime (afterDST), "Just after DST");
                        }
                
@@ -804,6 +804,143 @@ namespace MonoTests.System
                                Assert.IsTrue (london.Equals (deserialized));
                        }
                }
+
+               [TestFixture]
+               public class MultipleDaylightSavingTimeTests {
+                       private TimeZoneInfo cairo;
+                       private DateTime dst1Start;
+                       private DateTime dst1End;
+                       private DateTime dst2Start;
+                       private DateTime dst2End;
+
+                       private TimeSpan baseUtcOffset;
+                       private TimeSpan dstUtcOffset;
+                       private TimeSpan dstOffset;
+
+                       [SetUp]
+                       public void CreateTimeZones ()
+                       {
+                               /*
+                               From 1/1/2014 12:00:00 AM to 6/30/2014 12:00:00 AM
+                                       Delta: 01:00:00
+                                       Begins at 12:00 AM on 16 May
+                                       Ends at 1:00 AM on 29 June
+                               From 7/1/2014 12:00:00 AM to 12/31/2014 12:00:00 AM
+                                       Delta: 01:00:00
+                                       Begins at 12:00 AM on 29 July
+                                       Ends at 12:00 AM on 26 September
+                               */
+                               dst1Start = new DateTime (2014, 5, 16);
+                               dst1End = new DateTime (2014, 6, 29);
+                               dst2Start = new DateTime (2014, 7, 29);
+                               dst2End = new DateTime (2014, 9, 26);
+
+                               baseUtcOffset = new TimeSpan (2, 0, 0);
+                               dstUtcOffset = new TimeSpan (3, 0, 0);
+                               dstOffset = dstUtcOffset - baseUtcOffset;
+
+                               var rule1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
+                                       new DateTime (2014, 1, 1), new DateTime (2014, 6, 30), dstOffset,
+                                       CreateFixedDateRule (dst1Start), CreateFixedDateRule (dst1End));
+
+                               var rule2 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
+                                       new DateTime (2014, 7, 1), new DateTime (2014, 12, 31), dstOffset,
+                                       CreateFixedDateRule (dst2Start), CreateFixedDateRule (dst2End));
+
+                               cairo = TimeZoneInfo.CreateCustomTimeZone ("Africa/Cairo", baseUtcOffset, "Africa/Cairo", "EET", "EEST",
+                                       new [] {rule1, rule2});
+                       }
+
+                       private static TimeZoneInfo.TransitionTime CreateFixedDateRule (DateTime dateTime)
+                       {
+                               var time = new DateTime (dateTime.Ticks - dateTime.Date.Ticks);
+                               return TimeZoneInfo.TransitionTime.CreateFixedDateRule (time, dateTime.Month, dateTime.Day);
+                       }
+
+                       [Test]
+                       public void GetUtcOffset_FromUTC ()
+                       {
+                               var d = dst1Start.Add (-baseUtcOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst1End.Add (-baseUtcOffset-dstOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2Start.Add (-baseUtcOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2End.Add (-baseUtcOffset-dstOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+                       }
+
+                       [Test]
+                       public void GetUtcOffset_FromLocal ()
+                       {
+                               var d = dst1Start.Add (-baseUtcOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               d = d.ToLocalTime ();
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst1End.Add (-baseUtcOffset-dstOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               d = d.ToLocalTime ();
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2Start.Add (-baseUtcOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               d = d.ToLocalTime ();
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2End.Add (-baseUtcOffset-dstOffset);
+                               d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
+                               d = d.ToLocalTime ();
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+                       }
+
+                       [Test]
+                       public void GetUtcOffset_FromUnspecified ()
+                       {
+                               var d = dst1Start.Add (dstOffset);
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst1End.Add (-dstOffset);
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2Start.Add (dstOffset);
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+
+                               d = dst2End.Add (-dstOffset);
+                               Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
+                               Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
+                       }
+               }
        }
 }
 #endif
index 3022c52ab5b9220992a9a41a40f378ca5ea03aec..1e07337738e760ce5424006d4da07641621ae4e8 100644 (file)
@@ -50,6 +50,7 @@
     <Compile Include="Assembly\AssemblyInfo.cs" />\r
        <Compile Include="System.IdentityModel\CookieTransform.cs" />\r
     <Compile Include="System.IdentityModel\OpenObject.cs" />\r
+    <Compile Include="System.IdentityModel\SignatureVerificationFailedException.cs" />\r
     <Compile Include="System.IdentityModel.Claims\Claim.cs" />\r
     <Compile Include="System.IdentityModel.Claims\ClaimSet.cs" />\r
     <Compile Include="System.IdentityModel.Claims\ClaimTypes.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\SecurityToken.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\SecurityTokenDescriptor.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\SecurityTokenException.cs" />\r
-       <Compile Include="System.IdentityModel.Tokens\SecurityTokenHandler.cs" />\r
+    <Compile Include="System.IdentityModel.Tokens\SecurityTokenExpiredException.cs" />\r
+    <Compile Include="System.IdentityModel.Tokens\SecurityTokenHandler.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\SecurityTokenHandlerCollection.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\SecurityTokenHandlerConfiguration.cs" />\r
+    <Compile Include="System.IdentityModel.Tokens\SecurityTokenNotYetValidException.cs" />\r
+    <Compile Include="System.IdentityModel.Tokens\SecurityTokenReplayDetectedException.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\SecurityTokenTypes.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\SecurityTokenValidationException.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\SessionSecurityToken.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\X509SubjectKeyIdentifierClause.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\X509ThumbprintKeyIdentifierClause.cs" />\r
     <Compile Include="System.IdentityModel.Tokens\X509WindowsSecurityToken.cs" />\r
-    <Compile Include="System.Security.Claims\AuthenticationTypes.cs" />\r    <Compile Include="System.ServiceModel.Security\X509CertificateValidationMode.cs" />\r
+    <Compile Include="System.Security.Claims\AuthenticationTypes.cs" />\r
+    <Compile Include="System.ServiceModel.Security\X509CertificateValidationMode.cs" />\r
   </ItemGroup>\r
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
        Other similar extension points exist, see Microsoft.Common.targets.\r
   </Target>\r
   -->\r
   <PropertyGroup>\r
-    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
-
-    </PreBuildEvent>
-    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">
-
-    </PreBuildEvent>
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">\r
+\r
+    </PreBuildEvent>\r
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">\r
+\r
+    </PreBuildEvent>\r
+\r
+    <PostBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">\r
+\r
+    </PostBuildEvent>\r
+    <PostBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">\r
 \r
-    <PostBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
-
-    </PostBuildEvent>
-    <PostBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">
-
     </PostBuildEvent>\r
   </PropertyGroup>\r
   <ItemGroup>\r
     <Folder Include="Properties\" />\r
   </ItemGroup>\r
 </Project>\r
-
+\r
diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenExpiredException.cs b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenExpiredException.cs
new file mode 100644 (file)
index 0000000..2f10c94
--- /dev/null
@@ -0,0 +1,54 @@
+//
+// SecurityTokenExpiredException.cs
+//
+// Author:
+//   Noesis Labs (Ryan.Melena@noesislabs.com)
+//
+// Copyright (C) 2014 Noesis Labs, LLC  https://noesislabs.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_4_5
+
+using System;
+using System.Runtime.Serialization;
+
+namespace System.IdentityModel.Tokens
+{
+       public class SecurityTokenExpiredException : SecurityTokenValidationException
+       {
+               public SecurityTokenExpiredException()
+                       : base("ID4181: The security token has expired.")
+               { }
+
+               public SecurityTokenExpiredException(string message)
+                       : base(message)
+               { }
+
+               public SecurityTokenExpiredException(string message, Exception innerException)
+                       : base(message, innerException)
+               { }
+
+               public SecurityTokenExpiredException(SerializationInfo info, StreamingContext context)
+                       : base(info, context)
+               { }
+       }
+}
+#endif
diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenNotYetValidException.cs b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenNotYetValidException.cs
new file mode 100644 (file)
index 0000000..9f15b7b
--- /dev/null
@@ -0,0 +1,54 @@
+//
+// SecurityTokenNotYetValidException.cs
+//
+// Author:
+//   Noesis Labs (Ryan.Melena@noesislabs.com)
+//
+// Copyright (C) 2014 Noesis Labs, LLC  https://noesislabs.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_4_5
+
+using System;
+using System.Runtime.Serialization;
+
+namespace System.IdentityModel.Tokens
+{
+       public class SecurityTokenNotYetValidException : SecurityTokenValidationException
+       {
+               public SecurityTokenNotYetValidException()
+                       : base("ID4182: The security token is not valid yet.")
+               { }
+
+               public SecurityTokenNotYetValidException(string message)
+                       : base(message)
+               { }
+
+               public SecurityTokenNotYetValidException(string message, Exception innerException)
+                       : base(message, innerException)
+               { }
+
+               public SecurityTokenNotYetValidException(SerializationInfo info, StreamingContext context)
+                       : base(info, context)
+               { }
+       }
+}
+#endif
diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenReplayDetectedException.cs b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenReplayDetectedException.cs
new file mode 100644 (file)
index 0000000..eb4a786
--- /dev/null
@@ -0,0 +1,54 @@
+//
+// SecurityTokenReplayDetectedException.cs
+//
+// Author:
+//   Noesis Labs (Ryan.Melena@noesislabs.com)
+//
+// Copyright (C) 2014 Noesis Labs, LLC  https://noesislabs.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_4_5
+
+using System;
+using System.Runtime.Serialization;
+
+namespace System.IdentityModel.Tokens
+{
+       public class SecurityTokenReplayDetectedException : SecurityTokenValidationException
+       {
+               public SecurityTokenReplayDetectedException()
+                       : base("ID1070: Replay has been detected for a SecurityToken.")
+               { }
+
+               public SecurityTokenReplayDetectedException(string message)
+                       : base(message)
+               { }
+
+               public SecurityTokenReplayDetectedException(string message, Exception innerException)
+                       : base(message, innerException)
+               { }
+
+               public SecurityTokenReplayDetectedException(SerializationInfo info, StreamingContext context)
+                       : base(info, context)
+               { }
+       }
+}
+#endif
index 2c86355259a44a1e3fb982560175c28fe6597538..4d705d24d5794a9bb090e62ad31cf76312c4c1e0 100755 (executable)
@@ -3,6 +3,7 @@
 Assembly/AssemblyInfo.cs
 System.IdentityModel/CookieTransform.cs
 System.IdentityModel/OpenObject.cs
+System.IdentityModel/SignatureVerificationFailedException.cs
 System.IdentityModel.Claims/Claim.cs
 System.IdentityModel.Claims/ClaimSet.cs
 System.IdentityModel.Claims/ClaimTypes.cs
@@ -100,9 +101,12 @@ System.IdentityModel.Tokens/SecurityKeyUsage.cs
 System.IdentityModel.Tokens/SecurityToken.cs
 System.IdentityModel.Tokens/SecurityTokenDescriptor.cs
 System.IdentityModel.Tokens/SecurityTokenException.cs
+System.IdentityModel.Tokens/SecurityTokenExpiredException.cs
 System.IdentityModel.Tokens/SecurityTokenHandler.cs
 System.IdentityModel.Tokens/SecurityTokenHandlerCollection.cs
 System.IdentityModel.Tokens/SecurityTokenHandlerConfiguration.cs
+System.IdentityModel.Tokens/SecurityTokenNotYetValidException.cs
+System.IdentityModel.Tokens/SecurityTokenReplayDetectedException.cs
 System.IdentityModel.Tokens/SecurityTokenTypes.cs
 System.IdentityModel.Tokens/SecurityTokenValidationException.cs
 System.IdentityModel.Tokens/SessionSecurityToken.cs
@@ -124,4 +128,4 @@ System.IdentityModel.Tokens/X509SubjectKeyIdentifierClause.cs
 System.IdentityModel.Tokens/X509ThumbprintKeyIdentifierClause.cs
 System.IdentityModel.Tokens/X509WindowsSecurityToken.cs
 System.Security.Claims/AuthenticationTypes.cs
-System.ServiceModel.Security/X509CertificateValidationMode.cs
\ No newline at end of file
+System.ServiceModel.Security/X509CertificateValidationMode.cs
diff --git a/mcs/class/System.IdentityModel/System.IdentityModel/SignatureVerificationFailedException.cs b/mcs/class/System.IdentityModel/System.IdentityModel/SignatureVerificationFailedException.cs
new file mode 100644 (file)
index 0000000..2e1e711
--- /dev/null
@@ -0,0 +1,54 @@
+//
+// SignatureVerificationFailedException.cs
+//
+// Author:
+//   Noesis Labs (Ryan.Melena@noesislabs.com)
+//
+// Copyright (C) 2014 Noesis Labs, LLC  https://noesislabs.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_4_5
+
+using System;
+using System.Runtime.Serialization;
+
+namespace System.IdentityModel
+{
+       public class SignatureVerificationFailedException : Exception
+       {
+               public SignatureVerificationFailedException()
+                       : base("ID4038: Signature verification failed.")
+               { }
+
+               public SignatureVerificationFailedException(string message)
+                       : base(message)
+               { }
+
+               public SignatureVerificationFailedException(string message, Exception innerException)
+                       : base(message, innerException)
+               { }
+
+               public SignatureVerificationFailedException(SerializationInfo info, StreamingContext context)
+                       : base(info, context)
+               { }
+       }
+}
+#endif
index 22feb8530d7193050ee835f034ae9af5dd08beab..6581c0c1f77134541d3bf0dc5d542ce2b281e762 100644 (file)
@@ -183,10 +183,9 @@ namespace System.Web
                        return w.GetSection (sectionName);
                }
 
-               [MonoTODO]
                public override object GetService (Type serviceType)
                {
-                       throw new NotImplementedException ();
+                       return ((IServiceProvider)w).GetService (serviceType);
                }
 #if NET_4_0
                public override void RemapHandler (IHttpHandler handler)
index 3a31754b9499cd72e224c49210e2c2bba832b5ee..bf1d6f576aae614cb0cbdcb7175a7d5acd841fef 100644 (file)
@@ -138,7 +138,10 @@ namespace System.Web
 
 #if NET_4_5
                public virtual ReadEntityBodyMode ReadEntityBodyMode { get { NotImplemented(); return ReadEntityBodyMode.Classic; } }
+
+               public virtual UnvalidatedRequestValuesBase Unvalidated { get { NotImplemented (); return null; } }
 #endif
+
                public virtual Uri Url { get { NotImplemented (); return null; } }
 
                public virtual Uri UrlReferrer { get { NotImplemented (); return null; } }
index dc5098a3becfa0c727fd9633984a414b75b5fef0..197a7abd1c41f85b70d12be013a3b6b96026537b 100644 (file)
@@ -208,6 +208,18 @@ namespace System.Web
                        get { return w.TotalBytes; }
                }
 
+#if NET_4_5
+               public override UnvalidatedRequestValuesBase Unvalidated { 
+                       get { return new UnvalidatedRequestValuesWrapper (w.Unvalidated); } 
+               }
+#endif
+
+#if NET_4_5
+               public override ReadEntityBodyMode ReadEntityBodyMode {
+                       get { return ReadEntityBodyMode.Classic; }
+               }
+#endif
+
                public override Uri Url {
                        get { return w.Url; }
                }
index 0a3aa6694dd392a73ce18b7fa3b90133822cc49b..2bf8ebd2f21cab505e43be196eec8eef63716be5 100644 (file)
@@ -39,6 +39,7 @@ using System.Security.Permissions;
 using System.Security.Principal;
 using System.Text;
 using System.Web.Caching;
+using System.Threading;
 
 #if NET_4_0
 using System.Web.Routing;
@@ -69,6 +70,10 @@ namespace System.Web
 
                public virtual string Charset { get { NotImplemented (); return null; } set { NotImplemented (); } }
 
+#if NET_4_5
+               public virtual CancellationToken ClientDisconnectedToken { get { NotImplemented (); return CancellationToken.None; } }
+#endif
+
                public virtual Encoding ContentEncoding { get { NotImplemented (); return null; } set { NotImplemented (); } }
 
                public virtual string ContentType { get { NotImplemented (); return null; } set { NotImplemented (); } }
@@ -105,6 +110,10 @@ namespace System.Web
 
                public virtual bool SuppressContent { get { NotImplemented (); return false; } set { NotImplemented (); } }
 
+#if NET_4_5
+               public virtual bool SuppressFormsAuthenticationRedirect { get { NotImplemented (); return false; } set { NotImplemented (); } }
+#endif
+
                public virtual bool TrySkipIisCustomErrors { get { NotImplemented (); return false; } set { NotImplemented (); } }
 
 
index eed3415cd1c1319b711c9a4e8bdadc7e5d7a09c4..adb5f74edd7796cba02135b17ef3bfb31265f6cb 100644 (file)
@@ -39,6 +39,7 @@ using System.Security.Permissions;
 using System.Security.Principal;
 using System.Text;
 using System.Web.Caching;
+using System.Threading;
 
 namespace System.Web
 {
@@ -82,6 +83,12 @@ namespace System.Web
                        set { w.Charset = value; }
                }
 
+#if NET_4_5
+               public override CancellationToken ClientDisconnectedToken {
+                       get { return CancellationToken.None; }
+               }
+#endif
+
                public override Encoding ContentEncoding {
                        get { return w.ContentEncoding; }
                        set { w.ContentEncoding = value; }
@@ -169,6 +176,13 @@ namespace System.Web
                        set { w.SuppressContent = value; }
                }
 
+#if NET_4_5
+               public override bool SuppressFormsAuthenticationRedirect {
+                       get { return w.SuppressFormsAuthenticationRedirect; }
+                       set { w.SuppressFormsAuthenticationRedirect = value; }
+               }
+#endif
+
                public override bool TrySkipIisCustomErrors {
                        get { return w.TrySkipIisCustomErrors; }
                        set { w.TrySkipIisCustomErrors = value; }
index 14a03b2f0dc9ce59f09f35a61986f6e4185c62d8..9095cb866d3d26f4980bfd635c4794a257342056 100644 (file)
@@ -204,7 +204,11 @@ namespace System.Web.Script.Serialization
                }
 
                public object Deserialize (string input, Type targetType) {
-                       return DeserializeObjectInternal (input);
+                       object obj = DeserializeObjectInternal (input);
+
+                       if (obj == null) return null;
+
+                       return ConvertToType (obj, targetType);
                }
 
                static object Evaluate (object value) {
index 995590eeb2ec6cf0c5370555a82f0e304a7babeb..8274ef9c3f88a317570f68ad49fbb51451551bdc 100644 (file)
@@ -415,6 +415,22 @@ namespace MonoTests.System.Web.Script.Serialization
                        //object oo = ser.DeserializeObject ("{value:'Purple\\r \\n monkey\\'s:\\tdishwasher'}");
                }
 
+               [Test]
+               public void TestDeserializeNonGenericOverload()
+               {
+                       JavaScriptSerializer ser = new JavaScriptSerializer();
+                       Assert.IsNull(ser.Deserialize("", typeof(X)));
+
+                       X s = new X();
+                       s.Init();
+                       string x = ser.Serialize(s);
+
+                       Assert.AreEqual("{\"z\":8,\"ch\":\"v\",\"ch_null\":null,\"str\":\"vwF59g\",\"b\":253,\"sb\":-48,\"sh\":-32740,\"ush\":65511,\"i\":-234235453,\"ui\":4294733061,\"l\":-9223372036854775780,\"ul\":18446744073709551612,\"f\":NaN,\"f1\":-Infinity,\"f2\":Infinity,\"f3\":-3.40282347E+38,\"f4\":3.40282347E+38,\"d\":NaN,\"d1\":-Infinity,\"d2\":Infinity,\"d3\":-1.7976931348623157E+308,\"d4\":1.7976931348623157E+308,\"de\":-1,\"de1\":0,\"de2\":1,\"de3\":-79228162514264337593543950335,\"de4\":79228162514264337593543950335,\"g\":\"000000ea-0002-0162-0102-030405060708\",\"nb\":null,\"dbn\":null,\"uri\":\"http://kostat@mainsoft/adfasdf/asdfasdf.aspx/asda/ads?a=b&c=d\",\"hash\":{\"mykey\":{\"BB\":10}},\"point\":{\"IsEmpty\":false,\"X\":150,\"Y\":150},\"MyEnum\":[1,10,345],\"MyEnum1\":[1,10,345],\"AA\":5,\"AA1\":[{\"BB\":10},{\"BB\":10}],\"BB\":18446744073709551610,\"YY\":[{\"BB\":10},{\"BB\":10}]}", x, "#A1");
+
+                       X n = ser.Deserialize(x, typeof(X)) as X;
+                       Assert.AreEqual(s, n, "#A2");
+               }
+
                [Test]
                public void TestDeserializeTypeResolver () 
                {
index 186581616b89908966da650eaaad8ec7960c37d1..0c32f1576479342a44fe1f050644ca62dcdee063 100644 (file)
     <Compile Include="System.Web\DefaultExceptionPageTemplate.cs" />\r
     <Compile Include="System.Web\DefaultHttpHandler.cs" />\r
     <Compile Include="System.Web\EndEventHandler.cs" />\r
+    <Compile Include="System.Web\EventHandlerTaskAsyncHelper.cs" />\r
     <Compile Include="System.Web\ExceptionPageTemplate.cs" />\r
     <Compile Include="System.Web\ExceptionPageTemplateFragment.cs" />\r
     <Compile Include="System.Web\ExceptionPageTemplateFragmentValue.cs" />\r
     <Compile Include="System.Web\HttpRuntime.cs" />\r
     <Compile Include="System.Web\HttpServerUtility.cs" />\r
     <Compile Include="System.Web\HttpStaticObjectsCollection.cs" />\r
+    <Compile Include="System.Web\HttpTaskAsyncHandler.cs" />\r
     <Compile Include="System.Web\HttpUnhandledException.cs" />\r
     <Compile Include="System.Web\HttpUtility.cs" />\r
     <Compile Include="System.Web\HttpValidationStatus.cs" />\r
     <Compile Include="System.Web\SiteMapResolveEventArgs.cs" />\r
     <Compile Include="System.Web\StaticFileHandler.cs" />\r
     <Compile Include="System.Web\StaticSiteMapProvider.cs" />\r
+    <Compile Include="System.Web\TaskAsyncResult.cs" />\r
+    <Compile Include="System.Web\TaskEventHandler.cs" />\r
     <Compile Include="System.Web\TempFileStream.cs" />\r
     <Compile Include="System.Web\TraceContext.cs" />\r
     <Compile Include="System.Web\TraceContextEventArgs.cs" />\r
index 5f49197e3f6a3919a03a6464f6544bf0a93af6e6..d4a107dec057d3a27022708ecb26b388513acc69 100644 (file)
     <Compile Include="System.Web\DefaultExceptionPageTemplate.cs" />\r
     <Compile Include="System.Web\DefaultHttpHandler.cs" />\r
     <Compile Include="System.Web\EndEventHandler.cs" />\r
+    <Compile Include="System.Web\EventHandlerTaskAsyncHelper.cs" />\r
     <Compile Include="System.Web\ExceptionPageTemplate.cs" />\r
     <Compile Include="System.Web\ExceptionPageTemplateFragment.cs" />\r
     <Compile Include="System.Web\ExceptionPageTemplateFragmentValue.cs" />\r
     <Compile Include="System.Web\HttpRuntime.cs" />\r
     <Compile Include="System.Web\HttpServerUtility.cs" />\r
     <Compile Include="System.Web\HttpStaticObjectsCollection.cs" />\r
+    <Compile Include="System.Web\HttpTaskAsyncHandler.cs" />\r
     <Compile Include="System.Web\HttpUnhandledException.cs" />\r
     <Compile Include="System.Web\HttpUtility.cs" />\r
     <Compile Include="System.Web\HttpValidationStatus.cs" />\r
     <Compile Include="System.Web\ProcessShutdownReason.cs" />\r
     <Compile Include="System.Web\ProcessStatus.cs" />\r
     <Compile Include="System.Web\QueueManager.cs" />\r
+    <Compile Include="System.Web\ReadEntityBodyMode.cs" />\r
     <Compile Include="System.Web\RequestNotification.cs" />\r
     <Compile Include="System.Web\RequestNotificationStatus.cs" />\r
     <Compile Include="System.Web\ServerVariablesCollection.cs" />\r
     <Compile Include="System.Web\SiteMapResolveEventArgs.cs" />\r
     <Compile Include="System.Web\StaticFileHandler.cs" />\r
     <Compile Include="System.Web\StaticSiteMapProvider.cs" />\r
+    <Compile Include="System.Web\TaskAsyncResult.cs" />\r
+    <Compile Include="System.Web\TaskEventHandler.cs" />\r
     <Compile Include="System.Web\TempFileStream.cs" />\r
     <Compile Include="System.Web\TraceContext.cs" />\r
     <Compile Include="System.Web\TraceContextEventArgs.cs" />\r
index 6db954a2f78dadd9c931bde1b5b7c2b9e2b61c3f..bb9302e4995e3de4be8508cd39637792c1662765 100644 (file)
     <Compile Include="Test\System.Web.Util\UrlUtilsTest.cs" />\r
     <Compile Include="Test\System.Web.Util\WorkItemCas.cs" />\r
     <Compile Include="Test\System.Web\AppBrowsersTest.cs" />\r
+    <Compile Include="Test\System.Web\EventHandlerTaskAsyncHelperTest.cs" />\r
     <Compile Include="Test\System.Web\HttpApplicationCas.cs" />\r
     <Compile Include="Test\System.Web\HttpApplicationStateCas.cs" />\r
     <Compile Include="Test\System.Web\HttpApplicationTest.cs" />\r
     <Compile Include="Test\System.Web\HttpServerUtilityCas.cs" />\r
     <Compile Include="Test\System.Web\HttpServerUtilityTest.cs" />\r
     <Compile Include="Test\System.Web\HttpStaticObjectsCollectionCas.cs" />\r
+    <Compile Include="Test\System.Web\HttpTaskAsyncHandlerTest.cs" />\r
     <Compile Include="Test\System.Web\HttpUnhandledExceptionCas.cs" />\r
     <Compile Include="Test\System.Web\HttpUtilityCas.cs" />\r
     <Compile Include="Test\System.Web\HttpUtilityTest.cs" />\r
     <Compile Include="Test\System.Web\SiteMapNodeTest.cs" />\r
     <Compile Include="Test\System.Web\SiteMapProviderTest.cs" />\r
     <Compile Include="Test\System.Web\StaticSiteMapProviderTest.cs" />\r
+    <Compile Include="Test\System.Web\TaskAsyncResultTest.cs" />\r
     <Compile Include="Test\System.Web\TraceContextCas.cs" />\r
     <Compile Include="Test\System.Web\TraceContextRecordTest.cs" />\r
     <Compile Include="Test\System.Web\VirtualPathUtilityTest.cs" />\r
index cab57fea2f2ff83ab4b858d4e5947ac9b7c4d058..54f07294e288065497427146caf1e1577fbbee1b 100644 (file)
@@ -180,6 +180,11 @@ namespace System.Web.Security
                        if (context.Response.StatusCode != 401 || context.Request.QueryString ["ReturnUrl"] != null)
                                return;
 
+#if NET_4_5
+                       if (context.Response.StatusCode == 401 && context.Response.SuppressFormsAuthenticationRedirect)
+                               return;
+#endif
+
                        string loginPage;
                        InitConfig (context);
 #if NET_2_0
diff --git a/mcs/class/System.Web/System.Web/EventHandlerTaskAsyncHelper.cs b/mcs/class/System.Web/System.Web/EventHandlerTaskAsyncHelper.cs
new file mode 100644 (file)
index 0000000..d80188b
--- /dev/null
@@ -0,0 +1,62 @@
+//
+// System.Web.EventHandlerTaskAsyncHelper.cs
+//
+// Author:
+//   Kornel Pal (kornelpal@gmail.com)
+//
+// Copyright (C) 2014 Kornel Pal
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Threading.Tasks;
+
+namespace System.Web
+{
+       public sealed class EventHandlerTaskAsyncHelper
+       {
+               readonly TaskEventHandler taskEventHandler;
+               readonly BeginEventHandler beginEventHandler;
+               static readonly EndEventHandler endEventHandler = TaskAsyncResult.Wait;
+
+               public BeginEventHandler BeginEventHandler {
+                       get { return beginEventHandler; }
+               }
+
+               public EndEventHandler EndEventHandler {
+                       get { return endEventHandler; }
+               }
+
+               public EventHandlerTaskAsyncHelper (TaskEventHandler handler)
+               {
+                       if (handler == null)
+                               throw new ArgumentNullException ("handler");
+
+                       taskEventHandler = handler;
+                       beginEventHandler = GetAsyncResult;
+               }
+
+               IAsyncResult GetAsyncResult (object sender, EventArgs e, AsyncCallback callback, object state)
+               {
+                       Task task = taskEventHandler (sender, e);
+                       return TaskAsyncResult.GetAsyncResult (task, callback, state);
+               }
+       }
+}
index a2dd750eff48c2cb49596be5b3919ce55551579e..6f845dbe10855aeeca7e54119f35d3b2abb604ed 100755 (executable)
@@ -80,13 +80,17 @@ namespace System.Web
                string unescaped_path;
                string original_path;
                string path_info;
+               string path_info_unvalidated;
                string raw_url;
+               string raw_url_unvalidated;
                WebROCollection all_params;
-               WebROCollection headers;
+               NameValueCollection headers;
+               WebROCollection headers_unvalidated;
                Stream input_stream;
                InputFilterStream input_filter;
                Stream filter;
                HttpCookieCollection cookies;
+               HttpCookieCollection cookies_unvalidated;
                string http_method;
 
                WebROCollection form;
@@ -440,17 +444,27 @@ namespace System.Web
                        }
                }
 
-               public HttpCookieCollection Cookies {
+               internal HttpCookieCollection CookiesNoValidation {
                        get {
-                               if (cookies == null) {
+                               if (cookies_unvalidated == null) {
                                        if (worker_request == null) {
-                                               cookies = new HttpCookieCollection ();
+                                               cookies_unvalidated = new HttpCookieCollection ();
                                        } else {
                                                string cookie_hv = worker_request.GetKnownRequestHeader (HttpWorkerRequest.HeaderCookie);
-                                               cookies = new HttpCookieCollection (cookie_hv);
+                                               cookies_unvalidated = new HttpCookieCollection (cookie_hv);
                                        }
                                }
 
+                               return cookies_unvalidated;
+                       }
+               }
+
+               public HttpCookieCollection Cookies {
+                       get {
+                               if (cookies == null) {
+                                       cookies = CookiesNoValidation;
+                               }
+
 #if TARGET_J2EE
                                // For J2EE portal support we emulate cookies using the session.
                                GetSessionCookiesForPortal (cookies);
@@ -737,10 +751,20 @@ namespace System.Web
                        }
                }
 
+               internal NameValueCollection HeadersNoValidation {
+                       get {
+                               if (headers_unvalidated == null) {
+                                       headers_unvalidated = new HeadersCollection (this);
+                               }
+                       
+                               return headers_unvalidated;
+                       }
+               }
+
                public NameValueCollection Headers {
                        get {
                                if (headers == null) {
-                                       headers = new HeadersCollection (this);
+                                       headers = HeadersNoValidation;
 #if NET_4_0
                                        if (validateRequestNewMode) {
                                                RequestValidator validator = RequestValidator.Current;
@@ -1226,12 +1250,23 @@ namespace System.Web
                        }
                }
 
+               internal string PathInfoNoValidation {
+                       get {
+                               if (path_info_unvalidated == null) {
+                                       if (worker_request == null)
+                                               return String.Empty;
+
+                                       path_info_unvalidated = worker_request.GetPathInfo () ?? String.Empty;
+                               }
+
+                               return path_info_unvalidated;
+                       }
+               }
+
                public string PathInfo {
                        get {
                                if (path_info == null) {
-                                       if (worker_request == null)
-                                               return String.Empty;
-                                       path_info = worker_request.GetPathInfo () ?? String.Empty;
+                                       path_info = PathInfoNoValidation;
 #if NET_4_0
                                        if (validateRequestNewMode) {
                                                RequestValidator validator = RequestValidator.Current;
@@ -1335,16 +1370,26 @@ namespace System.Web
                        }
                }
 
-               public string RawUrl {
+               internal string RawUrlUnvalidated {
                        get {
-                               if (raw_url == null) {
+                               if (raw_url_unvalidated == null) {
                                        if (worker_request != null)
-                                               raw_url = worker_request.GetRawUrl ();
+                                               raw_url_unvalidated = worker_request.GetRawUrl ();
                                        else
-                                               raw_url = UrlComponents.Path + UrlComponents.Query;
+                                               raw_url_unvalidated = UrlComponents.Path + UrlComponents.Query;
                                        
-                                       if (raw_url == null)
-                                               raw_url = String.Empty;
+                                       if (raw_url_unvalidated == null)
+                                               raw_url_unvalidated = String.Empty;
+                               }
+
+                               return raw_url_unvalidated;
+                       }
+               }
+
+               public string RawUrl {
+                       get {
+                               if (raw_url == null) {
+                                       raw_url = RawUrlUnvalidated;
 #if NET_4_0
                                        if (validateRequestNewMode) {
                                                RequestValidator validator = RequestValidator.Current;
@@ -1398,6 +1443,26 @@ namespace System.Web
                        }
                }
 
+#if NET_4_5
+               public UnvalidatedRequestValues Unvalidated { 
+                       get {
+                               var vals = new UnvalidatedRequestValues ();
+                               
+                               vals.Cookies = CookiesNoValidation;
+                               vals.Files = Files;
+                               vals.Form = FormUnvalidated;
+                               vals.Headers = HeadersNoValidation;
+                               vals.Path = PathNoValidation;
+                               vals.PathInfo = PathInfoNoValidation;
+                               vals.QueryString = QueryStringUnvalidated;
+                               vals.RawUrl = RawUrlUnvalidated;
+                               vals.Url = Url;
+                               
+                               return vals;
+                       }
+               }
+#endif
+
                public Uri Url {
                        get {
                                if (cached_url == null) {
index 65718e5cd9bc41494cc3ec01bc9f2e62c8d39309..4bd3380a8f856e32a4cf7fea7fc13886ce43bea7 100644 (file)
@@ -400,6 +400,13 @@ namespace System.Web
                        set;
                }
 
+#if NET_4_5
+               public bool SuppressFormsAuthenticationRedirect {
+                       get;
+                       set;
+               }
+#endif
+
                public bool TrySkipIisCustomErrors {
                        get;
                        set;
diff --git a/mcs/class/System.Web/System.Web/HttpTaskAsyncHandler.cs b/mcs/class/System.Web/System.Web/HttpTaskAsyncHandler.cs
new file mode 100644 (file)
index 0000000..9cdcf73
--- /dev/null
@@ -0,0 +1,59 @@
+//
+// System.Web.HttpTaskAsyncHandler.cs
+//
+// Author:
+//   Kornel Pal (kornelpal@gmail.com)
+//
+// Copyright (C) 2014 Kornel Pal
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.ComponentModel;
+using System.Threading.Tasks;
+
+namespace System.Web
+{
+       public abstract class HttpTaskAsyncHandler : IHttpAsyncHandler, IHttpHandler
+       {
+               public virtual bool IsReusable {
+                       get { return false; }
+               }
+
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public virtual void ProcessRequest (HttpContext context)
+               {
+                       throw new NotSupportedException ("This handler cannot be executed synchronously.");
+               }
+
+               public abstract Task ProcessRequestAsync (HttpContext context);
+
+               IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
+               {
+                       Task task = ProcessRequestAsync (context);
+                       return TaskAsyncResult.GetAsyncResult (task, cb, extraData);
+               }
+
+               void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
+               {
+                       TaskAsyncResult.Wait (result);
+               }
+       }
+}
diff --git a/mcs/class/System.Web/System.Web/TaskAsyncResult.cs b/mcs/class/System.Web/System.Web/TaskAsyncResult.cs
new file mode 100644 (file)
index 0000000..2e3bd27
--- /dev/null
@@ -0,0 +1,101 @@
+//
+// System.Web.TaskAsyncResult.cs
+//
+// Author:
+//   Kornel Pal (kornelpal@gmail.com)
+//
+// Copyright (C) 2014 Kornel Pal
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Web
+{
+       sealed class TaskAsyncResult : IAsyncResult
+       {
+               static readonly Action<Task, object> invokeCallback = InvokeCallback;
+               readonly Task task;
+               readonly AsyncCallback callback;
+
+               public object AsyncState {
+                       get;
+                       private set;
+               }
+
+               public WaitHandle AsyncWaitHandle {
+                       get { return ((IAsyncResult) task).AsyncWaitHandle; }
+               }
+
+               public bool CompletedSynchronously {
+                       get;
+                       private set;
+               }
+
+               public bool IsCompleted {
+                       get { return task.IsCompleted; }
+               }
+
+               TaskAsyncResult (Task task, AsyncCallback callback, object state)
+               {
+                       this.task = task;
+                       this.callback = callback;
+                       this.AsyncState = state;
+                       this.CompletedSynchronously = task.IsCompleted;
+               }
+
+               public static IAsyncResult GetAsyncResult (Task task, AsyncCallback callback, object state)
+               {
+                       if (task == null)
+                               return null;
+
+                       var result = new TaskAsyncResult (task, callback, state);
+
+                       if (callback != null) {
+                               if (result.CompletedSynchronously)
+                                       callback (result);
+                               else
+                                       task.ContinueWith (invokeCallback, result);
+                       }
+
+                       return result;
+               }
+
+               public static void Wait (IAsyncResult result)
+               {
+                       if (result == null)
+                               throw new ArgumentNullException ("result");
+
+                       var taskAsyncResult = result as TaskAsyncResult;
+                       if (taskAsyncResult == null)
+                               throw new ArgumentException ("The provided IAsyncResult is invalid.", "result");
+
+                       taskAsyncResult.task.GetAwaiter ().GetResult ();
+               }
+
+               static void InvokeCallback (Task task, object state)
+               {
+                       var result = (TaskAsyncResult) state;
+                       result.callback (result);
+               }
+       }
+}
diff --git a/mcs/class/System.Web/System.Web/TaskEventHandler.cs b/mcs/class/System.Web/System.Web/TaskEventHandler.cs
new file mode 100644 (file)
index 0000000..9fc7988
--- /dev/null
@@ -0,0 +1,34 @@
+//
+// System.Web.TaskEventHandler.cs
+//
+// Author:
+//   Kornel Pal (kornelpal@gmail.com)
+//
+// Copyright (C) 2014 Kornel Pal
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Threading.Tasks;
+
+namespace System.Web
+{
+       public delegate Task TaskEventHandler (object sender, EventArgs e);
+}
diff --git a/mcs/class/System.Web/System.Web/UnvalidatedRequestValues.cs b/mcs/class/System.Web/System.Web/UnvalidatedRequestValues.cs
new file mode 100644 (file)
index 0000000..707b67e
--- /dev/null
@@ -0,0 +1,66 @@
+//
+// System.Web.UnvalidatedRequestValues.cs
+//
+// Author:
+//   Mike Morano <mmorano@mikeandwan.us>
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Specialized;
+
+
+namespace System.Web {
+       public sealed class UnvalidatedRequestValues {
+               public HttpCookieCollection Cookies { get; internal set; }
+               public HttpFileCollection Files { get; internal set; }
+               public NameValueCollection Form { get; internal set; }
+               public NameValueCollection Headers { get; internal set; }
+               public string Path { get; internal set; }
+               public string PathInfo { get; internal set; }
+               public NameValueCollection QueryString { get; internal set; }
+               public string RawUrl { get; internal set; }
+               public Uri Url { get; internal set; }
+
+               public string this[string field] { 
+                       get {
+                               if (Form != null && Form [field] != null) {
+                                       return Form [field];
+                               }
+
+                               if (Cookies != null && Cookies [field] != null) {
+                                       return Cookies [field].Value;
+                               }
+
+                               if (QueryString != null && QueryString [field] != null) {
+                                       return QueryString [field];
+                               }
+
+                               // msdn docs also suggest the ServerVariables are inspected by this indexer,
+                               // but that seems odd given what is available in this class
+
+                               return null;
+                       }
+               }
+       }
+}
diff --git a/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesBase.cs b/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesBase.cs
new file mode 100644 (file)
index 0000000..9b54b07
--- /dev/null
@@ -0,0 +1,90 @@
+//
+// System.Web.UnvalidatedRequestValuesBase.cs
+//
+// Author:
+//   Mike Morano <mmorano@mikeandwan.us>
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Specialized;
+
+
+namespace System.Web {
+       public abstract class UnvalidatedRequestValuesBase {
+               void NotImplemented ()
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public virtual HttpCookieCollection Cookies 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual HttpFileCollection Files 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual NameValueCollection Form 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual NameValueCollection Headers 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual string this[string field] 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual string Path 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual string PathInfo 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual NameValueCollection QueryString 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual string RawUrl 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+
+               public virtual Uri Url 
+               { 
+                       get { NotImplemented (); return null; }
+               }
+       }
+}
diff --git a/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesWrapper.cs b/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesWrapper.cs
new file mode 100644 (file)
index 0000000..e6b6084
--- /dev/null
@@ -0,0 +1,92 @@
+//
+// System.Web.UnvalidatedRequestValuesWrapper.cs
+//
+// Author:
+//   Mike Morano <mmorano@mikeandwan.us>
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Specialized;
+
+
+namespace System.Web {
+       public class UnvalidatedRequestValuesWrapper : UnvalidatedRequestValuesBase {
+               UnvalidatedRequestValues rv;
+
+               public UnvalidatedRequestValuesWrapper (UnvalidatedRequestValues requestValues) 
+               {
+                       rv = requestValues;
+               }
+
+               public override HttpCookieCollection Cookies 
+               { 
+                       get { return rv.Cookies; }
+               }
+
+               public override HttpFileCollection Files 
+               { 
+                       get { return rv.Files; }
+               }
+
+               public override NameValueCollection Form 
+               { 
+                       get { return rv.Form; }
+               }
+
+               public override NameValueCollection Headers 
+               { 
+                       get { return rv.Headers; }
+               }
+
+               public override string this[string field] 
+               { 
+                       get { return rv[field]; }
+               }
+
+               public override string Path 
+               { 
+                       get { return rv.Path; }
+               }
+
+               public override string PathInfo 
+               { 
+                       get { return rv.PathInfo; }
+               }
+
+               public override NameValueCollection QueryString 
+               { 
+                       get { return rv.QueryString; }
+               }
+
+               public override string RawUrl 
+               { 
+                       get { return rv.RawUrl; }
+               }
+
+               public override Uri Url 
+               { 
+                       get { return rv.Url; }
+               }
+       }
+}
index fd634af76c39c9e156c831444a2d211eb323bdde..055791f7b9659870073879b2dbbab304212be8d4 100644 (file)
@@ -45,6 +45,7 @@ mainsoft/NunitWeb/NunitWeb/Tests/AuthorConverter.cs
 mainsoft/NunitWeb/NunitWeb/Tests/Book.cs
 mainsoft/NunitWeb/NunitWeb/Tests/BookType.cs
 System.Web/AppBrowsersTest.cs
+System.Web/EventHandlerTaskAsyncHelperTest.cs
 System.Web/HttpApplicationTest.cs
 System.Web/HttpBrowserCapabilitiesTest.cs
 System.Web/HttpCacheVaryByContentEncodingsTest.cs
@@ -58,10 +59,12 @@ System.Web/HttpRequestTest.cs
 System.Web/HttpResponseTest.cs
 System.Web/HttpRuntimeTest.cs
 System.Web/HttpServerUtilityTest.cs
+System.Web/HttpTaskAsyncHandlerTest.cs
 System.Web/HttpUtilityTest.cs
 System.Web/SiteMapProviderTest.cs
 System.Web/SiteMapNodeTest.cs
 System.Web/StaticSiteMapProviderTest.cs
+System.Web/TaskAsyncResultTest.cs
 System.Web/TraceContextRecordTest.cs
 System.Web.Compilation/BuildManagerTest.cs
 System.Web.Compilation/ClientBuildManagerParameterTest.cs
diff --git a/mcs/class/System.Web/Test/System.Web/EventHandlerTaskAsyncHelperTest.cs b/mcs/class/System.Web/Test/System.Web/EventHandlerTaskAsyncHelperTest.cs
new file mode 100644 (file)
index 0000000..9ae8aae
--- /dev/null
@@ -0,0 +1,118 @@
+//
+// MonoTests.System.Web.EventHandlerTaskAsyncHelperTest.cs
+//
+// Author:
+//   Kornel Pal (kornelpal@gmail.com)
+//
+// Copyright (C) 2014 Kornel Pal
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if NET_4_5
+
+using System;
+using System.Threading.Tasks;
+using System.Web;
+using NUnit.Framework;
+
+namespace MonoTests.System.Web
+{
+       [TestFixture]
+       public sealed class EventHandlerTaskAsyncHelperTest : TaskAsyncResultTest
+       {
+               EventHandlerTaskAsyncHelper helper;
+               object expectedSender;
+               EventArgs expectedEventArgs;
+
+               static Task DummyTaskEventHandler (object sender, EventArgs e)
+               {
+                       throw new AssertionException ("Should not be called.");
+               }
+
+               protected override void SetNullArguments ()
+               {
+                       expectedSender = null;
+                       expectedEventArgs = null;
+               }
+
+               protected override IAsyncResult GetAsyncResult (Func<Task> taskFactory, AsyncCallback callback, object state)
+               {
+                       Assert.IsNull (helper, "GetAsyncResult#A01");
+
+                       TaskEventHandler handler = (sender, e) => {
+                               Assert.AreSame (expectedSender, sender, "GetAsyncResult#A02");
+                               Assert.AreSame (expectedEventArgs, e, "GetAsyncResult#A03");
+
+                               return taskFactory ();
+                       };
+
+                       helper = new EventHandlerTaskAsyncHelper (handler);
+                       return helper.BeginEventHandler (expectedSender, expectedEventArgs, callback, state);
+               }
+
+               protected override void Wait (IAsyncResult result)
+               {
+                       Assert.IsNotNull (helper, "Wait#A01");
+
+                       helper.EndEventHandler (result);
+               }
+
+               protected override void TestSetUp ()
+               {
+                       base.TestSetUp ();
+
+                       helper = null;
+                       expectedSender = new object ();
+                       expectedEventArgs = new EventArgs ();
+               }
+
+               [Test]
+               public void Constructor ()
+               {
+                       var helper = new EventHandlerTaskAsyncHelper (DummyTaskEventHandler);
+               }
+
+               [Test]
+               [ExpectedException (typeof (ArgumentNullException))]
+               public void Constructor_NullHandler ()
+               {
+                       var helper = new EventHandlerTaskAsyncHelper (null);
+               }
+
+               [Test]
+               public void BeginEventHandler ()
+               {
+                       var helper = new EventHandlerTaskAsyncHelper (DummyTaskEventHandler);
+
+                       Assert.IsNotNull (helper.BeginEventHandler, "#A01");
+               }
+
+               [Test]
+               public void EndEventHandler ()
+               {
+                       var helper = new EventHandlerTaskAsyncHelper (DummyTaskEventHandler);
+
+                       Assert.IsNotNull (helper.EndEventHandler, "#A01");
+               }
+       }
+}
+
+#endif
diff --git a/mcs/class/System.Web/Test/System.Web/HttpTaskAsyncHandlerTest.cs b/mcs/class/System.Web/Test/System.Web/HttpTaskAsyncHandlerTest.cs
new file mode 100644 (file)
index 0000000..50afda1
--- /dev/null
@@ -0,0 +1,132 @@
+//
+// MonoTests.System.Web.HttpTaskAsyncHandlerTest.cs
+//
+// Author:
+//   Kornel Pal (kornelpal@gmail.com)
+//
+// Copyright (C) 2014 Kornel Pal
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if NET_4_5
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Web;
+using NUnit.Framework;
+
+namespace MonoTests.System.Web
+{
+       [TestFixture]
+       public sealed class HttpTaskAsyncHandlerTest : TaskAsyncResultTest
+       {
+               sealed class DummyHttpTaskAsyncHandler : HttpTaskAsyncHandler
+               {
+                       public DummyHttpTaskAsyncHandler ()
+                       {
+                       }
+
+                       public override Task ProcessRequestAsync (HttpContext context)
+                       {
+                               throw new AssertionException ("Should not be called.");
+                       }
+               }
+
+               sealed class TestHttpTaskAsyncHandler : HttpTaskAsyncHandler
+               {
+                       readonly Func<Task> taskFactory;
+                       readonly HttpContext expectedContext;
+
+                       public TestHttpTaskAsyncHandler (Func<Task> taskFactory, HttpContext expectedContext)
+                       {
+                               this.taskFactory = taskFactory;
+                               this.expectedContext = expectedContext;
+                       }
+
+                       public override Task ProcessRequestAsync (HttpContext context)
+                       {
+                               Assert.AreSame (expectedContext, context, "TestHttpTaskAsyncHandler#A01");
+
+                               return taskFactory ();
+                       }
+               }
+
+               IHttpAsyncHandler handler;
+               HttpContext expectedContext;
+
+               protected override void SetNullArguments ()
+               {
+                       expectedContext = null;
+               }
+
+               protected override IAsyncResult GetAsyncResult (Func<Task> taskFactory, AsyncCallback callback, object state)
+               {
+                       Assert.IsNull (handler, "GetAsyncResult#A01");
+
+                       handler = new TestHttpTaskAsyncHandler (taskFactory, expectedContext);
+                       return handler.BeginProcessRequest (expectedContext, callback, state);
+               }
+
+               protected override void Wait (IAsyncResult result)
+               {
+                       Assert.IsNotNull (handler, "Wait#A01");
+
+                       handler.EndProcessRequest (result);
+               }
+
+               protected override void TestSetUp ()
+               {
+                       base.TestSetUp ();
+
+                       handler = null;
+
+                       var request = new HttpRequest (string.Empty, "http://localhost/", string.Empty);
+                       var response = new HttpResponse (TextWriter.Null);
+                       expectedContext = new HttpContext (request, response);
+               }
+
+               [Test]
+               public void IsReusable ()
+               {
+                       var handler = new DummyHttpTaskAsyncHandler ();
+                       Assert.IsFalse (handler.IsReusable, "#A01");
+               }
+
+               [Test]
+               [ExpectedException (typeof (NotSupportedException))]
+               public void ProcessRequest ()
+               {
+                       var handler = new DummyHttpTaskAsyncHandler ();
+                       handler.ProcessRequest (expectedContext);
+               }
+
+               [Test]
+               [ExpectedException (typeof (NotSupportedException))]
+               public void ProcessRequest_NullContext ()
+               {
+                       var handler = new DummyHttpTaskAsyncHandler ();
+                       handler.ProcessRequest (null);
+               }
+       }
+}
+
+#endif
diff --git a/mcs/class/System.Web/Test/System.Web/TaskAsyncResultTest.cs b/mcs/class/System.Web/Test/System.Web/TaskAsyncResultTest.cs
new file mode 100644 (file)
index 0000000..301a298
--- /dev/null
@@ -0,0 +1,334 @@
+//
+// MonoTests.System.Web.TaskAsyncResultTest.cs
+//
+// Author:
+//   Kornel Pal (kornelpal@gmail.com)
+//
+// Copyright (C) 2014 Kornel Pal
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if NET_4_5
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace MonoTests.System.Web
+{
+       public abstract class TaskAsyncResultTest
+       {
+               sealed class TestException : Exception
+               {
+                       public TestException ()
+                               : base ("Test exception")
+                       {
+                       }
+               }
+
+               sealed class DummyAsyncResult : IAsyncResult
+               {
+                       public object AsyncState {
+                               get { throw new AssertionException ("Should not be called."); }
+                       }
+
+                       public WaitHandle AsyncWaitHandle {
+                               get { throw new AssertionException ("Should not be called."); }
+                       }
+
+                       public bool CompletedSynchronously {
+                               get { throw new AssertionException ("Should not be called."); }
+                       }
+
+                       public bool IsCompleted {
+                               get { throw new AssertionException ("Should not be called."); }
+                       }
+               }
+
+               int testThreadId;
+               int factoryCount;
+               int callbackCount;
+               object expectedState;
+               Exception expectedException;
+               TaskCompletionSource<object> taskCompletion;
+               TaskCompletionSource<object> callbackCompletion;
+               IAsyncResult taskAsyncResult;
+
+               static Task NullTaskFatory ()
+               {
+                       return null;
+               }
+
+               static Task CompletedTaskFatory ()
+               {
+                       return Task.FromResult<object> (null);
+               }
+
+               static Task FailingTaskFatory ()
+               {
+                       throw new TestException ();
+               }
+
+               void DummyCallback (IAsyncResult result)
+               {
+                       Interlocked.Increment (ref callbackCount);
+
+                       Assert.Fail ("Should not be called.");
+               }
+
+               void FailingCallback (IAsyncResult result)
+               {
+                       Interlocked.Increment (ref callbackCount);
+
+                       throw new TestException ();
+               }
+
+               protected abstract void SetNullArguments ();
+               protected abstract IAsyncResult GetAsyncResult (Func<Task> taskFactory, AsyncCallback callback, object state);
+               protected abstract void Wait (IAsyncResult result);
+
+               [SetUp]
+               protected virtual void TestSetUp ()
+               {
+                       testThreadId = Thread.CurrentThread.ManagedThreadId;
+                       factoryCount = 0;
+                       callbackCount = 0;
+                       expectedState = new object ();
+                       expectedException = null;
+                       taskCompletion = new TaskCompletionSource<object> ();
+                       callbackCompletion = new TaskCompletionSource<object> ();
+                       taskAsyncResult = null;
+               }
+
+               [Test]
+               public void Invoke_NullArguments ()
+               {
+                       SetNullArguments ();
+
+                       IAsyncResult result = GetAsyncResult (CompletedTaskFatory, null, null);
+                       Wait (result);
+               }
+
+               [Test]
+               public void Invoke_NullTask ()
+               {
+                       IAsyncResult result = GetAsyncResult (NullTaskFatory, DummyCallback, null);
+
+                       Assert.AreEqual (0, callbackCount, "#A01");
+                       Assert.IsNull (result, "#A02");
+               }
+
+               [Test]
+               [ExpectedException (typeof (TestException))]
+               public void Invoke_TaskFatoryException ()
+               {
+                       try {
+                               GetAsyncResult (FailingTaskFatory, DummyCallback, expectedState);
+                       } finally {
+                               Assert.AreEqual (0, callbackCount, "#A01");
+                       }
+               }
+
+               [Test]
+               [ExpectedException (typeof (TestException))]
+               public void Invoke_CallbackException ()
+               {
+                       try {
+                               GetAsyncResult (CompletedTaskFatory, FailingCallback, expectedState);
+                       } finally {
+                               Assert.AreEqual (1, callbackCount, "#A01");
+                       }
+               }
+
+               [Test]
+               [ExpectedException (typeof (ArgumentNullException))]
+               public void Invoke_NullResult ()
+               {
+                       GetAsyncResult (NullTaskFatory, DummyCallback, null);
+                       Wait (null);
+               }
+
+               [Test]
+               [ExpectedException (typeof (ArgumentException))]
+               public void Invoke_InvalidResult ()
+               {
+                       GetAsyncResult (NullTaskFatory, DummyCallback, null);
+                       Wait (new DummyAsyncResult ());
+               }
+
+               void SetTaskResult ()
+               {
+                       if (expectedException == null)
+                               taskCompletion.SetResult (null);
+                       else
+                               taskCompletion.SetException (expectedException);
+               }
+
+               void WaitTaskResult ()
+               {
+                       if (expectedException == null) {
+                               Wait (taskAsyncResult);
+                               return;
+                       }
+
+                       try {
+                               Wait (taskAsyncResult);
+
+                               Assert.Fail ("Expected exception was not thrown.");
+                       } catch (AssertionException) {
+                               throw;
+                       } catch (Exception ex) {
+                               Assert.AreSame (expectedException, ex, "WaitTaskResult#A01");
+                       }
+               }
+
+               [Test]
+               public void InvokeSync ()
+               {
+                       InvokeSyncCore ();
+               }
+
+               [Test]
+               public void InvokeSync_Failed ()
+               {
+                       expectedException = new TestException ();
+
+                       InvokeSyncCore ();
+               }
+
+               void InvokeSyncCore ()
+               {
+                       IAsyncResult result = GetAsyncResult (SyncTaskFatory, SyncCallback, expectedState);
+
+                       Assert.IsNotNull (result, "InvokeSyncCore#A01");
+                       Assert.AreSame (taskAsyncResult, result, "InvokeSyncCore#A02");
+
+                       WaitTaskResult ();
+
+                       Assert.AreEqual (1, factoryCount, "InvokeSyncCore#A03");
+                       Assert.AreEqual (1, callbackCount, "InvokeSyncCore#A04");
+               }
+
+               Task SyncTaskFatory ()
+               {
+                       Interlocked.Increment (ref factoryCount);
+
+                       Assert.AreEqual (testThreadId, Thread.CurrentThread.ManagedThreadId, "SyncTaskFatory#A01");
+
+                       SetTaskResult ();
+
+                       return taskCompletion.Task;
+               }
+
+               void SyncCallback (IAsyncResult result)
+               {
+                       Interlocked.Increment (ref callbackCount);
+
+                       Assert.AreEqual (testThreadId, Thread.CurrentThread.ManagedThreadId, "SyncCallback#A01");
+
+                       Assert.IsNotNull (result, "SyncCallback#A02");
+                       Assert.AreSame (expectedState, result.AsyncState, "SyncCallback#A03");
+                       Assert.IsTrue (result.IsCompleted, "SyncCallback#A04");
+                       Assert.IsTrue (result.CompletedSynchronously, "SyncCallback#A05");
+                       Assert.IsNotNull (result.AsyncWaitHandle, "SyncCallback#A06");
+                       Assert.IsTrue (result.AsyncWaitHandle.WaitOne (0), "SyncCallback#A07");
+
+                       taskAsyncResult = result;
+
+                       Assert.AreEqual (1, factoryCount, "SyncCallback#A08");
+                       Assert.AreEqual (1, callbackCount, "SyncCallback#A09");
+               }
+
+               [Test]
+               public void InvokeAsync ()
+               {
+                       InvokeAsyncCore ();
+               }
+
+               [Test]
+               public void InvokeAsync_Failed ()
+               {
+                       expectedException = new TestException ();
+
+                       InvokeAsyncCore ();
+               }
+
+               void InvokeAsyncCore ()
+               {
+                       IAsyncResult result = GetAsyncResult (AsyncTaskFatory, AsyncCallback, expectedState);
+
+                       Assert.IsNotNull (result, "InvokeAsyncCore#A01");
+                       Assert.AreSame (expectedState, result.AsyncState, "InvokeAsyncCore#A02");
+                       Assert.IsFalse (result.IsCompleted, "InvokeAsyncCore#A03");
+                       Assert.IsFalse (result.CompletedSynchronously, "InvokeAsyncCore#A04");
+                       Assert.IsNotNull (result.AsyncWaitHandle, "InvokeAsyncCore#A05");
+                       Assert.IsFalse (result.AsyncWaitHandle.WaitOne (0), "InvokeAsyncCore#A06");
+
+                       Assert.AreEqual (1, factoryCount, "InvokeAsyncCore#A07");
+                       Assert.AreEqual (0, callbackCount, "InvokeAsyncCore#A08");
+
+                       taskAsyncResult = result;
+
+                       SetTaskResult ();
+
+                       callbackCompletion.Task.GetAwaiter ().GetResult ();
+
+                       Assert.AreEqual (1, factoryCount, "InvokeAsyncCore#A09");
+                       Assert.AreEqual (1, callbackCount, "InvokeAsyncCore#A10");
+               }
+
+               Task AsyncTaskFatory ()
+               {
+                       Interlocked.Increment (ref factoryCount);
+
+                       Assert.AreEqual (testThreadId, Thread.CurrentThread.ManagedThreadId, "AsyncTaskFatory#A01");
+
+                       return taskCompletion.Task;
+               }
+
+               void AsyncCallback (IAsyncResult result)
+               {
+                       try {
+                               Interlocked.Increment (ref callbackCount);
+
+                               Assert.AreNotEqual (testThreadId, Thread.CurrentThread.ManagedThreadId, "AsyncCallback#A01");
+
+                               Assert.IsNotNull (result, "AsyncCallback#A02");
+                               Assert.AreSame (expectedState, result.AsyncState, "AsyncCallback#A03");
+                               Assert.IsTrue (result.IsCompleted, "AsyncCallback#A04");
+                               Assert.IsFalse (result.CompletedSynchronously, "AsyncCallback#A05");
+                               Assert.IsNotNull (result.AsyncWaitHandle, "AsyncCallback#A06");
+                               Assert.IsTrue (result.AsyncWaitHandle.WaitOne (0), "AsyncCallback#A07");
+
+                               Assert.AreSame (taskAsyncResult, result, "AsyncCallback#A08");
+
+                               WaitTaskResult ();
+
+                               callbackCompletion.TrySetResult (null);
+                       } catch (Exception ex) {
+                               callbackCompletion.TrySetException (ex);
+                       }
+               }
+       }
+}
+
+#endif
index 04c7cacd659e57694c2e908224d5291356a80a2e..ea8508f9110ba2d1688f5ea0feefd26d8dff0d4d 100644 (file)
@@ -1,5 +1,11 @@
 #include net_4_0_System.Web.dll.sources
 
+System.Web/EventHandlerTaskAsyncHelper.cs
+System.Web/HttpTaskAsyncHandler.cs
 System.Web/MimeMapping.cs
 System.Web/ReadEntityBodyMode.cs
-
+System.Web/UnvalidatedRequestValues.cs
+System.Web/UnvalidatedRequestValuesBase.cs
+System.Web/UnvalidatedRequestValuesWrapper.cs
+System.Web/TaskAsyncResult.cs
+System.Web/TaskEventHandler.cs
index 4d1db5db58f0cf5c08c2597d9d08e26f191a2751..c93d68b5f37fb4db426918a5b8c06726d160b3bb 100644 (file)
@@ -858,20 +858,7 @@ namespace System.Xml
                [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
                public virtual XmlNode ReadNode (XmlReader reader)
                {
-                       if (PreserveWhitespace)
-                               return ReadNodeCore (reader);
-                       XmlTextReader xtr = reader as XmlTextReader;
-                       if (xtr != null && xtr.WhitespaceHandling ==
-                           WhitespaceHandling.All) {
-                               try {
-                                       xtr.WhitespaceHandling = WhitespaceHandling.Significant;
-                                       return ReadNodeCore (reader);
-                               } finally {
-                                       xtr.WhitespaceHandling = WhitespaceHandling.All;
-                               }
-                       }
-                       else
-                               return ReadNodeCore (reader);
+                       return ReadNodeCore (reader);
                }
 
                XmlNode ReadNodeCore (XmlReader reader)
index d0898923255140ab6beee3ce26027b81790a5692..596a808aac3d46ded22129990ded45f8d1866381 100644 (file)
@@ -1433,5 +1433,43 @@ namespace MonoTests.System.Xml
                        Assert.IsFalse (reader.ReadAttributeValue(), "#4");
                        Assert.AreEqual (XmlNodeType.Text, reader.NodeType, "#5");
                }
+               
+               [Test]
+               public void Whitespaces ()
+               {
+                       const string xml = "<?xml version=\"1.0\"?><test> <foo name=\"Hello\"> <value>World</value> </foo> <foo name=\"Foo\"><value>Bar</value></foo></test>";
+                       var reader = new XmlTextReader (new StringReader (xml));
+                       //reader.WhitespaceHandling = WhitespaceHandling.All;
+
+                       reader.Read ();
+                       Assert.AreEqual  (XmlNodeType.XmlDeclaration, reader.NodeType, "#1a");
+                       reader.Read ();
+                       Assert.AreEqual (XmlNodeType.Element, reader.NodeType, "#1b");
+                       Assert.AreEqual ("test", reader.Name, "#1c");
+
+                       reader.Read ();
+                       if  (reader.NodeType == XmlNodeType.Whitespace)
+                               reader.Read ();
+
+                       Assert.AreEqual (XmlNodeType.Element, reader.NodeType, "#2a");
+                       Assert.AreEqual ("foo", reader.Name, "#2b");
+
+                       var doc = new XmlDocument ();
+                       //doc.PreserveWhitespace = true;
+                       doc.ReadNode (reader);
+
+                       Assert.AreEqual (XmlNodeType.Whitespace, reader.NodeType, "#3");
+
+                       reader.Read ();
+                       if  (reader.NodeType == XmlNodeType.Whitespace)
+                               reader.Read ();
+
+                       Assert.AreEqual (XmlNodeType.Element, reader.NodeType, "#4");
+                       Assert.AreEqual ("foo", reader.Name, "#4b");
+
+                       doc.ReadNode (reader);
+
+                       Assert.AreEqual (XmlNodeType.EndElement, reader.NodeType, "#5");
+               }
        }
 }
index 125f07805f9403f212fe5789357ff92bd0d02f33..0d293e53188b4f6155380ba838edf3443f1f7117 100644 (file)
@@ -183,7 +183,10 @@ namespace System.IO {
                internal SearchPattern2 Pattern {
                        get {
                                if (pattern == null) {
-                                       pattern = new SearchPattern2 (MangledFilter);
+                                       if (watcher.GetType () == typeof (KeventWatcher))
+                                               pattern = new SearchPattern2 (MangledFilter, true); //assume we want to ignore case (OS X)
+                                       else
+                                               pattern = new SearchPattern2 (MangledFilter);
                                }
                                return pattern;
                        }
@@ -372,52 +375,60 @@ namespace System.IO {
                        ErrorEvent,
                        RenameEvent
                }
-               private void RaiseEvent (Delegate ev, EventArgs arg, EventType evtype)
-               {
-                       if (ev == null)
-                               return;
-
-                       if (synchronizingObject == null) {
-                               switch (evtype) {
-                               case EventType.RenameEvent:
-                                       ((RenamedEventHandler)ev).BeginInvoke (this, (RenamedEventArgs) arg, null, null);
-                                       break;
-                               case EventType.ErrorEvent:
-                                       ((ErrorEventHandler)ev).BeginInvoke (this, (ErrorEventArgs) arg, null, null);
-                                       break;
-                               case EventType.FileSystemEvent:
-                                       ((FileSystemEventHandler)ev).BeginInvoke (this, (FileSystemEventArgs) arg, null, null);
-                                       break;
-                               }
-                               return;
-                       }
                        
-                       synchronizingObject.BeginInvoke (ev, new object [] {this, arg});
-               }
-
                protected void OnChanged (FileSystemEventArgs e)
                {
-                       RaiseEvent (Changed, e, EventType.FileSystemEvent);
+                       if (Changed == null)
+                               return;
+
+                       if (synchronizingObject == null)
+                               Changed (this, e);
+                       else
+                               synchronizingObject.BeginInvoke (Changed, new object[] { this, e });
                }
 
                protected void OnCreated (FileSystemEventArgs e)
                {
-                       RaiseEvent (Created, e, EventType.FileSystemEvent);
+                       if (Created == null)
+                               return;
+
+                       if (synchronizingObject == null)
+                               Created (this, e);
+                       else
+                               synchronizingObject.BeginInvoke (Created, new object[] { this, e });
                }
 
                protected void OnDeleted (FileSystemEventArgs e)
                {
-                       RaiseEvent (Deleted, e, EventType.FileSystemEvent);
+                       if (Deleted == null)
+                               return;
+
+                       if (synchronizingObject == null)
+                               Deleted (this, e);
+                       else
+                               synchronizingObject.BeginInvoke (Deleted, new object[] { this, e });
                }
 
-               protected void OnError (ErrorEventArgs e)
+               internal void OnError (ErrorEventArgs e)
                {
-                       RaiseEvent (Error, e, EventType.ErrorEvent);
+                       if (Error == null)
+                               return;
+
+                       if (synchronizingObject == null)
+                               Error (this, e);
+                       else
+                               synchronizingObject.BeginInvoke (Error, new object[] { this, e });
                }
 
                protected void OnRenamed (RenamedEventArgs e)
                {
-                       RaiseEvent (Renamed, e, EventType.RenameEvent);
+                       if (Renamed == null)
+                               return;
+
+                       if (synchronizingObject == null)
+                               Renamed (this, e);
+                       else
+                               synchronizingObject.BeginInvoke (Renamed, new object[] { this, e });
                }
 
                public WaitForChangedResult WaitForChanged (WatcherChangeTypes changeType)
index e673f99739bcaecc9623faa6a277b7c5ca60ef44..f3cc7dcc183200a81a8ca409b3ab9e49f936f7ec 100644 (file)
@@ -3,6 +3,8 @@
 //
 // Authors:
 //     Geoff Norton (gnorton@customerdna.com)
+//     Cody Russell (cody@xamarin.com)
+//     Alexis Christoforides (lexas@xamarin.com)
 //
 // (c) 2004 Geoff Norton
 // Copyright 2014 Xamarin Inc
 
 using System;
 using System.Collections;
+using System.Collections.Generic;
 using System.ComponentModel;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Text;
 using System.Threading;
+using System.Reflection;
 
 namespace System.IO {
 
@@ -71,6 +75,7 @@ namespace System.IO {
                 VM = -11
         }
 
+       [Flags]
        enum FilterFlags : uint {
                 ReadPoll          = EventFlags.Flag0,
                 ReadOutOfBand     = EventFlags.Flag1,
@@ -123,13 +128,14 @@ namespace System.IO {
                 TimerNanoSeconds  =   0x00000004,
                 TimerAbsolute     =   0x00000008,
         }
-                       
+
+       [StructLayout(LayoutKind.Sequential)]
        struct kevent : IDisposable {
-               public int ident;
+               public UIntPtr ident;
                public EventFilter filter;
                public EventFlags flags;
                public FilterFlags fflags;
-               public int data;
+               public IntPtr data;
                public IntPtr udata;
 
                public void Dispose ()
@@ -137,307 +143,405 @@ namespace System.IO {
                        if (udata != IntPtr.Zero)
                                Marshal.FreeHGlobal (udata);
                }
+
+
        }
 
+       [StructLayout(LayoutKind.Sequential)]
        struct timespec {
-               public int tv_sec;
-               public int tv_usec;
+               public IntPtr tv_sec;
+               public IntPtr tv_usec;
        }
 
-       class KeventFileData {
-               public FileSystemInfo fsi;
-               public DateTime LastAccessTime;
-               public DateTime LastWriteTime;
+       class PathData
+       {
+               public string Path;
+               public bool IsDirectory;
+               public int Fd;
+       }
 
-               public KeventFileData(FileSystemInfo fsi, DateTime LastAccessTime, DateTime LastWriteTime) {
-                       this.fsi = fsi;
-                       this.LastAccessTime = LastAccessTime;
-                       this.LastWriteTime = LastWriteTime;
+       class KqueueMonitor : IDisposable
+       {
+               public int Connection
+               {
+                       get { return conn; }
                }
-       }
 
-       class KeventData {
-                public FileSystemWatcher FSW;
-                public string Directory;
-                public string FileMask;
-                public bool IncludeSubdirs;
-                public bool Enabled;
-               public Hashtable DirEntries;
-               public kevent ev;
-        }
+               public KqueueMonitor (FileSystemWatcher fsw)
+               {
+                       this.fsw = fsw;
+                       this.conn = -1;
+               }
 
-       class KeventWatcher : IFileWatcher
-       {
-               static bool failed;
-               static KeventWatcher instance;
-               static Hashtable watches;
-               static Hashtable requests;
-               static Thread thread;
-               static int conn;
-               static bool stop;
-               
-               private KeventWatcher ()
+               public void Dispose ()
                {
+                       CleanUp ();
                }
-               
-               // Locked by caller
-               public static bool GetInstance (out IFileWatcher watcher)
+
+               public void Start ()
                {
-                       if (failed == true) {
-                               watcher = null;
-                               return false;
-                       }
+                       lock (stateLock) {
+                               if (started)
+                                       return;
 
-                       if (instance != null) {
-                               watcher = instance;
-                               return true;
-                       }
+                               conn = kqueue ();
 
-                       watches = Hashtable.Synchronized (new Hashtable ());
-                       requests = Hashtable.Synchronized (new Hashtable ());
-                       conn = kqueue();
-                       if (conn == -1) {
-                               failed = true;
-                               watcher = null;
-                               return false;
-                       }
+                               if (conn == -1)
+                                       throw new IOException (String.Format (
+                                               "kqueue() error at init, error code = '{0}'", Marshal.GetLastWin32Error ()));
+                                       
+                               thread = new Thread (() => DoMonitor ());
+                               thread.IsBackground = true;
+                               thread.Start ();
 
-                       instance = new KeventWatcher ();
-                       watcher = instance;
-                       return true;
+                               startedEvent.WaitOne ();
+
+                               if (failedInit) {
+                                       thread.Join ();
+                                       CleanUp ();
+                                       throw new IOException ("Monitor thread failed while initializing.");
+                               }
+                               else 
+                                       started = true;
+                       }
                }
-               
-               public void StartDispatching (FileSystemWatcher fsw)
+
+               public void Stop ()
                {
-                       KeventData data;
-                       lock (this) {
-                               if (thread == null) {
-                                       thread = new Thread (new ThreadStart (Monitor));
-                                       thread.IsBackground = true;
-                                       thread.Start ();
-                               }
+                       lock (stateLock) {
+                               if (!started)
+                                       return;
+                                       
+                               requestStop = true;
+                               thread.Join ();
+                               requestStop = false;
 
-                               data = (KeventData) watches [fsw];
+                               CleanUp ();
+                               started = false;
                        }
+               }
 
-                       if (data == null) {
-                               data = new KeventData ();
-                               data.FSW = fsw;
-                               data.Directory = fsw.FullPath;
-                               data.FileMask = fsw.MangledFilter;
-                               data.IncludeSubdirs = fsw.IncludeSubdirectories;
-
-                               data.Enabled = true;
-                               lock (this) {
-                                       StartMonitoringDirectory (data);
-                                       watches [fsw] = data;
-                                       stop = false;
-                               }
-                       }
+               void CleanUp ()
+               {
+                       if (conn != -1)
+                               close (conn);
+
+                       conn = -1;
+
+                       foreach (int fd in fdsDict.Keys)
+                               close (fd); 
+
+                       fdsDict.Clear ();
+                       pathsDict.Clear ();
                }
 
-               static void StartMonitoringDirectory (KeventData data)
+               void DoMonitor ()
                {
-                       DirectoryInfo dir = new DirectoryInfo (data.Directory);
-                       if(data.DirEntries == null) {
-                               data.DirEntries = new Hashtable();
-                               foreach (FileSystemInfo fsi in dir.GetFileSystemInfos() ) 
-                                       data.DirEntries.Add(fsi.FullName, new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime));
+                       Exception exc = null;
+                       failedInit = false;
+
+                       try {
+                               Setup ();
+                       } catch (Exception e) {
+                               failedInit = true;
+                               exc = e;
+                       } finally {
+                               startedEvent.Set ();
                        }
 
-                       int fd = open(data.Directory, 0, 0);
-                       kevent ev = new kevent();
-                       ev.udata = IntPtr.Zero;
-                       timespec nullts = new timespec();
-                       nullts.tv_sec = 0;
-                       nullts.tv_usec = 0;
-                       if (fd > 0) {
-                               ev.ident = fd;
-                               ev.filter = EventFilter.Vnode;
-                               ev.flags = EventFlags.Add | EventFlags.Enable | EventFlags.OneShot;
-                               ev.fflags = // 20 | 2 | 1 | 8;
-                                       FilterFlags.VNodeDelete |
-                                       FilterFlags.VNodeWrite |
-                                       FilterFlags.VNodeAttrib |
-                                       // The following two values are the equivalent of the original value "20", but we suspect the original author meant
-                                       // 0x20, we will review later with some test cases
-                                       FilterFlags.VNodeLink |
-                                       FilterFlags.VNodeExtend;
-                               ev.data = 0;
-                               ev.udata = Marshal.StringToHGlobalAuto (data.Directory);
-                               kevent outev = new kevent();
-                               outev.udata = IntPtr.Zero;
-                               kevent (conn, ref ev, 1, ref outev, 0, ref nullts);
-                               data.ev = ev;
-                               requests [fd] = data;
-                       }
-                       
-                       if (!data.IncludeSubdirs)
+                       if (failedInit) {
+                               fsw.OnError (new ErrorEventArgs (exc));
                                return;
+                       }
 
+                       try {
+                               Monitor ();
+                       } catch (Exception e) {
+                               exc = e;
+                       } finally {
+                               if (!requestStop) { // failure
+                                       CleanUp ();
+                                       started = false;
+                               }
+                               if (exc != null)
+                                       fsw.OnError (new ErrorEventArgs (exc));
+                       }
                }
 
-               public void StopDispatching (FileSystemWatcher fsw)
-               {
-                       KeventData data;
-                       lock (this) {
-                               data = (KeventData) watches [fsw];
-                               if (data == null)
-                                       return;
+               void Setup ()
+               {       
+                       var initialFds = new List<int> ();
 
-                               StopMonitoringDirectory (data);
-                               watches.Remove (fsw);
-                               if (watches.Count == 0)
-                                       stop = true;
+                       // GetFilenameFromFd() returns the *realpath* which can be different than fsw.FullPath because symlinks.
+                       // If so, introduce a fixup step.
+                       int fd = open (fsw.FullPath, O_EVTONLY, 0);
+                       var resolvedFullPath = GetFilenameFromFd (fd);
+                       close (fd);
 
-                               if (!data.IncludeSubdirs)
-                                       return;
+                       if (resolvedFullPath != fsw.FullPath)
+                               fixupPath = resolvedFullPath;
+                       else
+                               fixupPath = null;
+
+                       Scan (fsw.FullPath, false, ref initialFds);
 
+                       var immediate_timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)0 };
+                       var eventBuffer = new kevent[0]; // we don't want to take any events from the queue at this point
+                       var changes = CreateChangeList (ref initialFds);
+
+                       int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);
+
+                       if (numEvents == -1) {
+                               var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", Marshal.GetLastWin32Error ());
+                               throw new IOException (errMsg);
                        }
                }
 
-               static void StopMonitoringDirectory (KeventData data)
+               kevent[] CreateChangeList (ref List<int> FdList)
                {
-                       close(data.ev.ident);
+                       if (FdList.Count == 0)
+                               return emptyEventList;
+
+                       var changes = new List<kevent> ();
+                       foreach (int fd in FdList) {
+                               var change = new kevent {
+
+                                       ident = (UIntPtr)fd,
+                                       filter = EventFilter.Vnode,
+                                       flags = EventFlags.Add | EventFlags.Enable | EventFlags.Clear,
+                                       fflags = FilterFlags.VNodeDelete | FilterFlags.VNodeExtend |
+                                               FilterFlags.VNodeRename | FilterFlags.VNodeAttrib |
+                                               FilterFlags.VNodeLink | FilterFlags.VNodeRevoke |
+                                               FilterFlags.VNodeWrite,
+                                       data = IntPtr.Zero,
+                                       udata = IntPtr.Zero
+                               };
+
+                               changes.Add (change);
+                       }
+                       FdList.Clear ();
+
+                       return changes.ToArray ();
                }
 
                void Monitor ()
                {
-               
-                       while (!stop) {
-                               kevent ev = new kevent();
-                               ev.udata = IntPtr.Zero;
-                               kevent nullev = new kevent();
-                               nullev.udata = IntPtr.Zero;
-                               timespec ts = new timespec();
-                               ts.tv_sec = 0;
-                               ts.tv_usec = 0;
-                               int haveEvents;
-                               lock (this) {
-                                       haveEvents = kevent (conn, ref nullev, 0, ref ev, 1, ref ts);
+                       var timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)500000000 };
+                       var eventBuffer = new kevent[32];
+                       var newFds = new List<int> ();
+                       List<PathData> removeQueue = new List<PathData> ();
+                       List<string> rescanQueue = new List<string> ();
+
+                       while (!requestStop) {
+                               var changes = CreateChangeList (ref newFds);
+
+                               int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref timeout);
+
+                               if (numEvents == -1) {
+                                       var errMsg = String.Format ("kevent() error, error code = '{0}'", Marshal.GetLastWin32Error ());
+                                       fsw.OnError (new ErrorEventArgs (new IOException (errMsg)));
                                }
 
-                               if (haveEvents > 0) {
-                                       // Restart monitoring
-                                       KeventData data = (KeventData) requests [ev.ident];
-                                       StopMonitoringDirectory (data);
-                                       StartMonitoringDirectory (data);
-                                       ProcessEvent (ev);
-                               } else {
-                                       System.Threading.Thread.Sleep (500);
+                               if (numEvents == 0)
+                                       continue;
+
+                               for (var i = 0; i < numEvents; i++) {
+                                       var kevt = eventBuffer [i];
+                                       var pathData = fdsDict [(int)kevt.ident];
+
+                                       if ((kevt.flags & EventFlags.Error) == EventFlags.Error) {
+                                               var errMsg = String.Format ("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
+                                               fsw.OnError (new ErrorEventArgs (new IOException (errMsg)));
+                                               continue;
+                                       }
+
+                                       if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke)
+                                               removeQueue.Add (pathData);
+
+                                       else if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite) {
+                                               if (pathData.IsDirectory)
+                                                       rescanQueue.Add (pathData.Path);
+                                               else
+                                                       PostEvent (FileAction.Modified, pathData.Path);
+                                       } 
+
+                                       else if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename) {
+                                               var newFilename = GetFilenameFromFd (pathData.Fd);
+
+                                               if (newFilename.StartsWith (fsw.FullPath))
+                                                       Rename (pathData, newFilename);
+                                               else //moved outside of our watched dir so stop watching
+                                                               RemoveTree (pathData);
+                                       } 
+
+                                       else if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
+                                               PostEvent (FileAction.Modified, pathData.Path);
                                }
+
+                               removeQueue.ForEach (Remove);
+                               removeQueue.Clear ();
+
+                               rescanQueue.ForEach (path => {
+                                       Scan (path, true, ref newFds);
+                               });
+                               rescanQueue.Clear ();
+                       }
+               }
+
+               PathData Add (string path, bool postEvents, ref List<int> fds)
+               {
+                       PathData pathData;
+                       pathsDict.TryGetValue (path, out pathData);
+
+                       if (pathData != null)
+                               return pathData;
+
+                       var fd = open (path, O_EVTONLY, 0);
+
+                       if (fd == -1) {
+                               fsw.OnError (new ErrorEventArgs (new IOException (String.Format (
+                                       "open() error while attempting to process path '{0}', error code = '{1}'", path, Marshal.GetLastWin32Error ()))));
+                               return null;
                        }
 
-                       lock (this) {
-                               thread = null;
-                               stop = false;
+                       try {
+                               fds.Add (fd);
+
+                               var attrs = File.GetAttributes (path);
+
+                               pathData = new PathData {
+                                       Path = path,
+                                       Fd = fd,
+                                       IsDirectory = (attrs & FileAttributes.Directory) == FileAttributes.Directory
+                               };
+                               
+                               pathsDict.Add (path, pathData);
+                               fdsDict.Add (fd, pathData);
+
+                               if (postEvents)
+                                       PostEvent (FileAction.Added, path);
+
+                               return pathData;
+                       } catch (Exception e) {
+                               close (fd);
+                               fsw.OnError (new ErrorEventArgs (e));
+                               return null;
                        }
+
                }
 
-               void ProcessEvent (kevent ev)
+               void Remove (PathData pathData)
                {
-                       lock (this) {
-                               KeventData data = (KeventData) requests [ev.ident];
-                               if (!data.Enabled)
-                                       return;
+                       fdsDict.Remove (pathData.Fd);
+                       pathsDict.Remove (pathData.Path);
+                       close (pathData.Fd);
+                       PostEvent (FileAction.Removed, pathData.Path);
+               }
 
-                               FileSystemWatcher fsw;
-                               string filename = "";
+               void RemoveTree (PathData pathData)
+               {
+                       var toRemove = new List<PathData> ();
 
-                               fsw = data.FSW;
-                               FileAction fa = 0;
-                               DirectoryInfo dir = new DirectoryInfo (data.Directory);
-                               FileSystemInfo changedFsi = null;
+                       toRemove.Add (pathData);
 
-                               try {
-                                       foreach (FileSystemInfo fsi in dir.GetFileSystemInfos() )
-                                               if (data.DirEntries.ContainsKey (fsi.FullName) && (fsi is FileInfo)) {
-                                                       KeventFileData entry = (KeventFileData) data.DirEntries [fsi.FullName];
-                                                       if (entry.LastWriteTime != fsi.LastWriteTime) {
-                                                               filename = fsi.Name;
-                                                               fa = FileAction.Modified;
-                                                               data.DirEntries [fsi.FullName] = new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime);
-                                                               if (fsw.IncludeSubdirectories && fsi is DirectoryInfo) {
-                                                                       data.Directory = filename;
-                                                                       requests [ev.ident] = data;
-                                                                       ProcessEvent(ev);
-                                                               }
-                                                               changedFsi = fsi;
-                                                               PostEvent(filename, fsw, fa, changedFsi);
-                                                       }
-                                               }
-                               } catch (Exception) {
-                                       // The file system infos were changed while we processed them
-                               }
-                               // Deleted
-                               try {
-                                       bool deleteMatched = true;
-                                       while(deleteMatched) {
-                                               foreach (KeventFileData entry in data.DirEntries.Values) { 
-                                                       if (!File.Exists (entry.fsi.FullName) && !Directory.Exists (entry.fsi.FullName)) {
-                                                               filename = entry.fsi.Name;
-                                                               fa = FileAction.Removed;
-                                                               data.DirEntries.Remove (entry.fsi.FullName);
-                                                               changedFsi = entry.fsi;
-                                                               PostEvent(filename, fsw, fa, changedFsi);
-                                                               break;
-                                                       }
-                                               }
-                                               deleteMatched = false;
+                       if (pathData.IsDirectory) {
+                               var prefix = pathData.Path + Path.DirectorySeparatorChar;
+                               foreach (var path in pathsDict.Keys)
+                                       if (path.StartsWith (prefix)) {
+                                               toRemove.Add (pathsDict [path]);
                                        }
-                               } catch (Exception) {
-                                       // The file system infos were changed while we processed them
-                               }
-                               // Added
-                               try {
-                                       foreach (FileSystemInfo fsi in dir.GetFileSystemInfos()) 
-                                               if (!data.DirEntries.ContainsKey (fsi.FullName)) {
-                                                       changedFsi = fsi;
-                                                       filename = fsi.Name;
-                                                       fa = FileAction.Added;
-                                                       data.DirEntries [fsi.FullName] = new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime);
-                                                       PostEvent(filename, fsw, fa, changedFsi);
-                                               }
-                               } catch (Exception) {
-                                       // The file system infos were changed while we processed them
-                               }
-                               
+                       }
+                       toRemove.ForEach (Remove);
+               }
 
+               void Rename (PathData pathData, string newRoot)
+               {
+                       var toRename = new List<PathData> ();
+                       var oldRoot = pathData.Path;
+
+                       toRename.Add (pathData);
+                                                                                                                       
+                       if (pathData.IsDirectory) {
+                               var prefix = oldRoot + Path.DirectorySeparatorChar;
+                               foreach (var path in pathsDict.Keys)
+                                       if (path.StartsWith (prefix))
+                                               toRename.Add (pathsDict [path]);
                        }
+
+                       toRename.ForEach ((pd) => { 
+                               var oldPath = pd.Path;
+                               var newPath = newRoot + oldPath.Substring (oldRoot.Length);
+                               pd.Path = newPath;
+                               pathsDict.Remove (oldPath);
+                               pathsDict.Add (newPath, pd);
+                       });
+
+                       PostEvent (FileAction.RenamedNewName, oldRoot, newRoot);
                }
 
-               private void PostEvent (string filename, FileSystemWatcher fsw, FileAction fa, FileSystemInfo changedFsi) {
-                       RenamedEventArgs renamed = null;
-                       if (fa == 0)
+               void Scan (string path, bool postEvents, ref List<int> fds)
+               {
+                       if (requestStop)
                                return;
-                       
-                       if (fsw.IncludeSubdirectories && fa == FileAction.Added) {
-                               if (changedFsi is DirectoryInfo) {
-                                       KeventData newdirdata = new KeventData ();
-                                       newdirdata.FSW = fsw;
-                                       newdirdata.Directory = changedFsi.FullName;
-                                       newdirdata.FileMask = fsw.MangledFilter;
-                                       newdirdata.IncludeSubdirs = fsw.IncludeSubdirectories;
-       
-                                       newdirdata.Enabled = true;
-                                       lock (this) {
-                                               StartMonitoringDirectory (newdirdata);
-                                       }
+                               
+                       var pathData = Add (path, postEvents, ref fds);
+
+                       if (pathData == null)
+                               return;
+                               
+                       if (!pathData.IsDirectory)
+                               return;
+
+                       var dirsToProcess = new List<string> ();
+                       dirsToProcess.Add (path);
+
+                       while (dirsToProcess.Count > 0) {
+                               var tmp = dirsToProcess [0];
+                               dirsToProcess.RemoveAt (0);
+
+                               var info = new DirectoryInfo (tmp);
+                               FileSystemInfo[] fsInfos = null;
+                               try {
+                                       fsInfos = info.GetFileSystemInfos ();
+                                               
+                               } catch (IOException) {
+                                       // this can happen if the directory has been deleted already.
+                                       // that's okay, just keep processing the other dirs.
+                                       fsInfos = new FileSystemInfo[0];
+                               }
+
+                               foreach (var fsi in fsInfos) {
+                                       if ((fsi.Attributes & FileAttributes.Directory) == FileAttributes.Directory && !fsw.IncludeSubdirectories)
+                                               continue;
+
+                                       if ((fsi.Attributes & FileAttributes.Directory) != FileAttributes.Directory && !fsw.Pattern.IsMatch (fsi.FullName))
+                                               continue;
+
+                                       var currentPathData = Add (fsi.FullName, postEvents, ref fds);
+
+                                       if (currentPathData != null && currentPathData.IsDirectory)
+                                               dirsToProcess.Add (fsi.FullName);
                                }
                        }
-               
-                       if (!fsw.Pattern.IsMatch(filename, true))
+               }
+                       
+               void PostEvent (FileAction action, string path, string newPath = null)
+               {
+                       RenamedEventArgs renamed = null;
+
+                       if (action == 0)
                                return;
 
+                       // only post events that match filter pattern. check both old and new paths for renames
+                       if (!fsw.Pattern.IsMatch (path) && (newPath == null || !fsw.Pattern.IsMatch (newPath))) 
+                               return;
+                               
+                       if (action == FileAction.RenamedNewName)
+                               renamed = new RenamedEventArgs (WatcherChangeTypes.Renamed, "", newPath, path);
+
                        lock (fsw) {
-                               if (changedFsi.FullName.StartsWith (fsw.FullPath, StringComparison.Ordinal)) {
-                                       if (fsw.FullPath.EndsWith ("/", StringComparison.Ordinal)) {
-                                               filename = changedFsi.FullName.Substring (fsw.FullPath.Length);
-                                       } else {
-                                               filename = changedFsi.FullName.Substring (fsw.FullPath.Length + 1);
-                                       }
-                               }
-                               fsw.DispatchEvents (fa, filename, ref renamed);
+                               fsw.DispatchEvents (action, path, ref renamed);
+
                                if (fsw.Waiting) {
                                        fsw.Waiting = false;
                                        System.Threading.Monitor.PulseAll (fsw);
@@ -445,17 +549,120 @@ namespace System.IO {
                        }
                }
 
+               private string GetFilenameFromFd (int fd)
+               {
+                       var sb = new StringBuilder (__DARWIN_MAXPATHLEN);
+
+                       if (fcntl (fd, F_GETPATH, sb) != -1) {
+                               if (fixupPath != null)
+                                       sb.Replace (fixupPath, fsw.FullPath, 0, fixupPath.Length); // see Setup()
+                               return sb.ToString ();
+                       } else {
+                               fsw.OnError (new ErrorEventArgs (new IOException (String.Format (
+                                       "fcntl() error while attempting to get path for fd '{0}', error code = '{1}'", fd, Marshal.GetLastWin32Error ()))));
+                               return String.Empty;
+                       }
+               }
+
+               const int O_EVTONLY = 0x8000;
+               const int F_GETPATH = 50;
+               const int __DARWIN_MAXPATHLEN = 1024;
+               static readonly kevent[] emptyEventList = new System.IO.kevent[0];
+
+               FileSystemWatcher fsw;
+               int conn;
+               Thread thread;
+               volatile bool requestStop = false;
+               AutoResetEvent startedEvent = new AutoResetEvent (false);
+               bool started = false;
+               bool failedInit = false;
+               object stateLock = new object ();
+
+               readonly Dictionary<string, PathData> pathsDict = new Dictionary<string, PathData> ();
+               readonly Dictionary<int, PathData> fdsDict = new Dictionary<int, PathData> ();
+               string fixupPath = null;
+
+               [DllImport ("libc", EntryPoint="fcntl", CharSet=CharSet.Auto, SetLastError=true)]
+               static extern int fcntl (int file_names_by_descriptor, int cmd, StringBuilder sb);
+
+               [DllImport ("libc")]
+               extern static int open (string path, int flags, int mode_t);
+
                [DllImport ("libc")]
-               extern static int open(string path, int flags, int mode_t);
-               
+               extern static int close (int fd);
+
                [DllImport ("libc")]
-               extern static int close(int fd);
+               extern static int kqueue ();
 
                [DllImport ("libc")]
-               extern static int kqueue();
+               extern static int kevent (int kq, [In]kevent[] ev, int nchanges, [Out]kevent[] evtlist, int nevents, [In] ref timespec time);
+       }
+
+       class KeventWatcher : IFileWatcher
+       {
+               static bool failed;
+               static KeventWatcher instance;
+               static Hashtable watches;  // <FileSystemWatcher, KqueueMonitor>
+
+               private KeventWatcher ()
+               {
+               }
+
+               // Locked by caller
+               public static bool GetInstance (out IFileWatcher watcher)
+               {
+                       if (failed == true) {
+                               watcher = null;
+                               return false;
+                       }
+
+                       if (instance != null) {
+                               watcher = instance;
+                               return true;
+                       }
+
+                       watches = Hashtable.Synchronized (new Hashtable ());
+                       var conn = kqueue();
+                       if (conn == -1) {
+                               failed = true;
+                               watcher = null;
+                               return false;
+                       }
+                       close (conn);
+
+                       instance = new KeventWatcher ();
+                       watcher = instance;
+                       return true;
+               }
+
+               public void StartDispatching (FileSystemWatcher fsw)
+               {
+                       KqueueMonitor monitor;
+
+                       if (watches.ContainsKey (fsw)) {
+                               monitor = (KqueueMonitor)watches [fsw];
+                       } else {
+                               monitor = new KqueueMonitor (fsw);
+                               watches.Add (fsw, monitor);
+                       }
+                               
+                       monitor.Start ();
+               }
+
+               public void StopDispatching (FileSystemWatcher fsw)
+               {
+                       KqueueMonitor monitor = (KqueueMonitor)watches [fsw];
+                       if (monitor == null)
+                               return;
+
+                       monitor.Stop ();
+               }
+                       
+               [DllImport ("libc")]
+               extern static int close (int fd);
 
                [DllImport ("libc")]
-               extern static int kevent(int kqueue, ref kevent ev, int nchanges, ref kevent evtlist,  int nevents, ref timespec ts);
+               extern static int kqueue ();
        }
 }
 
index 0fbab4e5e7eb3e50be08b27174d1d8efb8b7c6bf..f302dffaaa046940f430fbec3a04b6dd78948660 100644 (file)
@@ -47,7 +47,7 @@ namespace System.IO {
                        Compile (pattern);
                }
 
-               // OSX has a retarded case-insensitive yet case-aware filesystem
+               // OSX has a case-insensitive yet case-aware filesystem
                // so we need a overload in here for the Kqueue watcher
                public bool IsMatch (string text, bool ignorecase)
                {
@@ -55,20 +55,17 @@ namespace System.IO {
                                bool match = String.Compare (pattern, text, ignorecase) == 0;
                                if (match)
                                        return true;
-                               
-                               // This is a special case for FSW. It needs to match e.g. subdir/file.txt
-                               // when the pattern is "file.txt"
-                               int idx = text.LastIndexOf ('/');
-                               if (idx == -1)
-                                       return false;
-                               idx++;
-                               if (idx == text.Length)
-                                       return false;
-                               
-                               return (String.Compare (pattern, text.Substring (idx), ignorecase) == 0);
                        }
+                               
+                       // This is a special case for FSW. It needs to match e.g. subdir/file.txt
+                       // when the pattern is "file.txt"
+                       var fileName = Path.GetFileName (text);
+                       
+                       if (!hasWildcard)
+                               return (String.Compare (pattern, fileName, ignorecase) == 0);
+                       
                        
-                       return Match (ops, text, 0);
+                       return Match (ops, fileName, 0);
                }
 
                public bool IsMatch (string text)
index 628c04d8eddcba9f61fffee9e155e50cbb622eaa..a1d0896dba63d84bb0927be9b160ec03b54c5996 100644 (file)
@@ -200,6 +200,8 @@ namespace Mono.Audio {
                                snd_pcm_hw_params_free (hw_param);
                        if (handle != IntPtr.Zero)
                                snd_pcm_close (handle);
+                       sw_param = IntPtr.Zero;
+                       hw_param = IntPtr.Zero;
                        handle = IntPtr.Zero;
                }
 
@@ -278,10 +280,14 @@ namespace Mono.Audio {
                                Console.WriteLine ("failed to alloc Alsa sw param struct");
                        }
 
-                       if (hw_param != IntPtr.Zero)
+                       if (hw_param != IntPtr.Zero) {
                                snd_pcm_hw_params_free (hw_param);  // free hw params
-                       if (sw_param != IntPtr.Zero)
+                               hw_param = IntPtr.Zero;
+                       }
+                       if (sw_param != IntPtr.Zero) {
                                snd_pcm_sw_params_free (sw_param);  // free sw params
+                               sw_param = IntPtr.Zero;
+                       }
 
                        return alsa_err == 0;
                }
index a7eeb67d883c73ab90fdb7e57a87c096b633c452..c7f6259172d3d4adbc0c35eac98a54512c80679a 100644 (file)
@@ -260,6 +260,8 @@ namespace System.Net.Sockets
                                curSocket.EndConnect (ares);
                        } catch (SocketException se) {
                                SocketError = se.SocketErrorCode;
+                       } catch (ObjectDisposedException) {
+                               SocketError = SocketError.OperationAborted;
                        } finally {
                                OnCompleted (this);
                        }
index b0295bef71beff144c4de459318150487d150b83..b44a061159207ba22e4f1ec05cd8c236eb4cbf5d 100644 (file)
@@ -952,6 +952,14 @@ namespace System.Net.Sockets {
 #endif
                }
 
+#if NET_4_5
+               [MonoTODO ("Currently hardcoded to IPv4. Ideally, support v4/v6 dual-stack.")]
+               public Socket (SocketType socketType, ProtocolType protocolType)
+                       : this (AddressFamily.InterNetwork, socketType, protocolType)
+               {
+               }
+#endif
+
                ~Socket ()
                {
                        Dispose (false);
index ded7767114a62349033d4746f6f240ec534895cc..38415f05c5f7ca3043da0b464e3e8ac754960e29 100644 (file)
@@ -1972,20 +1972,17 @@ namespace System.Net
                        if (fileName == null)
                                throw new ArgumentNullException ("fileName");
 
-                       WebRequest request = null;
                        try {
                                SetBusy ();
                                cts = new CancellationTokenSource ();
-                               request = await SetupRequestAsync (address, method, true).ConfigureAwait (false);
-                               var result = await UploadFileTaskAsyncCore (request, method, fileName, cts.Token).ConfigureAwait (false);
+
+                               var result = await UploadFileTaskAsyncCore (address, method, fileName, cts.Token).ConfigureAwait (false);
                                OnUploadFileCompleted (new UploadFileCompletedEventArgs (result, null, false, null));
                                return result;
                        } catch (WebException ex) {
                                OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, ex, false, null));
                                throw;
                        } catch (OperationCanceledException) {
-                               if (request != null)
-                                       request.Abort ();
                                OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, null, true, null));
                                throw;
                        } catch (Exception ex) {
@@ -1994,8 +1991,7 @@ namespace System.Net
                        }
                }
 
-               async Task<byte[]> UploadFileTaskAsyncCore (WebRequest request, string method,
-                                                           string fileName, CancellationToken token)
+               async Task<byte[]> UploadFileTaskAsyncCore (Uri address, string method, string fileName, CancellationToken token)
                {
                        token.ThrowIfCancellationRequested ();
 
@@ -2018,9 +2014,15 @@ namespace System.Net
                        Stream reqStream = null;
                        Stream fStream = null;
                        WebResponse response = null;
+                       WebRequest request = null;
 
                        fileName = Path.GetFullPath (fileName);
 
+                       try {
+                               request = await SetupRequestAsync (address, method, true).ConfigureAwait (false);
+                       } catch (OperationCanceledException) {
+                       }
+
                        try {
                                fStream = File.OpenRead (fileName);
                                token.ThrowIfCancellationRequested ();
@@ -2042,7 +2044,9 @@ namespace System.Net
                                                        Path.GetFileName (fileName), fileCType);
                                                byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
                                                ms.Write (partHeadersBytes, 0, partHeadersBytes.Length);
-                                               await ms.CopyToAsync (reqStream, (int)ms.Position, token).ConfigureAwait (false);
+                                               var msLength = (int)ms.Position;
+                                               ms.Seek (0, SeekOrigin.Begin);
+                                               await ms.CopyToAsync (reqStream, msLength, token).ConfigureAwait (false);
                                        }
                                }
                                int nread;
@@ -2084,7 +2088,9 @@ namespace System.Net
                                                ms.WriteByte ((byte) '-');
                                                ms.WriteByte ((byte) '\r');
                                                ms.WriteByte ((byte) '\n');
-                                               await ms.CopyToAsync (reqStream, (int)ms.Position, token).ConfigureAwait (false);
+                                               var msLength = (int)ms.Position;
+                                               ms.Seek (0, SeekOrigin.Begin);
+                                               await ms.CopyToAsync (reqStream, msLength, token).ConfigureAwait (false);
                                        }
                                }
                                reqStream.Close ();
index 5e94d3bdf539e67969bdcc768a3c4464debf0a03..dfbd0e75b213c4d75f184ef192c5726729b5f092 100644 (file)
@@ -269,15 +269,6 @@ namespace System {
                                return state.remaining.Length > 0;
                        }
 
-                       if (state.elements.scheme == Uri.UriSchemeFile) {
-                               // under Windows all file:// URI are considered UNC, which is not the case other MacOS (e.g. Silverlight)
-#if BOOTSTRAP_BASIC
-                               state.elements.isUnc = (Path.DirectorySeparatorChar == '\\');
-#else
-                               state.elements.isUnc = Environment.IsRunningOnWindows;
-#endif
-                       }
-
                        return ParseDelimiter (state);
                }
 
@@ -430,7 +421,17 @@ namespace System {
                        state.elements.host = state.elements.host.ToLowerInvariant ();
 
                        state.remaining = part.Substring (state.elements.host.Length);
-                               
+
+                       if (state.elements.scheme == Uri.UriSchemeFile &&
+                               state.elements.host != "") {
+                               // under Windows all file://host URI are considered UNC, which is not the case other MacOS (e.g. Silverlight)
+#if BOOTSTRAP_BASIC
+                               state.elements.isUnc = (Path.DirectorySeparatorChar == '\\');
+#else
+                               state.elements.isUnc = Environment.IsRunningOnWindows;
+#endif
+                       }
+
                        return state.remaining.Length > 0;
                }
                
index 48722d45510fd03642ce0aad7ff725e25529587c..ef3f681742513571b358bbfd9b9b126b4276eecd 100644 (file)
@@ -2221,6 +2221,28 @@ namespace MonoTests.System.Net
                                webClient.UploadFileAsync (uri, "PUT", tempFile);
                        });
                }
+
+               [Test]
+               public void UploadFileAsyncContentType ()
+               {
+                       var serverUri = "http://localhost:13370/";
+                       var filename = Path.GetTempFileName ();
+
+                       HttpListener listener = new HttpListener ();
+                       listener.Prefixes.Add (serverUri);
+                       listener.Start ();
+
+                       using (var client = new WebClient ())
+                       {
+                               client.UploadFileTaskAsync (new Uri (serverUri), filename);
+                               var request = listener.GetContext ().Request;
+
+                               var expected = "multipart/form-data; boundary=------------";
+                               Assert.AreEqual (expected.Length + 15, request.ContentType.Length);
+                               Assert.AreEqual (expected, request.ContentType.Substring (0, expected.Length));
+                       }
+                       listener.Close ();
+               }
 #endif
 
 #if NET_4_0
index 73b143aae2f140b50f8e8b4a7ef2f89ab9329792..e3a4530e0c653230592e85ac46a8ef6a7c354ce3 100644 (file)
@@ -919,6 +919,102 @@ TextWriter sw = Console.Out;
                                Assert.AreEqual ("/%3C%3E%25%22%7B%7D%7C/%5E%60;/:@&=+$,%5B%5D%3F", uri.AbsolutePath, "Special");
                }
 
+               [Test]
+               public void LocalFile ()
+               {
+                       Uri uri = new Uri ("file:///c:/subdir/file");
+
+                       Assert.AreEqual ("c:/subdir/file", uri.AbsolutePath, "AbsolutePath");
+                       Assert.AreEqual ("file:///c:/subdir/file", uri.AbsoluteUri, "AbsoluteUri");
+                       Assert.AreEqual ("c:\\subdir\\file", uri.LocalPath, "LocalPath");
+                       Assert.AreEqual ("c:/subdir/file", uri.PathAndQuery, "PathAndQuery");
+                       Assert.AreEqual (String.Empty, uri.Query, "Query");
+                       Assert.AreEqual ("file", uri.Segments [3], "Segments [3]");
+
+                       Assert.AreEqual (String.Empty, uri.Authority, "Authority");
+                       Assert.AreEqual (String.Empty, uri.DnsSafeHost, "DnsSafeHost");
+                       Assert.AreEqual (String.Empty, uri.Fragment, "Fragment");
+                       Assert.AreEqual (String.Empty, uri.Host, "Host");
+                       Assert.AreEqual (UriHostNameType.Basic, uri.HostNameType, "HostNameType");
+                       Assert.IsTrue (uri.IsAbsoluteUri, "IsAbsoluteUri");
+                       Assert.IsTrue (uri.IsDefaultPort, "IsDefaultPort");
+                       Assert.IsTrue (uri.IsFile, "IsFile");
+                       Assert.IsTrue (uri.IsLoopback, "IsLoopback");
+                       Assert.IsFalse (uri.IsUnc, "IsUnc");
+                       Assert.AreEqual ("file:///c:/subdir/file", uri.OriginalString, "OriginalString");
+                       Assert.AreEqual (-1, uri.Port, "Port");
+                       Assert.AreEqual ("file", uri.Scheme, "Scheme");
+                       Assert.AreEqual ("/", uri.Segments [0], "Segments [0]");
+                       Assert.AreEqual ("c:/", uri.Segments [1], "Segments [1]");
+                       Assert.AreEqual ("subdir/", uri.Segments [2], "Segments [2]");
+                       Assert.IsFalse (uri.UserEscaped, "UserEscaped");
+                       Assert.AreEqual (String.Empty, uri.UserInfo, "UserInfo");
+               }
+
+               [Test]
+               public void LocalhostWinFile ()
+               {
+                       Uri uri = new Uri ("file://localhost/c:/subdir/file");
+
+                       Assert.AreEqual ("/c:/subdir/file", uri.AbsolutePath, "AbsolutePath");
+                       Assert.AreEqual ("file://localhost/c:/subdir/file", uri.AbsoluteUri, "AbsoluteUri");
+                       Assert.AreEqual (isWin32 ? "\\\\localhost\\c:\\subdir\\file" : "/c:/subdir/file", uri.LocalPath, "LocalPath");
+                       Assert.AreEqual ("/c:/subdir/file", uri.PathAndQuery, "PathAndQuery");
+                       Assert.AreEqual (String.Empty, uri.Query, "Query");
+                       Assert.AreEqual ("file", uri.Segments [3], "Segments [3]");
+
+                       Assert.AreEqual ("localhost", uri.Authority, "Authority");
+                       Assert.AreEqual ("localhost", uri.DnsSafeHost, "DnsSafeHost");
+                       Assert.AreEqual (String.Empty, uri.Fragment, "Fragment");
+                       Assert.AreEqual ("localhost", uri.Host, "Host");
+                       Assert.AreEqual (UriHostNameType.Dns, uri.HostNameType, "HostNameType");
+                       Assert.IsTrue (uri.IsAbsoluteUri, "IsAbsoluteUri");
+                       Assert.IsTrue (uri.IsDefaultPort, "IsDefaultPort");
+                       Assert.IsTrue (uri.IsFile, "IsFile");
+                       Assert.IsTrue (uri.IsLoopback, "IsLoopback");
+                       Assert.AreEqual (isWin32, uri.IsUnc, "IsUnc");
+                       Assert.AreEqual ("file://localhost/c:/subdir/file", uri.OriginalString, "OriginalString");
+                       Assert.AreEqual (-1, uri.Port, "Port");
+                       Assert.AreEqual ("file", uri.Scheme, "Scheme");
+                       Assert.AreEqual ("/", uri.Segments [0], "Segments [0]");
+                       Assert.AreEqual ("c:/", uri.Segments [1], "Segments [1]");
+                       Assert.AreEqual ("subdir/", uri.Segments [2], "Segments [2]");
+                       Assert.IsFalse (uri.UserEscaped, "UserEscaped");
+                       Assert.AreEqual (String.Empty, uri.UserInfo, "UserInfo");
+               }
+
+               [Test]
+               public void LocalhostFile ()
+               {
+                       Uri uri = new Uri ("file://localhost/dir/subdir/file");
+
+                       Assert.AreEqual ("/dir/subdir/file", uri.AbsolutePath, "AbsolutePath");
+                       Assert.AreEqual ("file://localhost/dir/subdir/file", uri.AbsoluteUri, "AbsoluteUri");
+                       Assert.AreEqual (isWin32 ? "\\\\localhost\\dir\\subdir\\file" : "/dir/subdir/file", uri.LocalPath, "LocalPath");
+                       Assert.AreEqual ("/dir/subdir/file", uri.PathAndQuery, "PathAndQuery");
+                       Assert.AreEqual (String.Empty, uri.Query, "Query");
+                       Assert.AreEqual ("file", uri.Segments [3], "Segments [3]");
+
+                       Assert.AreEqual ("localhost", uri.Authority, "Authority");
+                       Assert.AreEqual ("localhost", uri.DnsSafeHost, "DnsSafeHost");
+                       Assert.AreEqual (String.Empty, uri.Fragment, "Fragment");
+                       Assert.AreEqual ("localhost", uri.Host, "Host");
+                       Assert.AreEqual (UriHostNameType.Dns, uri.HostNameType, "HostNameType");
+                       Assert.IsTrue (uri.IsAbsoluteUri, "IsAbsoluteUri");
+                       Assert.IsTrue (uri.IsDefaultPort, "IsDefaultPort");
+                       Assert.IsTrue (uri.IsFile, "IsFile");
+                       Assert.IsTrue (uri.IsLoopback, "IsLoopback");
+                       Assert.AreEqual (isWin32, uri.IsUnc, "IsUnc");
+                       Assert.AreEqual ("file://localhost/dir/subdir/file", uri.OriginalString, "OriginalString");
+                       Assert.AreEqual (-1, uri.Port, "Port");
+                       Assert.AreEqual ("file", uri.Scheme, "Scheme");
+                       Assert.AreEqual ("/", uri.Segments [0], "Segments [0]");
+                       Assert.AreEqual ("dir/", uri.Segments [1], "Segments [1]");
+                       Assert.AreEqual ("subdir/", uri.Segments [2], "Segments [2]");
+                       Assert.IsFalse (uri.UserEscaped, "UserEscaped");
+                       Assert.AreEqual (String.Empty, uri.UserInfo, "UserInfo");
+               }
+
                [Test]
                public void PathReduction_2e ()
                {
diff --git a/mcs/class/corlib/DateTime.Now_Test.sh b/mcs/class/corlib/DateTime.Now_Test.sh
new file mode 100755 (executable)
index 0000000..27b9c20
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+export MONO_PATH=${MONO_PATH:-$SCRIPT_PATH/../lib/net_4_5/}
+
+TZ_FAILS=0
+TZ_COUNT=0
+FORMAT="%a %b %d %T %Y"
+
+for tz in $(cd /usr/share/zoneinfo/; find * -type f -print); do
+       TZ_COUNT=$(expr $TZ_COUNT + 1)
+       SYS_DATETIME=$(date -ju -f "$FORMAT" "$(TZ=$tz date "+$FORMAT")" "+%s")
+       CS_DATETIME=$(TZ=$tz csharp -e '(int)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;')
+       DIFF=$(expr $SYS_DATETIME - $CS_DATETIME)
+       if [ "$DIFF" -gt "5" ] || [ "$DIFF" -lt "-5" ]; then
+               TZ_FAILS=$(expr $TZ_FAILS + 1)
+               echo ""
+               echo "DateTime.Now failed with timezone: $tz"
+               echo "    System:       $(date -ju -f "%s" "$SYS_DATETIME" "+%Y-%m-%d %T")"
+               echo "    DateTime.Now: $(date -ju -f "%s" "$CS_DATETIME" "+%Y-%m-%d %T")"
+       fi
+       echo ".\c"
+done
+echo ""
+echo "DateTime.Now failed with $TZ_FAILS of $TZ_COUNT timezones."
index ea8984394b46030245c00440b404dd639de7b2e9..958fc6153594c03f42b443fcb2f6959f907b6f76 100644 (file)
@@ -63,7 +63,7 @@ namespace System.Collections.Concurrent
                {
                        Node node = new Node ();
                        node.Value = item;
-                       
+
                        Node oldTail = null;
                        Node oldNext = null;
                        
@@ -71,6 +71,8 @@ namespace System.Collections.Concurrent
                        while (!update) {
                                oldTail = tail;
                                oldNext = oldTail.Next;
+
+                               Thread.MemoryBarrier ();
                                
                                // Did tail was already updated ?
                                if (tail == oldTail) {
@@ -104,6 +106,8 @@ namespace System.Collections.Concurrent
                                Node oldHead = head;
                                Node oldTail = tail;
                                oldNext = oldHead.Next;
+
+                               Thread.MemoryBarrier ();
                                
                                if (oldHead == head) {
                                        // Empty case ?
@@ -146,6 +150,8 @@ namespace System.Collections.Concurrent
                                }
 
                                result = oldNext.Value;
+
+                               Thread.MemoryBarrier ();
                                
                                //check if head has been updated
                                update = head != oldHead;
diff --git a/mcs/class/corlib/System.Runtime.InteropServices/IErrorInfo.cs b/mcs/class/corlib/System.Runtime.InteropServices/IErrorInfo.cs
new file mode 100644 (file)
index 0000000..36c663c
--- /dev/null
@@ -0,0 +1,38 @@
+// IErrorInfo interface
+//
+// Eberhard Beilharz (eb1@sil.org)
+//
+// Copyright (C) 2011 SIL International
+using System;
+using System.Runtime.CompilerServices;
+using System.Security;
+
+namespace System.Runtime.InteropServices
+{
+       [ComImport]
+       [SuppressUnmanagedCodeSecurity]
+       [Guid ("1CF2B120-547D-101B-8E65-08002B2BD119")]
+       [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
+       internal interface IErrorInfo
+       {
+               [MethodImpl (MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
+               [PreserveSig]
+               int GetGUID (out Guid pGuid);
+
+               [MethodImpl (MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
+               [PreserveSig]
+               int GetSource ([MarshalAs (UnmanagedType.BStr)] out string pBstrSource);
+
+               [MethodImpl (MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
+               [PreserveSig]
+               int GetDescription ([MarshalAs (UnmanagedType.BStr)] out string pbstrDescription);
+
+               [MethodImpl (MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
+               [PreserveSig]
+               int GetHelpFile ([MarshalAs (UnmanagedType.BStr)] out string pBstrHelpFile);
+
+               [MethodImpl (MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
+               [PreserveSig]
+               int GetHelpContext (out uint pdwHelpContext);
+       }
+}
diff --git a/mcs/class/corlib/System.Runtime.InteropServices/ManagedErrorInfo.cs b/mcs/class/corlib/System.Runtime.InteropServices/ManagedErrorInfo.cs
new file mode 100644 (file)
index 0000000..c77857c
--- /dev/null
@@ -0,0 +1,63 @@
+// ManagedErrorInfo class
+//
+// Eberhard Beilharz (eb1@sil.org)
+//
+// Copyright (C) 2012 SIL International
+using System;
+using System.Runtime.CompilerServices;
+using System.Security;
+
+namespace System.Runtime.InteropServices
+{
+       /// <summary>
+       /// Helper class that allows to pass an exception as an IErrorInfo object. This is useful
+       /// when we get an exception in managed code that is called from unmanaged code that is called
+       /// from managed code and we want to get to the exception in the outer managed code.
+       /// </summary>
+       internal class ManagedErrorInfo: IErrorInfo
+       {
+               private Exception m_Exception;
+               public ManagedErrorInfo (Exception e)
+               {
+                       m_Exception = e;
+               }
+
+               public Exception Exception {
+                       get { return m_Exception; }
+               }
+
+               #region IErrorInfo
+               public int GetGUID (out Guid guid)
+               {
+                       // not supported
+                       guid = Guid.Empty;
+                       return 0;
+               }
+
+               public int GetSource (out string source)
+               {
+                       source = m_Exception.Source;
+                       return 0;
+               }
+
+               public int GetDescription (out string description)
+               {
+                       description = m_Exception.Message;
+                       return 0;
+               }
+
+               public int GetHelpFile (out string helpFile)
+               {
+                       helpFile = m_Exception.HelpLink;
+                       return 0;
+               }
+
+               public int GetHelpContext(out uint helpContext)
+               {
+                       // not supported
+                       helpContext = 0;
+                       return 0;
+               }
+               #endregion
+       }
+}
index e339f94955ad4463ee6de55a20d018c6b0157cd2..243984706ceaaf1c27f77ccacd711eaf450bcce6 100644 (file)
@@ -414,9 +414,11 @@ namespace System.Runtime.InteropServices
 #endif // !FULL_AOT_RUNTIME
 
 #if !FULL_AOT_RUNTIME
-               [MonoTODO ("SetErrorInfo")]
                public static int GetHRForException (Exception e)
                {
+                       var errorInfo = new ManagedErrorInfo(e);
+                       SetErrorInfo (0, errorInfo);
+
                        return e.hresult;
                }
 
@@ -1314,27 +1316,310 @@ namespace System.Runtime.InteropServices
                        throw new NotImplementedException ();
                }
 
-               public static Exception GetExceptionForHR (int errorCode) {
-                       return GetExceptionForHR (errorCode, IntPtr.Zero);
-               }
-
-               public static Exception GetExceptionForHR (int errorCode, IntPtr errorInfo) {
-
+               private static Exception ConvertHrToException (int errorCode)
+               {
+                       const int MSEE_E_APPDOMAINUNLOADED = unchecked ((int)0x80131014L);
+                       const int COR_E_APPLICATION = unchecked ((int)0x80131600L);
+                       const int E_INVALIDARG = unchecked ((int)0x80070057);
+                       const int COR_E_ARGUMENTOUTOFRANGE = unchecked ((int)0x80131502L);
+                       const int COR_E_ARITHMETIC = unchecked ((int)0x80070216);
+                       const int COR_E_ARRAYTYPEMISMATCH = unchecked ((int)0x80131503L);
+                       const int COR_E_BADIMAGEFORMAT = unchecked ((int)0x8007000BL);
+                       const int ERROR_BAD_FORMAT = unchecked ((int)0x0B);
+                       //const int COR_E_COMEMULATE_ERROR = unchecked ((int)?);
+                       const int COR_E_CONTEXTMARSHAL = unchecked ((int)0x80131504L);
+                       //const int COR_E_CORE = unchecked ((int)?);
+                       const int NTE_FAIL = unchecked ((int)0x80090020L);
+                       const int COR_E_DIRECTORYNOTFOUND = unchecked ((int)0x80070003L);
+                       const int ERROR_PATH_NOT_FOUND = unchecked ((int)0x03);
+                       const int COR_E_DIVIDEBYZERO = unchecked ((int)0x80020012L);
+                       const int COR_E_DUPLICATEWAITOBJECT = unchecked ((int)0x80131529L);
+                       const int COR_E_ENDOFSTREAM = unchecked ((int)0x80070026L);
+                       const int COR_E_TYPELOAD = unchecked ((int)0x80131522L);
+                       const int COR_E_EXCEPTION = unchecked ((int)0x80131500L);
+                       const int COR_E_EXECUTIONENGINE = unchecked ((int)0x80131506L);
+                       const int COR_E_FIELDACCESS = unchecked ((int)0x80131507L);
+                       const int COR_E_FILENOTFOUND = unchecked ((int)0x80070002L);
+                       const int ERROR_FILE_NOT_FOUND = unchecked ((int)0x02);
+                       const int COR_E_FORMAT = unchecked ((int)0x80131537L);
+                       const int COR_E_INDEXOUTOFRANGE = unchecked ((int)0x80131508L);
+                       const int COR_E_INVALIDCAST = unchecked ((int)0x80004002L);
+                       const int COR_E_INVALIDCOMOBJECT = unchecked ((int)0x80131527L);
+                       const int COR_E_INVALIDFILTERCRITERIA = unchecked ((int)0x80131601L);
+                       const int COR_E_INVALIDOLEVARIANTTYPE = unchecked ((int)0x80131531L);
+                       const int COR_E_INVALIDOPERATION = unchecked ((int)0x80131509L);
+                       const int COR_E_IO = unchecked ((int)0x80131620L);
+                       const int COR_E_MEMBERACCESS = unchecked ((int)0x8013151AL);
+                       const int COR_E_METHODACCESS = unchecked ((int)0x80131510L);
+                       const int COR_E_MISSINGFIELD = unchecked ((int)0x80131511L);
+                       const int COR_E_MISSINGMANIFESTRESOURCE = unchecked ((int)0x80131532L);
+                       const int COR_E_MISSINGMEMBER = unchecked ((int)0x80131512L);
+                       const int COR_E_MISSINGMETHOD = unchecked ((int)0x80131513L);
+                       const int COR_E_MULTICASTNOTSUPPORTED = unchecked ((int)0x80131514L);
+                       const int COR_E_NOTFINITENUMBER = unchecked ((int)0x80131528L);
+                       const int E_NOTIMPL = unchecked ((int)0x80004001L);
+                       const int COR_E_NOTSUPPORTED = unchecked ((int)0x80131515L);
+                       const int COR_E_NULLREFERENCE = unchecked ((int)0x80004003L);
                        const int E_OUTOFMEMORY = unchecked ((int)0x8007000EL);
-                       const int E_INVALIDARG = unchecked ((int)0X80070057);
-                       
-                       switch (errorCode)
-                       {
-                       case E_OUTOFMEMORY:
-                               return new OutOfMemoryException ();
-                       case E_INVALIDARG:
-                               return new ArgumentException ();
+                       const int COR_E_OVERFLOW = unchecked ((int)0x80131516L);
+                       const int COR_E_PATHTOOLONG = unchecked ((int)0x800700CEL);
+                       const int ERROR_FILENAME_EXCED_RANGE = unchecked ((int)0xCE);
+                       const int COR_E_RANK = unchecked ((int)0x80131517L);
+                       const int COR_E_REFLECTIONTYPELOAD = unchecked ((int)0x80131602L);
+                       const int COR_E_REMOTING = unchecked ((int)0x8013150BL);
+                       const int COR_E_SAFEARRAYTYPEMISMATCH = unchecked ((int)0x80131533L);
+                       const int COR_E_SECURITY = unchecked ((int)0x8013150AL);
+                       const int COR_E_SERIALIZATION = unchecked ((int)0x8013150CL);
+                       const int COR_E_STACKOVERFLOW = unchecked ((int)0x800703E9L);
+                       const int ERROR_STACK_OVERFLOW = unchecked ((int)0x03E9);
+                       const int COR_E_SYNCHRONIZATIONLOCK = unchecked ((int)0x80131518L);
+                       const int COR_E_SYSTEM = unchecked ((int)0x80131501L);
+                       const int COR_E_TARGET = unchecked ((int)0x80131603L);
+                       const int COR_E_TARGETINVOCATION = unchecked ((int)0x80131604L);
+                       const int COR_E_TARGETPARAMCOUNT = unchecked ((int)0x8002000EL);
+                       const int COR_E_THREADABORTED = unchecked ((int)0x80131530L);
+                       const int COR_E_THREADINTERRUPTED = unchecked ((int)0x80131519L);
+                       const int COR_E_THREADSTATE = unchecked ((int)0x80131520L);
+                       const int COR_E_THREADSTOP = unchecked ((int)0x80131521L);
+                       const int COR_E_TYPEINITIALIZATION = unchecked ((int)0x80131534L);
+                       const int COR_E_VERIFICATION = unchecked ((int)0x8013150DL);
+                       //const int COR_E_WEAKREFERENCE = unchecked ((int)?);
+                       //const int COR_E_VTABLECALLSNOTSUPPORTED = unchecked ((int));
+
+                       switch (errorCode) {
+                               case MSEE_E_APPDOMAINUNLOADED:
+                                       return new AppDomainUnloadedException ();
+                               case COR_E_APPLICATION:
+                                       return new ApplicationException ();
+                               case E_INVALIDARG:
+                                       return new ArgumentException ();
+                               case COR_E_ARGUMENTOUTOFRANGE:
+                                       return new ArgumentOutOfRangeException ();
+                               case COR_E_ARITHMETIC:
+                                       return new ArithmeticException ();
+                               case COR_E_ARRAYTYPEMISMATCH:
+                                       return new ArrayTypeMismatchException ();
+                               case COR_E_BADIMAGEFORMAT:
+                               case ERROR_BAD_FORMAT:
+                                       return new BadImageFormatException ();
+//                             case COR_E_COMEMULATE_ERROR:
+//                                     return new COMEmulateException ();
+                               case COR_E_CONTEXTMARSHAL:
+                                       return new ContextMarshalException ();
+//                             case COR_E_CORE:
+//                                     return new CoreException ();
+                               case NTE_FAIL:
+                                       return new System.Security.Cryptography.CryptographicException ();
+                               case COR_E_DIRECTORYNOTFOUND:
+                               case ERROR_PATH_NOT_FOUND:
+                                       return new System.IO.DirectoryNotFoundException ();
+                               case COR_E_DIVIDEBYZERO:
+                                       return new DivideByZeroException ();
+                               case COR_E_DUPLICATEWAITOBJECT:
+                                       return new DuplicateWaitObjectException ();
+                               case COR_E_ENDOFSTREAM:
+                                       return new System.IO.EndOfStreamException ();
+                               case COR_E_EXCEPTION:
+                                       return new Exception ();
+                               case COR_E_EXECUTIONENGINE:
+                                       return new ExecutionEngineException ();
+                               case COR_E_FIELDACCESS:
+                                       return new FieldAccessException ();
+                               case COR_E_FILENOTFOUND:
+                               case ERROR_FILE_NOT_FOUND:
+                                       return new System.IO.FileNotFoundException ();
+                               case COR_E_FORMAT:
+                                       return new FormatException ();
+                               case COR_E_INDEXOUTOFRANGE:
+                                       return new IndexOutOfRangeException ();
+                               case COR_E_INVALIDCAST:
+                               // E_NOINTERFACE has same value as COR_E_INVALIDCAST
+                                       return new InvalidCastException ();
+                               case COR_E_INVALIDCOMOBJECT:
+                                       return new InvalidComObjectException ();
+                               case COR_E_INVALIDFILTERCRITERIA:
+                                       return new InvalidFilterCriteriaException ();
+                               case COR_E_INVALIDOLEVARIANTTYPE:
+                                       return new InvalidOleVariantTypeException ();
+                               case COR_E_INVALIDOPERATION:
+                                       return new InvalidOperationException ();
+                               case COR_E_IO:
+                                       return new System.IO.IOException ();
+                               case COR_E_MEMBERACCESS:
+                                       return new MemberAccessException ();
+                               case COR_E_METHODACCESS:
+                                       return new MethodAccessException ();
+                               case COR_E_MISSINGFIELD:
+                                       return new MissingFieldException ();
+                               case COR_E_MISSINGMANIFESTRESOURCE:
+                                       return new System.Resources.MissingManifestResourceException ();
+                               case COR_E_MISSINGMEMBER:
+                                       return new MissingMemberException ();
+                               case COR_E_MISSINGMETHOD:
+                                       return new MissingMethodException ();
+                               case COR_E_MULTICASTNOTSUPPORTED:
+                                       return new MulticastNotSupportedException ();
+                               case COR_E_NOTFINITENUMBER:
+                                       return new NotFiniteNumberException ();
+                               case E_NOTIMPL:
+                                       return new NotImplementedException ();
+                               case COR_E_NOTSUPPORTED:
+                                       return new NotSupportedException ();
+                               case COR_E_NULLREFERENCE:
+                               // E_POINTER has the same value as COR_E_NULLREFERENCE
+                                       return new NullReferenceException ();
+                               case E_OUTOFMEMORY:
+                               // COR_E_OUTOFMEMORY has the same value as E_OUTOFMEMORY
+                                       return new OutOfMemoryException ();
+                               case COR_E_OVERFLOW:
+                                       return new OverflowException ();
+                               case COR_E_PATHTOOLONG:
+                               case ERROR_FILENAME_EXCED_RANGE:
+                                       return new System.IO.PathTooLongException ();
+                               case COR_E_RANK:
+                                       return new RankException ();
+                               case COR_E_REFLECTIONTYPELOAD:
+                                       return new System.Reflection.ReflectionTypeLoadException (new Type[] { }, new Exception[] { });
+                               case COR_E_REMOTING:
+                                       return new System.Runtime.Remoting.RemotingException ();
+                               case COR_E_SAFEARRAYTYPEMISMATCH:
+                                       return new SafeArrayTypeMismatchException ();
+                               case COR_E_SECURITY:
+                                       return new SecurityException ();
+                               case COR_E_SERIALIZATION:
+                                       return new System.Runtime.Serialization.SerializationException ();
+                               case COR_E_STACKOVERFLOW:
+                               case ERROR_STACK_OVERFLOW:
+                                       return new StackOverflowException ();
+                               case COR_E_SYNCHRONIZATIONLOCK:
+                                       return new SynchronizationLockException ();
+                               case COR_E_SYSTEM:
+                                       return new SystemException ();
+                               case COR_E_TARGET:
+                                       return new TargetException ();
+                               case COR_E_TARGETINVOCATION:
+                                       return new System.Reflection.TargetInvocationException (null);
+                               case COR_E_TARGETPARAMCOUNT:
+                                       return new TargetParameterCountException ();
+//                             case COR_E_THREADABORTED:
+//                                     ThreadAbortException c'tor is inaccessible
+//                                     return new System.Threading.ThreadAbortException ();
+                               case COR_E_THREADINTERRUPTED:
+                                       return new ThreadInterruptedException ();
+                               case COR_E_THREADSTATE:
+                                       return new ThreadStateException ();
+//                             case COR_E_THREADSTOP:
+//                                     ThreadStopException does not exist
+//                                     return new System.Threading.ThreadStopException ();
+                               case COR_E_TYPELOAD:
+                                       return new TypeLoadException ();
+                               // MSDN lists COR_E_TYPELOAD twice with different exceptions.
+                               // return new EntryPointNotFoundException ();
+                               case COR_E_TYPEINITIALIZATION:
+                                       return new TypeInitializationException("", null);
+                               case COR_E_VERIFICATION:
+                                       return new VerificationException ();
+//                             case COR_E_WEAKREFERENCE:
+//                                     return new WeakReferenceException ();
+//                             case COR_E_VTABLECALLSNOTSUPPORTED:
+//                                     return new VTableCallsNotSupportedException ();
                        }
                        if (errorCode < 0)
                                return new COMException ("", errorCode);
                        return null;
                }
 
+               [DllImport ("oleaut32.dll", CharSet=CharSet.Unicode, EntryPoint = "SetErrorInfo")]
+               static extern int _SetErrorInfo (int dwReserved,
+                       [MarshalAs(UnmanagedType.Interface)] IErrorInfo pIErrorInfo);
+
+               [DllImport ("oleaut32.dll", CharSet=CharSet.Unicode, EntryPoint = "GetErrorInfo")]
+               static extern int _GetErrorInfo (int dwReserved,
+                       [MarshalAs(UnmanagedType.Interface)] out IErrorInfo ppIErrorInfo);
+
+               static bool SetErrorInfoNotAvailable;
+               static bool GetErrorInfoNotAvailable;
+
+               internal static int SetErrorInfo (int dwReserved, IErrorInfo errorInfo)
+               {
+                       int retVal = 0;
+                       errorInfo = null;
+
+                       if (SetErrorInfoNotAvailable)
+                               return -1;
+
+                       try {
+                               retVal = _SetErrorInfo (dwReserved, errorInfo);
+                       }
+                       catch (Exception) {
+                               // ignore any exception - probably there's no suitable SetErrorInfo
+                               // method available.
+                               SetErrorInfoNotAvailable = true;
+                       }
+                       return retVal;
+               }
+
+               internal static int GetErrorInfo (int dwReserved, out IErrorInfo errorInfo)
+               {
+                       int retVal = 0;
+                       errorInfo = null;
+
+                       if (GetErrorInfoNotAvailable)
+                               return -1;
+
+                       try {
+                               retVal = _GetErrorInfo (dwReserved, out errorInfo);
+                       }
+                       catch (Exception) {
+                               // ignore any exception - probably there's no suitable GetErrorInfo
+                               // method available.
+                               GetErrorInfoNotAvailable = true;
+                       }
+                       return retVal;
+               }
+
+               public static Exception GetExceptionForHR (int errorCode)
+               {
+                       return GetExceptionForHR (errorCode, IntPtr.Zero);
+               }
+
+               public static Exception GetExceptionForHR (int errorCode, IntPtr errorInfoPtr)
+               {
+                       IErrorInfo errorInfo = null;
+                       if (errorInfoPtr != (IntPtr)(-1)) {
+                               if (errorInfoPtr == IntPtr.Zero) {
+                                       if (GetErrorInfo (0, out errorInfo) != 0) {
+                                               errorInfo = null;
+                                       }
+                               } else {
+                                       errorInfo = Marshal.GetObjectForIUnknown (errorInfoPtr) as IErrorInfo;
+                               }
+                       }
+
+                       if (errorInfo is ManagedErrorInfo && ((ManagedErrorInfo)errorInfo).Exception.hresult == errorCode) {
+                               return ((ManagedErrorInfo)errorInfo).Exception;
+                       }
+
+                       Exception e = ConvertHrToException (errorCode);
+                       if (errorInfo != null && e != null) {
+                               uint helpContext;
+                               errorInfo.GetHelpContext (out helpContext);
+                               string str;
+                               errorInfo.GetSource (out str);
+                               e.Source = str;
+                               errorInfo.GetDescription (out str);
+                               e.SetMessage (str);
+                               errorInfo.GetHelpFile (out str);
+
+                               if (helpContext == 0) {
+                                       e.HelpLink = str;
+                               } else {
+                                       e.HelpLink = string.Format ("{0}#{1}", str, helpContext);
+                               }
+                       }
+                       return e;
+               }
+
 #if !FULL_AOT_RUNTIME
                public static int FinalReleaseComObject (object o)
                {
index ffb7ce734497625671f67efd3f9fcc55231a65e1..0347052d2361252524dfb24e5e57158582f98ddf 100644 (file)
@@ -58,6 +58,9 @@ namespace System.Security.Claims {
                                throw new ArgumentNullException ("type");
                        if (value == null)
                                throw new ArgumentNullException ("value");
+
+                       Properties = new Dictionary <string, string> ();
+
                        Type = type;
                        Value = value;
                        ValueType = valueType == null ? ClaimValueTypes.String : valueType;
@@ -91,4 +94,4 @@ namespace System.Security.Claims {
                }
        }
 }
-#endif
\ No newline at end of file
+#endif
index 7096e56cd33f94d6d47e167ec960162873defe24..7beb2d4982c93f211fe8de1d6fc1f6d0abd26d5c 100644 (file)
@@ -24,8 +24,6 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if NET_4_0
-
 using System.Runtime.CompilerServices;
 
 namespace System
@@ -36,7 +34,10 @@ namespace System
 #elif NET_4_0
        [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)]
 #endif
-       public class InvalidTimeZoneException : Exception
+#if NET_4_0
+       public
+#endif
+       class InvalidTimeZoneException : Exception
        {
                public InvalidTimeZoneException () : base ()
                {}
@@ -51,5 +52,3 @@ namespace System
                {}
        }
 }
-
-#endif
index cea224133e4ab73ff1dbd3560b1f764d942c57aa..f4e01b03be322cc4f832f672002573eb025517f7 100644 (file)
@@ -144,22 +144,7 @@ namespace System
                                        return DateTime.SpecifyKind (DateTime.MinValue, DateTimeKind.Local);
                        }
 
-                       DateTime local = DateTime.SpecifyKind (time.Add (utcOffset), DateTimeKind.Local);
-                       DaylightTime dlt = GetDaylightChanges (time.Year);
-                       if (dlt.Delta.Ticks == 0)
-                               return DateTime.SpecifyKind (local, DateTimeKind.Local);
-
-                       // FIXME: check all of the combination of
-                       //      - basis: local-based or UTC-based
-                       //      - hemisphere: Northern or Southern
-                       //      - offset: positive or negative
-
-                       // PST should work fine here.
-                       if (local < dlt.End && dlt.End.Subtract (dlt.Delta) <= local)
-                               return DateTime.SpecifyKind (local, DateTimeKind.Local);
-
-                       TimeSpan localOffset = GetUtcOffset (local);
-                       return DateTime.SpecifyKind (time.Add (localOffset), DateTimeKind.Local);
+                       return DateTime.SpecifyKind (time.Add (utcOffset), DateTimeKind.Local);
                }
 
                public virtual DateTime ToUniversalTime (DateTime time)
@@ -252,17 +237,6 @@ namespace System
                // A yearwise cache of DaylightTime.
                private Dictionary<int, DaylightTime> m_CachedDaylightChanges = new Dictionary<int, DaylightTime> (1);
 
-               // the offset when daylightsaving is not on (in ticks)
-               private long m_ticksOffset;
-
-               // the offset when daylightsaving is not on.
-               [NonSerialized]
-               private TimeSpan utcOffsetWithOutDLS;
-  
-               // the offset when daylightsaving is on.
-               [NonSerialized]
-               private TimeSpan utcOffsetWithDLS;
-
                internal enum TimeZoneData
                {
                        DaylightSavingStartIdx,
@@ -315,8 +289,6 @@ namespace System
                        m_standardName = Locale.GetText (names[(int)TimeZoneNames.StandardNameIdx]);
                        m_daylightName = Locale.GetText (names[(int)TimeZoneNames.DaylightNameIdx]);
 
-                       m_ticksOffset = data[(int)TimeZoneData.UtcOffsetIdx];
-
                        DaylightTime dlt = GetDaylightTimeFromData (data);
                        m_CachedDaylightChanges.Add (now.Year, dlt);
                        OnDeserialization (dlt);
@@ -366,20 +338,7 @@ namespace System
                        if (time.Kind == DateTimeKind.Utc)
                                return TimeSpan.Zero;
 
-                       if (IsDaylightSavingTime (time) && !IsAmbiguousTime (time))
-                               return utcOffsetWithDLS;
-
-                       return utcOffsetWithOutDLS;
-               }
-
-               private bool IsAmbiguousTime (DateTime time)
-               {
-                       if (time.Kind == DateTimeKind.Utc)
-                               return false;
-
-                       DaylightTime changes = GetDaylightChanges (time.Year);
-
-                       return time < changes.End && time >= changes.End - changes.Delta;
+                       return TimeZoneInfo.Local.GetUtcOffset (time);
                }
 
                void IDeserializationCallback.OnDeserialization (object sender)
@@ -400,8 +359,6 @@ namespace System
                        } else
                                this_year = dlt.Start.Year;
                        
-                       utcOffsetWithOutDLS = new TimeSpan (m_ticksOffset);
-                       utcOffsetWithDLS = new TimeSpan (m_ticksOffset + dlt.Delta.Ticks);
                        this_year_dlt = dlt;
                }
 
index 79b094ddde0ad00192c63c5c9253dbfedb54cdec..643b82104b385eddeefe74e3532e6a9ff55b521c 100644 (file)
@@ -24,7 +24,6 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#if NET_4_0
 
 using System.Runtime.CompilerServices;
 
@@ -36,7 +35,10 @@ namespace System
 #elif NET_4_0
        [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)]
 #endif
-       public class TimeZoneNotFoundException : Exception
+#if NET_4_0
+       public
+#endif
+       class TimeZoneNotFoundException : Exception
        {
                public TimeZoneNotFoundException () : base ()
                {}
@@ -51,5 +53,3 @@ namespace System
                {}
        }
 }
-
-#endif
index b1516b8bb1427aa88926bb4cc09e2924cbf10579..5268a3a9766a55efbdb9a4bf1ea874691d021764 100644 (file)
@@ -811,6 +811,7 @@ System.Runtime.InteropServices/IDispatchImplAttribute.cs
 System.Runtime.InteropServices/IDispatchImplType.cs
 System.Runtime.InteropServices/IDLDESC.cs
 System.Runtime.InteropServices/IDLFLAG.cs
+System.Runtime.InteropServices/IErrorInfo.cs
 System.Runtime.InteropServices/IMPLTYPEFLAGS.cs
 System.Runtime.InteropServices/INVOKEKIND.cs
 System.Runtime.InteropServices/IRegistrationServices.cs
@@ -827,6 +828,7 @@ System.Runtime.InteropServices/InvalidOleVariantTypeException.cs
 System.Runtime.InteropServices/LCIDConversionAttribute.cs
 System.Runtime.InteropServices/LIBFLAGS.cs
 System.Runtime.InteropServices/LayoutKind.cs
+System.Runtime.InteropServices/ManagedErrorInfo.cs
 System.Runtime.InteropServices/Marshal.cs
 System.Runtime.InteropServices/MarshalAsAttribute.cs
 System.Runtime.InteropServices/MarshalDirectiveException.cs
index 519eec9a191735c93380098363c6060bd644cf19..e9ff58249ef34610b39221c1f0cb51752a500f00 100644 (file)
@@ -2013,10 +2013,13 @@ mono_class_layout_fields (MonoClass *class)
                                if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
                                        continue;
 
+                               // FIXME: Too much code does this
+#if 0
                                if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) {
                                        char *err_msg = g_strdup_printf ("Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", class->name, field->offset);
                                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
                                }
+#endif
                        }
                        g_free (ref_bitmap);
                }
index 3b0c3a3ec335e070449a21edf73a0e16c527ac53..368388a5dab2fe5bf006844ac910be56d92811bc 100644 (file)
@@ -291,20 +291,30 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
                        available_in_tlab = (int)(TLAB_REAL_END - TLAB_NEXT);//We'll never have tlabs > 2Gb
                        if (size > tlab_size || available_in_tlab > SGEN_MAX_NURSERY_WASTE) {
                                /* Allocate directly from the nursery */
-                               do {
-                                       p = sgen_nursery_alloc (size);
-                                       if (!p) {
-                                               sgen_ensure_free_space (real_size);
-                                               if (degraded_mode)
-                                                       return alloc_degraded (vtable, size, FALSE);
-                                               else
-                                                       p = sgen_nursery_alloc (size);
-                                       }
-                               } while (!p);
+                               p = sgen_nursery_alloc (size);
                                if (!p) {
-                                       // no space left
-                                       g_assert (0);
+                                       /*
+                                        * We couldn't allocate from the nursery, so we try
+                                        * collecting.  Even after the collection, we might
+                                        * still not have enough memory to allocate the
+                                        * object.  The reason will most likely be that we've
+                                        * run out of memory, but there is the theoretical
+                                        * possibility that other threads might have consumed
+                                        * the freed up memory ahead of us, so doing another
+                                        * collection and trying again might actually help.
+                                        * Of course the same thing might happen again.
+                                        *
+                                        * Ideally we'd like to detect that case and loop (if
+                                        * we always loop we will loop endlessly in the case of
+                                        * OOM).  What we do here is give up right away.
+                                        */
+                                       sgen_ensure_free_space (real_size);
+                                       if (degraded_mode)
+                                               return alloc_degraded (vtable, size, FALSE);
+                                       else
+                                               p = sgen_nursery_alloc (size);
                                }
+                               SGEN_ASSERT (0, p, "Out of memory");
 
                                zero_tlab_if_necessary (p, size);
                        } else {
@@ -313,21 +323,16 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
                                        SGEN_LOG (3, "Retire TLAB: %p-%p [%ld]", TLAB_START, TLAB_REAL_END, (long)(TLAB_REAL_END - TLAB_NEXT - size));
                                sgen_nursery_retire_region (p, available_in_tlab);
 
-                               do {
-                                       p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
-                                       if (!p) {
-                                               sgen_ensure_free_space (tlab_size);
-                                               if (degraded_mode)
-                                                       return alloc_degraded (vtable, size, FALSE);
-                                               else
-                                                       p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
-                                       }
-                               } while (!p);
-                                       
+                               p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
                                if (!p) {
-                                       // no space left
-                                       g_assert (0);
+                                       /* See comment above in similar case. */
+                                       sgen_ensure_free_space (tlab_size);
+                                       if (degraded_mode)
+                                               return alloc_degraded (vtable, size, FALSE);
+                                       else
+                                               p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
                                }
+                               SGEN_ASSERT (0, p, "Out of memory");
 
                                /* Allocate a new TLAB from the current nursery fragment */
                                TLAB_START = (char*)p;
index 4b0b5a320121f3c064437be958d7da70e149d8fc..c9a0792c519290d57e2059c1927f663658f78109 100644 (file)
@@ -912,8 +912,8 @@ static int
 pin_objects_from_nursery_pin_queue (ScanCopyContext ctx)
 {
        GCMemSection *section = nursery_section;
-       void **start = section->pin_queue_start;
-       void **end = start + section->pin_queue_num_entries;
+       void **start =  sgen_pinning_get_entry (section->pin_queue_first_entry);
+       void **end = sgen_pinning_get_entry (section->pin_queue_last_entry);
        void *start_nursery = section->data;
        void *end_nursery = section->next_data;
        void *last = NULL;
@@ -1080,13 +1080,11 @@ pin_objects_in_nursery (ScanCopyContext ctx)
 {
        size_t reduced_to;
 
-       if (!nursery_section->pin_queue_num_entries)
+       if (nursery_section->pin_queue_first_entry == nursery_section->pin_queue_last_entry)
                return;
 
        reduced_to = pin_objects_from_nursery_pin_queue (ctx);
-       nursery_section->pin_queue_num_entries = reduced_to;
-       if (!reduced_to)
-               nursery_section->pin_queue_start = NULL;
+       nursery_section->pin_queue_last_entry = nursery_section->pin_queue_first_entry + reduced_to;
 }
 
 
@@ -1101,7 +1099,7 @@ sgen_pin_object (void *object, GrayQueue *queue)
        if (G_UNLIKELY (do_pin_stats))
                sgen_pin_stats_register_object (object, safe_object_get_size (object));
 
-       GRAY_OBJECT_ENQUEUE (queue, object, sgen_obj_get_descriptor (object));
+       GRAY_OBJECT_ENQUEUE (queue, object, sgen_obj_get_descriptor_safe (object));
        binary_protocol_pin (object, (gpointer)LOAD_VTABLE (object), safe_object_get_size (object));
 
 #ifdef ENABLE_DTRACE
@@ -2407,9 +2405,7 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
         * next allocations.
         */
        mono_profiler_gc_event (MONO_GC_EVENT_RECLAIM_START, 0);
-       fragment_total = sgen_build_nursery_fragments (nursery_section,
-                       nursery_section->pin_queue_start, nursery_section->pin_queue_num_entries,
-                       unpin_queue);
+       fragment_total = sgen_build_nursery_fragments (nursery_section, unpin_queue);
        if (!fragment_total)
                degraded_mode = 1;
 
@@ -2600,7 +2596,7 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con
        SGEN_LOG (6, "Pinning from large objects");
        for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) {
                size_t dummy;
-               if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + sgen_los_object_size (bigobj), &dummy)) {
+               if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + sgen_los_object_size (bigobj), &dummy, &dummy)) {
                        binary_protocol_pin (bigobj->data, (gpointer)LOAD_VTABLE (bigobj->data), safe_object_get_size (((MonoObject*)(bigobj->data))));
 
 #ifdef ENABLE_DTRACE
@@ -2860,8 +2856,20 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean
        if (objects_pinned) {
                g_assert (!concurrent_collection_in_progress);
 
-               /*This is slow, but we just OOM'd*/
+               /*
+                * This is slow, but we just OOM'd.
+                *
+                * See comment at `sgen_pin_queue_clear_discarded_entries` for how the pin
+                * queue is laid out at this point.
+                */
                sgen_pin_queue_clear_discarded_entries (nursery_section, old_next_pin_slot);
+               /*
+                * We need to reestablish all pinned nursery objects in the pin queue
+                * because they're needed for fragment creation.  Unpinning happens by
+                * walking the whole queue, so it's not necessary to reestablish where major
+                * heap block pins are - all we care is that they're still in there
+                * somewhere.
+                */
                sgen_optimize_pin_queue ();
                sgen_find_section_pin_queue_start_end (nursery_section);
                objects_pinned = 0;
@@ -2918,7 +2926,7 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean
                 * pinned objects as we go, memzero() the empty fragments so they are ready for the
                 * next allocations.
                 */
-               if (!sgen_build_nursery_fragments (nursery_section, nursery_section->pin_queue_start, nursery_section->pin_queue_num_entries, NULL))
+               if (!sgen_build_nursery_fragments (nursery_section, NULL))
                        degraded_mode = 1;
 
                /* prepare the pin queue for the next collection */
index 12121dc723f7dadc9fad2acce63e771cbe8f99a8..0fa761304114da3fa34dfc4cd29ad74856d0b45c 100644 (file)
@@ -144,8 +144,8 @@ struct _GCMemSection {
         */
        char **scan_starts;
        /* in major collections indexes in the pin_queue for objects that pin this section */
-       void **pin_queue_start;
-       size_t pin_queue_num_entries;
+       size_t pin_queue_first_entry;
+       size_t pin_queue_last_entry;
        size_t num_scan_start;
 };
 
@@ -486,10 +486,6 @@ void sgen_free_internal (void *addr, int type) MONO_INTERNAL;
 void* sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure) MONO_INTERNAL;
 void sgen_free_internal_dynamic (void *addr, size_t size, int type) MONO_INTERNAL;
 
-void** sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *num) MONO_INTERNAL;
-void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL;
-void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL;
-
 void sgen_pin_stats_register_object (char *obj, size_t size);
 void sgen_pin_stats_register_global_remset (char *obj);
 void sgen_pin_stats_print_class_stats (void);
@@ -978,7 +974,7 @@ gboolean sgen_los_object_is_pinned (char *obj) MONO_INTERNAL;
 void sgen_clear_nursery_fragments (void) MONO_INTERNAL;
 void sgen_nursery_allocator_prepare_for_pinning (void) MONO_INTERNAL;
 void sgen_nursery_allocator_set_nursery_bounds (char *nursery_start, char *nursery_end) MONO_INTERNAL;
-mword sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_t num_entries, SgenGrayQueue *unpin_queue) MONO_INTERNAL;
+mword sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue) MONO_INTERNAL;
 void sgen_init_nursery_allocator (void) MONO_INTERNAL;
 void sgen_nursery_allocator_init_heavy_stats (void) MONO_INTERNAL;
 void sgen_alloc_init_heavy_stats (void) MONO_INTERNAL;
index 89806871343ac9bee593570dd242f006527331db..dfe7504242fe7dbc14238bd2d49969312cf23056 100644 (file)
@@ -41,6 +41,7 @@
 #include "metadata/sgen-layout-stats.h"
 #include "metadata/gc-internal.h"
 #include "metadata/sgen-pointer-queue.h"
+#include "metadata/sgen-pinning.h"
 
 #define SGEN_HAVE_CONCURRENT_MARK
 
@@ -74,7 +75,6 @@ typedef struct _MSBlockInfo MSBlockInfo;
 struct _MSBlockInfo {
        int obj_size;
        int obj_size_index;
-       size_t pin_queue_num_entries;
        unsigned int pinned : 1;
        unsigned int has_references : 1;
        unsigned int has_pinned : 1;    /* means cannot evacuate */
@@ -83,7 +83,8 @@ struct _MSBlockInfo {
        char *block;
        void **free_list;
        MSBlockInfo *next_free;
-       void **pin_queue_start;
+       size_t pin_queue_first_entry;
+       size_t pin_queue_last_entry;
 #ifdef SGEN_HAVE_CONCURRENT_MARK
        guint8 *cardtable_mod_union;
 #endif
@@ -1074,18 +1075,21 @@ major_get_and_reset_num_major_objects_marked (void)
 static void
 mark_pinned_objects_in_block (MSBlockInfo *block, SgenGrayQueue *queue)
 {
-       int i;
+       void **entry, **end;
        int last_index = -1;
 
-       if (!block->pin_queue_num_entries)
+       if (block->pin_queue_first_entry == block->pin_queue_last_entry)
                return;
 
        block->has_pinned = TRUE;
 
-       for (i = 0; i < block->pin_queue_num_entries; ++i) {
-               int index = MS_BLOCK_OBJ_INDEX (block->pin_queue_start [i], block);
+       entry = sgen_pinning_get_entry (block->pin_queue_first_entry);
+       end = sgen_pinning_get_entry (block->pin_queue_last_entry);
+
+       for (; entry < end; ++entry) {
+               int index = MS_BLOCK_OBJ_INDEX (*entry, block);
                char *obj;
-               SGEN_ASSERT (9, index >= 0 && index < MS_BLOCK_FREE / block->obj_size, "invalid object %p index %d max-index %d", block->pin_queue_start [i], index, MS_BLOCK_FREE / block->obj_size);
+               SGEN_ASSERT (9, index >= 0 && index < MS_BLOCK_FREE / block->obj_size, "invalid object %p index %d max-index %d", *entry, index, MS_BLOCK_FREE / block->obj_size);
                if (index == last_index)
                        continue;
                obj = MS_BLOCK_OBJ (block, index);
@@ -1626,8 +1630,8 @@ major_find_pin_queue_start_ends (SgenGrayQueue *queue)
        MSBlockInfo *block;
 
        FOREACH_BLOCK (block) {
-               block->pin_queue_start = sgen_find_optimized_pin_queue_area (MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SKIP, MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE,
-                               &block->pin_queue_num_entries);
+               sgen_find_optimized_pin_queue_area (MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SKIP, MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE,
+                               &block->pin_queue_first_entry, &block->pin_queue_last_entry);
        } END_FOREACH_BLOCK;
 }
 
index 01d1bd1a7960cc908c2da78769993a689e53e529..75297a7e1b1c9d79673fb5755b6bd3c9e6dd7f54 100644 (file)
@@ -71,6 +71,7 @@
 #include "metadata/sgen-archdep.h"
 #include "metadata/sgen-bridge.h"
 #include "metadata/sgen-memory-governor.h"
+#include "metadata/sgen-pinning.h"
 #include "metadata/mono-gc.h"
 #include "metadata/method-builder.h"
 #include "metadata/profiler-private.h"
@@ -747,12 +748,12 @@ fragment_list_reverse (SgenFragmentAllocator *allocator)
 }
 
 mword
-sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_t num_entries, SgenGrayQueue *unpin_queue)
+sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue)
 {
        char *frag_start, *frag_end;
        size_t frag_size;
-       size_t i = 0;
        SgenFragment *frags_ranges;
+       void **pin_start, **pin_entry, **pin_end;
 
 #ifdef NALLOC_DEBUG
        reset_alloc_records ();
@@ -769,14 +770,17 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_
        /* clear scan starts */
        memset (nursery_section->scan_starts, 0, nursery_section->num_scan_start * sizeof (gpointer));
 
-       while (i < num_entries || frags_ranges) {
+       pin_start = pin_entry = sgen_pinning_get_entry (nursery_section->pin_queue_first_entry);
+       pin_end = sgen_pinning_get_entry (nursery_section->pin_queue_last_entry);
+
+       while (pin_entry < pin_end || frags_ranges) {
                char *addr0, *addr1;
                size_t size;
                SgenFragment *last_frag = NULL;
 
                addr0 = addr1 = sgen_nursery_end;
-               if (i < num_entries)
-                       addr0 = start [i];
+               if (pin_entry < pin_end)
+                       addr0 = *pin_entry;
                if (frags_ranges)
                        addr1 = frags_ranges->fragment_start;
 
@@ -789,7 +793,7 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_
                        CANARIFY_SIZE (size);
                        sgen_set_nursery_scan_start (addr0);
                        frag_end = addr0;
-                       ++i;
+                       ++pin_entry;
                } else {
                        frag_end = addr1;
                        size = frags_ranges->fragment_next - addr1;
@@ -809,7 +813,7 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_
 
                frag_size = size;
 #ifdef NALLOC_DEBUG
-               add_alloc_record (start [i], frag_size, PINNING);
+               add_alloc_record (*pin_entry, frag_size, PINNING);
 #endif
                frag_start = frag_end + frag_size;
        }
@@ -830,9 +834,10 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_
        sgen_minor_collector.build_fragments_finish (&mutator_allocator);
 
        if (!unmask (mutator_allocator.alloc_head)) {
-               SGEN_LOG (1, "Nursery fully pinned (%zd)", num_entries);
-               for (i = 0; i < num_entries; ++i) {
-                       SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", start [i], sgen_safe_name (start [i]), sgen_safe_object_get_size (start [i]));
+               SGEN_LOG (1, "Nursery fully pinned");
+               for (pin_entry = pin_start; pin_entry < pin_end; ++pin_entry) {
+                       void *p = *pin_entry;
+                       SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", p, sgen_safe_name (p), sgen_safe_object_get_size (p));
                }
        }
        return fragment_total;
index 71a8dbefebe0999513e55b4d083fd79e7d2665c9..c895d7471ea53e0539423c751e2aacb20c06e980 100644 (file)
@@ -59,50 +59,89 @@ sgen_pin_stage_ptr (void *ptr)
        sgen_pointer_queue_add (&pin_queue, ptr);
 }
 
+gboolean
+sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *first_out, size_t *last_out)
+{
+       size_t first = sgen_pointer_queue_search (&pin_queue, start);
+       size_t last = sgen_pointer_queue_search (&pin_queue, end);
+       SGEN_ASSERT (0, last == pin_queue.next_slot || pin_queue.data [last] >= end, "Pin queue search gone awry");
+       *first_out = first;
+       *last_out = last;
+       return first != last;
+}
+
 void**
-sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *num)
+sgen_pinning_get_entry (size_t index)
 {
-       size_t first, last;
-       first = sgen_pointer_queue_search (&pin_queue, start);
-       last = sgen_pointer_queue_search (&pin_queue, end);
-       *num = last - first;
-       if (first == last)
-               return NULL;
-       return pin_queue.data + first;
+       SGEN_ASSERT (0, index <= pin_queue.next_slot, "Pin queue entry out of range");
+       return &pin_queue.data [index];
 }
 
 void
 sgen_find_section_pin_queue_start_end (GCMemSection *section)
 {
        SGEN_LOG (6, "Pinning from section %p (%p-%p)", section, section->data, section->end_data);
-       section->pin_queue_start = sgen_find_optimized_pin_queue_area (section->data, section->end_data, &section->pin_queue_num_entries);
-       SGEN_LOG (6, "Found %zd pinning addresses in section %p", section->pin_queue_num_entries, section);
+
+       sgen_find_optimized_pin_queue_area (section->data, section->end_data,
+                       &section->pin_queue_first_entry, &section->pin_queue_last_entry);
+
+       SGEN_LOG (6, "Found %zd pinning addresses in section %p",
+                       section->pin_queue_last_entry - section->pin_queue_first_entry, section);
 }
 
 /*This will setup the given section for the while pin queue. */
 void
 sgen_pinning_setup_section (GCMemSection *section)
 {
-       section->pin_queue_start = pin_queue.data;
-       section->pin_queue_num_entries = pin_queue.next_slot;
+       section->pin_queue_first_entry = 0;
+       section->pin_queue_last_entry = pin_queue.next_slot;
 }
 
 void
 sgen_pinning_trim_queue_to_section (GCMemSection *section)
 {
-       pin_queue.next_slot = section->pin_queue_num_entries;
+       SGEN_ASSERT (0, section->pin_queue_first_entry == 0, "Pin queue trimming assumes the whole pin queue is used by the nursery");
+       pin_queue.next_slot = section->pin_queue_last_entry;
 }
 
+/*
+ * This is called when we've run out of memory during a major collection.
+ *
+ * After collecting potential pin entries and sorting the array, this is what it looks like:
+ *
+ * +--------------------+---------------------------------------------+--------------------+
+ * | major heap entries |               nursery entries               | major heap entries |
+ * +--------------------+---------------------------------------------+--------------------+
+ *
+ * Of course there might not be major heap entries before and/or after the nursery entries,
+ * depending on where the major heap sections are in the address space, and whether there
+ * were any potential pointers there.
+ *
+ * When we pin nursery objects, we compact the nursery part of the pin array, which leaves
+ * discarded entries after the ones that actually pointed to nursery objects:
+ *
+ * +--------------------+-----------------+---------------------------+--------------------+
+ * | major heap entries | nursery entries | discarded nursery entries | major heap entries |
+ * +--------------------+-----------------+---------------------------+--------------------+
+ *
+ * When, due to being out of memory, we late pin more objects, the pin array looks like
+ * this:
+ *
+ * +--------------------+-----------------+---------------------------+--------------------+--------------+
+ * | major heap entries | nursery entries | discarded nursery entries | major heap entries | late entries |
+ * +--------------------+-----------------+---------------------------+--------------------+--------------+
+ *
+ * This function gets rid of the discarded nursery entries by nulling them out.  Note that
+ * we can late pin objects not only in the nursery but also in the major heap, which happens
+ * when evacuation fails.
+ */
 void
 sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_slot)
 {
-       void **start = section->pin_queue_start + section->pin_queue_num_entries;
-       void **end = pin_queue.data + max_pin_slot;
+       void **start = sgen_pinning_get_entry (section->pin_queue_last_entry);
+       void **end = sgen_pinning_get_entry (max_pin_slot);
        void *addr;
 
-       if (!start)
-               return;
-
        for (; start < end; ++start) {
                addr = *start;
                if ((char*)addr < section->data || (char*)addr > section->end_data)
index 19840beb646c4d2fb0ba2b66de4c6b6a332899cd..9a2dcbb2c5781306df28516c0c7114ecca9cd0eb 100644 (file)
@@ -38,6 +38,11 @@ void sgen_pinning_trim_queue_to_section (GCMemSection *section) MONO_INTERNAL;
 
 void sgen_dump_pin_queue (void) MONO_INTERNAL;
 
+gboolean sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *first_out, size_t *last_out) MONO_INTERNAL;
+void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL;
+void** sgen_pinning_get_entry (size_t index) MONO_INTERNAL;
+void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL;
+
 /* Pinning stats */
 
 void sgen_pin_stats_register_address (char *addr, int pin_type) MONO_INTERNAL;
index cbce0f772694e052aecff7c62090ddb2140fa93c..949164e5548c4e82fcc5f27f9c524c9963c825ba 100644 (file)
 #include <glib.h>
 #include <string.h>
 #include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <errno.h>
-
-#include <sys/types.h>
 #ifdef HOST_WIN32
 #include <ws2tcpip.h>
 #else
 #include <netdb.h>
 #include <arpa/inet.h>
 #endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <sys/types.h>
 
 #include <mono/metadata/object.h>
 #include <mono/io-layer/io-layer.h>
index 3c712920d4f2bdb11c302cf7f08aa0463431655a..36514cc6ea8a06c0f26c553ecb68e59de2d846a7 100644 (file)
@@ -785,6 +785,13 @@ typedef struct {
        gint8 nthreads_diff;
 } SamplesHistory;
 
+/*
+ * returns :
+ *  -  1 if the number of threads should increase
+ *  -  0 if it should not change
+ *  - -1 if it should decrease
+ *  - -2 in case of error
+ */
 static gint8
 monitor_heuristic (gint16 *current, gint16 *history_size, SamplesHistory *history, ThreadPool *tp)
 {
@@ -829,6 +836,10 @@ monitor_heuristic (gint16 *current, gint16 *history_size, SamplesHistory *histor
                decision = 2;
        } else {
                mono_mutex_lock (&threads_lock);
+               if (threads == NULL) {
+                       mono_mutex_unlock (&threads_lock);
+                       return -2;
+               }
                all_waitsleepjoin = TRUE;
                for (i = 0; i < threads->len; ++i) {
                        thread = g_ptr_array_index (threads, i);
@@ -910,6 +921,10 @@ monitor_thread (gpointer unused)
                if (suspended)
                        continue;
 
+               /* threadpool is cleaning up */
+               if (async_tp.pool_status == 2 || async_io_tp.pool_status == 2)
+                       break;
+
                switch (monitor_state) {
                case MONITOR_STATE_AWAKE:
                        num_waiting_iterations = 0;
@@ -939,9 +954,9 @@ monitor_thread (gpointer unused)
                        } else {
                                gint8 nthreads_diff = monitor_heuristic (&current, &history_size, history, tp);
 
-                               if (nthreads_diff > 0)
+                               if (nthreads_diff == 1)
                                        threadpool_start_thread (tp);
-                               else if (nthreads_diff < 0)
+                               else if (nthreads_diff == -1)
                                        threadpool_kill_thread (tp);
                        }
                }
@@ -992,6 +1007,7 @@ mono_thread_pool_init (void)
 
        mono_mutex_init (&threads_lock);
        threads = g_ptr_array_sized_new (thread_count);
+       g_assert (threads);
 
        mono_mutex_init_recursive (&wsqs_lock);
        wsqs = g_ptr_array_sized_new (MAX (100 * cpu_count, thread_count));
@@ -1182,6 +1198,7 @@ threadpool_start_thread (ThreadPool *tp)
                        thread = mono_thread_create_internal (mono_get_root_domain (), tp->async_invoke, tp, TRUE, stack_size);
                        if (!tp->is_io) {
                                mono_mutex_lock (&threads_lock);
+                               g_assert (threads != NULL);
                                g_ptr_array_add (threads, thread);
                                mono_mutex_unlock (&threads_lock);
                        }
@@ -1704,9 +1721,14 @@ async_invoke_thread (gpointer data)
                                        if (tp_finish_func)
                                                tp_finish_func (tp_hooks_user_data);
 
-                                       mono_mutex_lock (&threads_lock);
-                                       g_ptr_array_remove_fast (threads, mono_thread_current ()->internal_thread);
-                                       mono_mutex_unlock (&threads_lock);
+                                       if (!tp->is_io) {
+                                               if (threads) {
+                                                       mono_mutex_lock (&threads_lock);
+                                                       if (threads)
+                                                               g_ptr_array_remove_fast (threads, mono_thread_current ()->internal_thread);
+                                                       mono_mutex_unlock (&threads_lock);
+                                               }
+                                       }
 
                                        return;
                                }
index b4c85e1a4d318c7138c0ff43431c8eed3e8edbf4..d43605ce620c8c9e472e83debd2a1451ae4b5356 100755 (executable)
@@ -344,6 +344,7 @@ sparc_sources = \
 s390x_sources = \
        mini-s390x.c            \
        mini-s390x.h            \
+       support-s390x.h         \
        exceptions-s390x.c      \
        tramp-s390x.c
 
index 4b53f0cae197a61f4991636cd2179bafe4f0b333..d5bb922e142aae06542a892cd6c357aa5e4625be 100644 (file)
  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
  */
 
-/* Remaining AOT-only work:
- * - optimize the trampolines, generate more code in the arch files.
- * - make things more consistent with how elf works, for example, use ELF 
- *   relocations.
- * Remaining generics sharing work:
- * - optimize the size of the data which is encoded.
- * - optimize the runtime loading of data:
- *   - the trampoline code calls mono_jit_info_table_find () to find the rgctx, 
- *     which loads the debugging+exception handling info for the method. This is a 
- *     huge waste of time and code, since the rgctx structure is currently empty.
- */
 #include "config.h"
 #include <sys/types.h>
 #ifdef HAVE_UNISTD_H
@@ -42,7 +31,6 @@
 #include <errno.h>
 #include <sys/stat.h>
 
-
 #include <mono/metadata/abi-details.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/class.h>
@@ -1274,6 +1262,11 @@ arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
                g_assert (code - buf == 8);
                emit_bytes (acfg, buf, code - buf);
        }
+
+       acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_SPECIFIC] = 16;
+       acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = 16;
+       acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT_THUNK] = 72;
+       acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = 16;
 #elif defined(TARGET_ARM64)
        arm64_emit_specific_trampoline_pages (acfg);
 #endif
index e9b5f42668a6b634bee63d6e68043e4c050669d1..97d22706db0440ac1d2d695d1bdcd26a93a57f43 100644 (file)
@@ -4476,13 +4476,6 @@ mono_aot_get_trampoline (const char *name)
 #include <mach/mach.h>
 
 static TrampolinePage* trampoline_pages [MONO_AOT_TRAMP_NUM];
-/* these sizes are for ARM code, parametrize if porting to other architectures (see arch_emit_specific_trampoline_pages)
- * trampoline size is assumed to be 8 bytes below as well (8 is the minimum for 32 bit archs, since we need to store
- * two pointers for trampoline in the data page).
- * the minimum for the common code must be at least sizeof(TrampolinePage), since we store the page info at the
- * beginning of the data page.
- */
-static const int trampolines_pages_code_offsets [MONO_AOT_TRAMP_NUM] = {16, 16, 72, 16};
 
 static unsigned char*
 get_new_trampoline_from_page (int tramp_type)
@@ -4571,11 +4564,7 @@ get_new_trampoline_from_page (int tramp_type)
                page = (TrampolinePage*)addr;
                page->next = trampoline_pages [tramp_type];
                trampoline_pages [tramp_type] = page;
-#ifdef TARGET_ARM64
                page->trampolines = (void*)(taddr + amodule->info.tramp_page_code_offsets [tramp_type]);
-#else
-               page->trampolines = (void*)(taddr + trampolines_pages_code_offsets [tramp_type]);
-#endif
                page->trampolines_end = (void*)(taddr + psize - 64);
                code = page->trampolines;
                page->trampolines += specific_trampoline_size;
index b3dce352ec640faff6fbb71abd21c2aeaab6042c..2eee2e4e57de2513cea47bc74092da93ed3c6aa0 100644 (file)
@@ -283,6 +283,7 @@ long_xor: dest:i src1:i src2:i len:8
 long_neg: dest:i src1:i len:6
 long_not: dest:i src1:i len:12
 long_rem: dest:i src1:i src2:i len:12
+long_rem_imm: dest:i src1:i src2:i len:12
 long_rem_un: dest:i src1:i src2:i len:16
 long_shl: dest:i src1:i src2:i len:14
 long_shl_imm: dest:i src1:i len:14
index 907d7582ae2de63fd2970c2b4d5a1de504721fe3..f29e913acf91e5849479f9e12d74514ffa68c1df 100644 (file)
@@ -486,6 +486,9 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                        ins->opcode = OP_ICONST;
                        MONO_INST_NULLIFY_SREGS (ins);
                        ins->inst_c0 = 0;
+#if __s390__
+               }
+#else
                } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
                        gboolean is_long = ins->opcode == OP_LREM_IMM;
                        int compensator_reg = alloc_ireg (cfg);
@@ -497,12 +500,12 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
 
                        if (power > 1) {
                                intermediate_reg = compensator_reg;
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_SHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
                        } else {
                                intermediate_reg = ins->sreg1;
                        }
 
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_SHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_ISHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
                        MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
                        /* Compute remainder */
                        MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
@@ -511,6 +514,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
 
                        NULLIFY_INS (ins);
                }
+#endif
                break;
        }
 
index 7560fcf012b2f17193f4548f1830cac936fb0d54..bf5e16f8fac47d2e005ca5c7c4e2f205cc2513c8 100644 (file)
 
 #include "mini-llvm-cpp.h"
 
-#define LLVM_CHECK_VERSION(major,minor) \
-       ((LLVM_MAJOR_VERSION > (major)) ||                                                                      \
-        ((LLVM_MAJOR_VERSION == (major)) && (LLVM_MINOR_VERSION >= (minor))))
-
 // extern "C" void LLVMInitializeARMTargetInfo();
 // extern "C" void LLVMInitializeARMTarget ();
 // extern "C" void LLVMInitializeARMTargetMC ();
@@ -606,7 +602,6 @@ mono_llvm_create_ee (LLVMModuleProviderRef MP, AllocCodeMemoryCb *alloc_cb, Func
   // EngineBuilder no longer has a copy assignment operator (?)
   std::unique_ptr<Module> Owner(unwrap(MP));
   EngineBuilder b (std::move(Owner));
-  EngineBuilder &eb = b;
 #ifdef TARGET_AMD64
   ExecutionEngine *EE = b.setJITMemoryManager (mono_mm).setTargetOptions (opts).setAllocateGVsWithCode (true).setMCPU (cpu_name).setCodeModel (CodeModel::Large).create ();
 #else
index 2b778c3aaabbc729d6ca9f41b2c6b4e77242aee1..28e76665e16b5a197410e2f8833ed6419092e315 100644 (file)
@@ -420,6 +420,7 @@ type_is_unsigned (EmitContext *ctx, MonoType *t)
        switch (t->type) {
        case MONO_TYPE_U1:
        case MONO_TYPE_U2:
+       case MONO_TYPE_CHAR:
        case MONO_TYPE_U4:
        case MONO_TYPE_U8:
                return TRUE;
@@ -437,7 +438,12 @@ static LLVMTypeRef
 type_to_llvm_arg_type (EmitContext *ctx, MonoType *t)
 {
        LLVMTypeRef ptype = type_to_llvm_type (ctx, t);
-       
+
+       /*
+        * This works on all abis except arm64/ios which passes multiple
+        * arguments in one stack slot.
+        */
+#ifndef TARGET_ARM64
        if (ptype == LLVMInt8Type () || ptype == LLVMInt16Type ()) {
                /* 
                 * LLVM generates code which only sets the lower bits, while JITted
@@ -445,6 +451,7 @@ type_to_llvm_arg_type (EmitContext *ctx, MonoType *t)
                 */
                ptype = LLVMInt32Type ();
        }
+#endif
 
        return ptype;
 }
@@ -1817,7 +1824,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
                                ctx->values [reg] = LLVMBuildLoad (builder, ctx->addresses [reg], "");
                        }
                } else {
-                       ctx->values [reg] = convert (ctx, ctx->values [reg], llvm_type_to_stack_type (type_to_llvm_type (ctx, sig->params [i])));
+                       ctx->values [reg] = convert_full (ctx, ctx->values [reg], llvm_type_to_stack_type (type_to_llvm_type (ctx, sig->params [i])), type_is_unsigned (ctx, sig->params [i]));
                }
        }
 
@@ -5390,7 +5397,8 @@ mono_llvm_emit_aot_module (const char *filename, int got_size)
                                LLVMValueRef lmethod;
 
                                lmethod = g_hash_table_lookup (module->method_to_lmethod, ji->data.method);
-                               if (lmethod) {
+                               /* The types might not match because the caller might pass an rgctx */
+                               if (lmethod && LLVMTypeOf (callee) == LLVMTypeOf (lmethod)) {
                                        mono_llvm_replace_uses_of (callee, lmethod);
                                        mono_aot_mark_unused_llvm_plt_entry (ji);
                                }
index 435ef2904a495ce910dd6a9aa36e55ea1d9db6f7..d84c87860d1f95b652405201c0823ed719a62097 100644 (file)
@@ -624,7 +624,7 @@ indent (int diff) {
        if (diff < 0)
                indent_level += diff;
        v = indent_level;
-       printf("%p [%3d] ",pthread_self(),v);
+       printf("%p [%3d] ",(void *)pthread_self(),v);
        while (v-- > 0) {
                printf (". ");
        }
@@ -2798,6 +2798,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_IREM_UN_IMM:
                case OP_LAND_IMM:
                case OP_LOR_IMM:
+               case OP_LREM_IMM:
                case OP_LXOR_IMM:
                case OP_LOCALLOC_IMM:
                        mono_decompose_op_imm (cfg, bb, ins);
@@ -3312,6 +3313,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_lgr  (code, ins->dreg, s390_r0);
                        break;
                }
+               case OP_LREM_IMM: {
+                       if (s390_is_imm16 (ins->inst_imm)) {
+                               s390_lghi (code, s390_r13, ins->inst_imm);
+                       } else {
+                               s390_lgfi (code, s390_r13, ins->inst_imm);
+                       }
+                       s390_lgr  (code, s390_r0, ins->sreg1);
+                       s390_dsgr (code, s390_r0, s390_r13);
+                       s390_lgfr (code, ins->dreg, s390_r0);
+               }
+                       break;
                case OP_LREM_UN: {
                        s390_lgr   (code, s390_r1, ins->sreg1);
                        s390_lghi  (code, s390_r0, 0);
@@ -5735,9 +5747,35 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
 /*------------------------------------------------------------------*/
 
 gpointer
-mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
+mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, 
+                                           int offset, gboolean load_imt_reg)
 {
-       return NULL;
+       guint8 *code, *start;
+       int size = 20;
+
+       start = code = mono_global_codeman_reserve (size);
+
+       /*
+        * Replace the "this" argument with the target
+        */
+       s390_lgr  (code, s390_r1, s390_r2);
+       s390_lg   (code, s390_r2, s390_r1, 0, MONO_STRUCT_OFFSET(MonoDelegate, target));        
+       
+       /*
+        * Load the IMT register, if needed
+        */
+       if (load_imt_reg) {
+               s390_lg  (code, MONO_ARCH_IMT_REG, s390_r2, 0, MONO_STRUCT_OFFSET(MonoDelegate, method));
+       }
+
+       /*
+        * Load the vTable
+        */
+       s390_lg  (code, s390_r1, s390_r2, 0, MONO_STRUCT_OFFSET(MonoObject, vtable));
+       s390_agfi(code, s390_r1, offset);
+       s390_br  (code, s390_r1);
+
+       return(start);
 }
 
 /*========================= End of Function ========================*/
@@ -5833,7 +5871,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain,
                                                s390_lg   (code, s390_r1, 0, s390_r1, 0);
                                        }
                                        s390_br   (code, s390_r1);
-                                       target = S390_RELATIVE(code, item->jmp_code);
+                                       target = (gint64) S390_RELATIVE(code, item->jmp_code);
                                        s390_patch_rel(item->jmp_code+2, target);
                                        S390_SET  (code, s390_r1, fail_tramp);
                                        s390_br   (code, s390_r1);
@@ -5863,7 +5901,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain,
                if (item->jmp_code) {
                        if (item->check_target_idx) {
                                gint64 offset;
-                               offset = S390_RELATIVE(imt_entries [item->check_target_idx]->code_target,
+                               offset = (gint64) S390_RELATIVE(imt_entries [item->check_target_idx]->code_target,
                                                       item->jmp_code);
                                s390_patch_rel ((guchar *) item->jmp_code + 2, (guint64) offset);
                        }
@@ -5932,7 +5970,7 @@ mono_arch_get_cie_program (void)
 {
        GSList *l = NULL;
 
-       mono_add_unwind_op_def_cfa (l, NULL, NULL, STK_BASE, 0);
+       mono_add_unwind_op_def_cfa (l, 0, 0, STK_BASE, 0);
 
        return(l);
 }
index 8d9bcc9f2065aad4a88f8d1510fdc5107a80d27d..e345cadc55bc984b594731b26cc8faef15ad2a45 100755 (executable)
 #define COMPILE_SOFT_FLOAT(cfg) (0)
 #endif
 
-#ifdef ENABLE_LLVM
-#define LLVM_CHECK_VERSION(major,minor) \
-       ((LLVM_MAJOR_VERSION > (major)) ||                                                                      \
-        ((LLVM_MAJOR_VERSION == (major)) && (LLVM_MINOR_VERSION >= (minor))))
-#else
-#define LLVM_CHECK_VERSION(major,minor) 0
-#endif
-
 #define NOT_IMPLEMENTED do { g_assert_not_reached (); } while (0)
 
 /* for 32 bit systems */
index 62edcc4e7e9279bb91bdb4079c45b25be997a27f..f93dc88c0c6922e3b097ffd2c0f488df657801d9 100644 (file)
@@ -4,8 +4,12 @@
 #define S390_SET(loc, dr, v)                                   \
        do {                                                    \
                guint64 val = (guint64) v;                      \
-               if (s390_is_uimm16(val)) {                      \
+               if (s390_is_imm16(val)) {                       \
+                       s390_lghi(loc, dr, val);                \
+               } else if (s390_is_uimm16(val)) {               \
                        s390_llill(loc, dr, val);               \
+               } else if (s390_is_imm32(val)) {                \
+                       s390_lgfi(loc, dr, val);                \
                } else if (s390_is_uimm32(val)) {               \
                        s390_llilf(loc, dr, val);               \
                } else {                                        \
index cc70df01822c4cf2863a4e6c185406067de62847..f61f3dd3ee37d9d22e57b18715cb40a9a264acad 100644 (file)
@@ -19,9 +19,6 @@
 
 #if defined(TARGET_X86)
 
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__DragonFly__)
-#include <ucontext.h>
-#endif
 #if defined(__APPLE__)
 #include <AvailabilityMacros.h>
 #endif
@@ -90,7 +87,7 @@
        #define UCONTEXT_REG_EIP(ctx) (((ucontext_t*)(ctx))->uc_mcontext.gregs [EIP])
 #else
 
-#if defined(PLATFORM_ANDROID)
+#if defined(PLATFORM_ANDROID) && !defined(HAVE_UCONTEXT_H)
 /* No ucontext.h as of NDK v6b */
 typedef int greg_t;
 #define NGREG 19