1 // 2 // Mono.Unix/UnixSignal.cs 3 // 4 // Authors: 5 // Jonathan Pryor (jpryor@novell.com) 6 // Tim Jenks (tim.jenks@realtimeworlds.com) 7 // 8 // (C) 2008 Novell, Inc. 9 // 10 // Permission is hereby granted, free of charge, to any person obtaining 11 // a copy of this software and associated documentation files (the 12 // "Software"), to deal in the Software without restriction, including 13 // without limitation the rights to use, copy, modify, merge, publish, 14 // distribute, sublicense, and/or sell copies of the Software, and to 15 // permit persons to whom the Software is furnished to do so, subject to 16 // the following conditions: 17 // 18 // The above copyright notice and this permission notice shall be 19 // included in all copies or substantial portions of the Software. 20 // 21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 // 29 30 using System; 31 using System.Runtime.InteropServices; 32 using System.Threading; 33 34 using Mono.Unix.Native; 35 36 namespace Mono.Unix { 37 38 public class UnixSignal : WaitHandle { 39 private int signum; 40 private IntPtr signal_info; 41 UnixSignal()42 static UnixSignal () 43 { 44 Stdlib.VersionCheck (); 45 } 46 UnixSignal(Signum signum)47 public UnixSignal (Signum signum) 48 { 49 this.signum = NativeConvert.FromSignum (signum); 50 this.signal_info = install (this.signum); 51 if (this.signal_info == IntPtr.Zero) { 52 throw new ArgumentException ("Unable to handle signal", "signum"); 53 } 54 } 55 UnixSignal(Mono.Unix.Native.RealTimeSignum rtsig)56 public UnixSignal (Mono.Unix.Native.RealTimeSignum rtsig) 57 { 58 signum = NativeConvert.FromRealTimeSignum (rtsig); 59 this.signal_info = install (this.signum); 60 Native.Errno err = Native.Stdlib.GetLastError (); 61 if (this.signal_info == IntPtr.Zero) { 62 if (err == Native.Errno.EADDRINUSE) 63 throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum"); 64 throw new ArgumentException ("Unable to handle signal", "signum"); 65 } 66 } 67 68 public Signum Signum { 69 get { 70 if (IsRealTimeSignal) 71 throw new InvalidOperationException ("This signal is a RealTimeSignum"); 72 return NativeConvert.ToSignum (signum); 73 } 74 } 75 76 public RealTimeSignum RealTimeSignum { 77 get { 78 if (!IsRealTimeSignal) 79 throw new InvalidOperationException ("This signal is not a RealTimeSignum"); 80 return NativeConvert.ToRealTimeSignum (signum-GetSIGRTMIN ()); 81 } 82 } 83 84 public bool IsRealTimeSignal { 85 get { 86 AssertValid (); 87 int sigrtmin = GetSIGRTMIN (); 88 if (sigrtmin == -1) 89 return false; 90 return signum >= sigrtmin; 91 } 92 } 93 94 [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, 95 EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)] install(int signum)96 private static extern IntPtr install (int signum); 97 98 [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, 99 EntryPoint="Mono_Unix_UnixSignal_uninstall")] uninstall(IntPtr info)100 private static extern int uninstall (IntPtr info); 101 102 [UnmanagedFunctionPointer (CallingConvention.Cdecl)] Mono_Posix_RuntimeIsShuttingDown()103 delegate int Mono_Posix_RuntimeIsShuttingDown (); 104 static Mono_Posix_RuntimeIsShuttingDown ShuttingDown = RuntimeShuttingDownCallback; 105 RuntimeShuttingDownCallback()106 static int RuntimeShuttingDownCallback () 107 { 108 return Environment.HasShutdownStarted ? 1 : 0; 109 } 110 111 [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, 112 EntryPoint="Mono_Unix_UnixSignal_WaitAny")] WaitAny(IntPtr[] infos, int count, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down)113 private static extern int WaitAny (IntPtr[] infos, int count, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down); 114 115 [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, 116 EntryPoint="Mono_Posix_SIGRTMIN")] GetSIGRTMIN()117 internal static extern int GetSIGRTMIN (); 118 119 [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, 120 EntryPoint="Mono_Posix_SIGRTMAX")] GetSIGRTMAX()121 internal static extern int GetSIGRTMAX (); 122 AssertValid()123 private void AssertValid () 124 { 125 if (signal_info == IntPtr.Zero) 126 throw new ObjectDisposedException (GetType().FullName); 127 } 128 129 private unsafe SignalInfo* Info { 130 get { 131 AssertValid (); 132 return (SignalInfo*) signal_info; 133 } 134 } 135 136 public bool IsSet { 137 get { 138 return Count > 0; 139 } 140 } 141 Reset()142 public unsafe bool Reset () 143 { 144 int n = Interlocked.Exchange (ref Info->count, 0); 145 return n != 0; 146 } 147 148 public unsafe int Count { 149 get {return Info->count;} 150 set {Interlocked.Exchange (ref Info->count, value);} 151 } 152 153 // signum, count, write_fd, pipecnt, and pipelock are read from a signal handler thread 154 // count and pipelock are both read and written from the signal handler thread 155 #pragma warning disable 649 156 [Map] 157 struct SignalInfo { 158 public int signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler; 159 public IntPtr handler; // Backed-up handler to restore when signal unregistered 160 } 161 #pragma warning restore 649 162 163 #region WaitHandle overrides Dispose(bool disposing)164 protected unsafe override void Dispose (bool disposing) 165 { 166 base.Dispose (disposing); 167 if (signal_info == IntPtr.Zero) 168 return; 169 uninstall (signal_info); 170 signal_info = IntPtr.Zero; 171 } 172 WaitOne()173 public override bool WaitOne () 174 { 175 return WaitOne (-1, false); 176 } 177 WaitOne(TimeSpan timeout, bool exitContext)178 public override bool WaitOne (TimeSpan timeout, bool exitContext) 179 { 180 long ms = (long) timeout.TotalMilliseconds; 181 if (ms < -1 || ms > Int32.MaxValue) 182 throw new ArgumentOutOfRangeException ("timeout"); 183 return WaitOne ((int) ms, exitContext); 184 } 185 WaitOne(int millisecondsTimeout, bool exitContext)186 public override bool WaitOne (int millisecondsTimeout, bool exitContext) 187 { 188 AssertValid (); 189 if (exitContext) 190 throw new InvalidOperationException ("exitContext is not supported"); 191 if (millisecondsTimeout == 0) 192 return IsSet; 193 return WaitAny (new UnixSignal[]{this}, millisecondsTimeout) == 0; 194 } 195 #endregion 196 WaitAny(UnixSignal[] signals)197 public static int WaitAny (UnixSignal[] signals) 198 { 199 return WaitAny (signals, -1); 200 } 201 WaitAny(UnixSignal[] signals, TimeSpan timeout)202 public static int WaitAny (UnixSignal[] signals, TimeSpan timeout) 203 { 204 long ms = (long) timeout.TotalMilliseconds; 205 if (ms < -1 || ms > Int32.MaxValue) 206 throw new ArgumentOutOfRangeException ("timeout"); 207 return WaitAny (signals, (int) ms); 208 } 209 210 WaitAny(UnixSignal[] signals, int millisecondsTimeout)211 public static unsafe int WaitAny (UnixSignal[] signals, int millisecondsTimeout) 212 { 213 if (signals == null) 214 throw new ArgumentNullException ("signals"); 215 if (millisecondsTimeout < -1) 216 throw new ArgumentOutOfRangeException ("millisecondsTimeout"); 217 IntPtr[] infos = new IntPtr [signals.Length]; 218 for (int i = 0; i < signals.Length; ++i) { 219 infos [i] = signals [i].signal_info; 220 if (infos [i] == IntPtr.Zero) 221 throw new InvalidOperationException ("Disposed UnixSignal"); 222 } 223 return WaitAny (infos, infos.Length, millisecondsTimeout, ShuttingDown); 224 } 225 } 226 } 227 228