[bcl] Remove NET_4_0 defines from class libs.
[mono.git] / mcs / class / corlib / System.Threading.Tasks / TaskScheduler.cs
1 // 
2 // TaskScheduler.cs
3 //  
4 // Authors:
5 //       Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 //       Marek Safar <marek.safar@gmail.com>
7 // 
8 // Copyright (c) 2009 Jérémie "Garuma" Laval
9 // Copyright 2012 Xamarin, Inc (http://www.xamarin.com)
10 // 
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28
29
30 using System.Collections.Generic;
31 using System.Diagnostics;
32
33 namespace System.Threading.Tasks
34 {
35         [DebuggerDisplay ("Id={Id}")]
36         [DebuggerTypeProxy (typeof (TaskSchedulerDebuggerView))]
37         public abstract class TaskScheduler
38         {
39                 sealed class TaskSchedulerDebuggerView
40                 {
41                         readonly TaskScheduler scheduler;
42
43                         public TaskSchedulerDebuggerView (TaskScheduler scheduler)
44                         {
45                                 this.scheduler = scheduler;
46                         }
47
48                         public IEnumerable<Task> ScheduledTasks {
49                                 get {
50                                         return scheduler.GetScheduledTasks ();
51                                 }
52                         }
53                 }
54
55                 static readonly TaskScheduler defaultScheduler = new TpScheduler ();
56                 
57                 [ThreadStatic]
58                 static TaskScheduler currentScheduler;
59                 
60                 int id;
61                 static int lastId = int.MinValue;
62                 
63                 public static event EventHandler<UnobservedTaskExceptionEventArgs> UnobservedTaskException;
64                 
65                 protected TaskScheduler ()
66                 {
67                         this.id = Interlocked.Increment (ref lastId);
68                 }
69                 
70                 public static TaskScheduler FromCurrentSynchronizationContext ()
71                 {
72                         var syncCtx = SynchronizationContext.Current;
73                         if (syncCtx == null)
74                                 throw new InvalidOperationException ("The current SynchronizationContext is null and cannot be used as a TaskScheduler");
75
76                         return new SynchronizationContextScheduler (syncCtx);
77                 }
78                 
79                 public static TaskScheduler Default  {
80                         get {
81                                 return defaultScheduler;
82                         }
83                 }
84                 
85                 public static TaskScheduler Current  {
86                         get {
87                                 if (currentScheduler != null)
88                                         return currentScheduler;
89                                 
90                                 return defaultScheduler;
91                         }
92                         internal set {
93                                 currentScheduler = value;
94                         }
95                 }
96                 
97                 public int Id {
98                         get {
99                                 return id;
100                         }
101                 }
102
103                 internal static bool IsDefault {
104                         get {
105                                 return currentScheduler == null || currentScheduler == defaultScheduler;
106                         }
107                 }
108                 
109                 public virtual int MaximumConcurrencyLevel {
110                         get {
111                                 return int.MaxValue;
112                         }
113                 }
114
115                 protected abstract IEnumerable<Task> GetScheduledTasks ();
116                 protected internal abstract void QueueTask (Task task);
117
118                 protected internal virtual bool TryDequeue (Task task)
119                 {
120                         return false;
121                 }
122
123                 internal protected bool TryExecuteTask (Task task)
124                 {
125                         if (task.IsCompleted)
126                                 return false;
127
128                         if (task.Status == TaskStatus.WaitingToRun) {
129                                 task.Execute ();
130                                 if (task.WaitOnChildren ())
131                                         task.Wait ();
132
133                                 return true;
134                         }
135
136                         return false;
137                 }
138
139                 protected abstract bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued);
140
141                 internal bool RunInline (Task task, bool taskWasPreviouslyQueued)
142                 {
143                         if (!TryExecuteTaskInline (task, taskWasPreviouslyQueued))
144                                 return false;
145
146                         if (!task.IsCompleted)
147                                 throw new InvalidOperationException ("The TryExecuteTaskInline call to the underlying scheduler succeeded, but the task body was not invoked");
148
149                         return true;
150                 }
151
152                 internal static UnobservedTaskExceptionEventArgs FireUnobservedEvent (Task task, AggregateException e)
153                 {
154                         UnobservedTaskExceptionEventArgs args = new UnobservedTaskExceptionEventArgs (e);
155                         
156                         EventHandler<UnobservedTaskExceptionEventArgs> temp = UnobservedTaskException;
157                         if (temp == null)
158                                 return args;
159                         
160                         temp (task, args);
161                         
162                         return args;
163                 }
164         }
165 }