Merge pull request #1369 from DynamicDevices/ajl/appveyor
authorJoão Matos <joao@tritao.eu>
Tue, 28 Oct 2014 16:47:19 +0000 (16:47 +0000)
committerJoão Matos <joao@tritao.eu>
Tue, 28 Oct 2014 16:47:19 +0000 (16:47 +0000)
[CI] Add appveyor.yml configuration file to support Windows build

14 files changed:
acinclude.m4
eglib/acinclude.m4
libgc/acinclude.m4
mcs/class/System.Web.Abstractions/System.Web/HttpResponseBase.cs
mcs/class/System.Web.Abstractions/System.Web/HttpResponseWrapper.cs
mcs/class/System.Web/System.Web.Security/FormsAuthenticationModule.cs
mcs/class/System.Web/System.Web/HttpResponse.cs
mcs/class/System/System.IO/FileSystemWatcher.cs
mcs/class/System/System.IO/KeventWatcher.cs
mcs/class/System/System.IO/SearchPattern.cs
mono/metadata/socket-io.c
mono/metadata/threadpool.c
mono/mini/Makefile.am.in
mono/mini/decompose.c

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 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 0a3aa6694dd392a73ce18b7fa3b90133822cc49b..921ace9ea843e78321ab1d21c19f8bb476188dec 100644 (file)
@@ -105,6 +105,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..1d9c20781719eca5fafb0470f0ca2a40e50bb5e8 100644 (file)
@@ -169,6 +169,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 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
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;
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 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 907d7582ae2de63fd2970c2b4d5a1de504721fe3..6e9d4aaef7190601aab7461fa11b92e62e521008 100644 (file)
@@ -497,12 +497,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);