PageRenderTime 72ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/thread.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 308 lines | 224 code | 60 blank | 24 comment | 25 complexity | 5a68337e7926dde5a9336f9473b56023 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Threading;
  19. using IronPython.Runtime;
  20. using IronPython.Runtime.Exceptions;
  21. using IronPython.Runtime.Operations;
  22. using IronPython.Runtime.Types;
  23. using Microsoft.Scripting;
  24. using Microsoft.Scripting.Runtime;
  25. using Microsoft.Scripting.Utils;
  26. using SpecialName = System.Runtime.CompilerServices.SpecialNameAttribute;
  27. [assembly: PythonModule("thread", typeof(IronPython.Modules.PythonThread))]
  28. namespace IronPython.Modules {
  29. public static class PythonThread {
  30. public const string __doc__ = "Provides low level primitives for threading.";
  31. private static readonly object _stackSizeKey = new object();
  32. [SpecialName]
  33. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  34. context.SetModuleState(_stackSizeKey, 0);
  35. context.EnsureModuleException("threaderror", dict, "error", "thread");
  36. }
  37. #region Public API Surface
  38. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  39. public static readonly PythonType LockType = DynamicHelpers.GetPythonTypeFromType(typeof(@lock));
  40. [Documentation("start_new_thread(function, [args, [kwDict]]) -> thread id\nCreates a new thread running the given function")]
  41. public static object start_new_thread(CodeContext/*!*/ context, object function, object args, object kwDict) {
  42. PythonTuple tupArgs = args as PythonTuple;
  43. if (tupArgs == null) throw PythonOps.TypeError("2nd arg must be a tuple");
  44. Thread t = CreateThread(context, new ThreadObj(context, function, tupArgs, kwDict).Start);
  45. t.Start();
  46. return t.ManagedThreadId;
  47. }
  48. [Documentation("start_new_thread(function, args, [kwDict]) -> thread id\nCreates a new thread running the given function")]
  49. public static object start_new_thread(CodeContext/*!*/ context, object function, object args) {
  50. PythonTuple tupArgs = args as PythonTuple;
  51. if (tupArgs == null) throw PythonOps.TypeError("2nd arg must be a tuple");
  52. Thread t = CreateThread(context, new ThreadObj(context, function, tupArgs, null).Start);
  53. t.IsBackground = true;
  54. t.Start();
  55. return t.ManagedThreadId;
  56. }
  57. public static void interrupt_main() {
  58. throw PythonOps.NotImplementedError("interrupt_main not implemented");
  59. //throw new PythonKeyboardInterrupt();
  60. }
  61. public static void exit() {
  62. PythonOps.SystemExit();
  63. }
  64. [Documentation("allocate_lock() -> lock object\nAllocates a new lock object that can be used for synchronization")]
  65. public static object allocate_lock() {
  66. return new @lock();
  67. }
  68. public static object get_ident() {
  69. return Thread.CurrentThread.ManagedThreadId;
  70. }
  71. public static int stack_size(CodeContext/*!*/ context) {
  72. return GetStackSize(context);
  73. }
  74. public static int stack_size(CodeContext/*!*/ context, int size) {
  75. if (size < 256 * 1024 && size != 0) {
  76. throw PythonOps.ValueError("size too small: {0}", size);
  77. }
  78. int oldSize = GetStackSize(context);
  79. SetStackSize(context, size);
  80. return oldSize;
  81. }
  82. // deprecated synonyms, wrappers over preferred names...
  83. [Documentation("start_new(function, [args, [kwDict]]) -> thread id\nCreates a new thread running the given function")]
  84. public static object start_new(CodeContext context, object function, object args) {
  85. return start_new_thread(context, function, args);
  86. }
  87. public static void exit_thread() {
  88. exit();
  89. }
  90. public static object allocate() {
  91. return allocate_lock();
  92. }
  93. #endregion
  94. [PythonType, PythonHidden]
  95. public class @lock {
  96. private AutoResetEvent blockEvent;
  97. private Thread curHolder;
  98. public object __enter__() {
  99. acquire();
  100. return this;
  101. }
  102. public void __exit__(CodeContext/*!*/ context, params object[] args) {
  103. release(context);
  104. }
  105. public object acquire() {
  106. return (acquire(ScriptingRuntimeHelpers.True));
  107. }
  108. public object acquire(object waitflag) {
  109. bool fWait = PythonOps.IsTrue(waitflag);
  110. for (; ; ) {
  111. if (Interlocked.CompareExchange<Thread>(ref curHolder, Thread.CurrentThread, null) == null) {
  112. return ScriptingRuntimeHelpers.True;
  113. }
  114. if (!fWait) {
  115. return ScriptingRuntimeHelpers.False;
  116. }
  117. if (blockEvent == null) {
  118. // try again in case someone released us, checked the block
  119. // event and discovered it was null so they didn't set it.
  120. CreateBlockEvent();
  121. continue;
  122. }
  123. blockEvent.WaitOne();
  124. }
  125. }
  126. public void release(CodeContext/*!*/ context, params object[] param) {
  127. release(context);
  128. }
  129. public void release(CodeContext/*!*/ context) {
  130. if (Interlocked.Exchange<Thread>(ref curHolder, null) == null) {
  131. throw PythonExceptions.CreateThrowable((PythonType)PythonContext.GetContext(context).GetModuleState("threaderror"), "lock isn't held", null);
  132. }
  133. if (blockEvent != null) {
  134. // if this isn't set yet we race, it's handled in Acquire()
  135. blockEvent.Set();
  136. }
  137. }
  138. public bool locked() {
  139. return curHolder != null;
  140. }
  141. private void CreateBlockEvent() {
  142. AutoResetEvent are = new AutoResetEvent(false);
  143. if (Interlocked.CompareExchange<AutoResetEvent>(ref blockEvent, are, null) != null) {
  144. are.Close();
  145. }
  146. }
  147. }
  148. #region Internal Implementation details
  149. private static Thread CreateThread(CodeContext/*!*/ context, ThreadStart start) {
  150. #if !SILVERLIGHT
  151. int size = GetStackSize(context);
  152. return (size != 0) ? new Thread(start, size) : new Thread(start);
  153. #else
  154. return new Thread(start);
  155. #endif
  156. }
  157. private class ThreadObj {
  158. private readonly object _func, _kwargs;
  159. private readonly PythonTuple _args;
  160. private readonly CodeContext _context;
  161. public ThreadObj(CodeContext context, object function, PythonTuple args, object kwargs) {
  162. Debug.Assert(args != null);
  163. _func = function;
  164. _kwargs = kwargs;
  165. _args = args;
  166. _context = context;
  167. }
  168. public void Start() {
  169. try {
  170. if (_kwargs != null) {
  171. PythonOps.CallWithArgsTupleAndKeywordDictAndContext(_context, _func, ArrayUtils.EmptyObjects, ArrayUtils.EmptyStrings, _args, _kwargs);
  172. } else {
  173. PythonOps.CallWithArgsTuple(_func, ArrayUtils.EmptyObjects, _args);
  174. }
  175. } catch (SystemExitException) {
  176. // ignore and quit
  177. } catch (Exception e) {
  178. PythonOps.PrintWithDest(_context, PythonContext.GetContext(_context).SystemStandardError, "Unhandled exception on thread");
  179. string result = _context.LanguageContext.FormatException(e);
  180. PythonOps.PrintWithDest(_context, PythonContext.GetContext(_context).SystemStandardError, result);
  181. }
  182. }
  183. }
  184. #endregion
  185. private static int GetStackSize(CodeContext/*!*/ context) {
  186. return (int)PythonContext.GetContext(context).GetModuleState(_stackSizeKey);
  187. }
  188. private static void SetStackSize(CodeContext/*!*/ context, int stackSize) {
  189. PythonContext.GetContext(context).SetModuleState(_stackSizeKey, stackSize);
  190. }
  191. [PythonType]
  192. public class _local {
  193. private readonly PythonDictionary/*!*/ _dict = new PythonDictionary(new ThreadLocalDictionaryStorage());
  194. #region Custom Attribute Access
  195. [SpecialName]
  196. public object GetCustomMember(string name) {
  197. return _dict.get(name, OperationFailed.Value);
  198. }
  199. [SpecialName]
  200. public void SetMemberAfter(string name, object value) {
  201. _dict[name] = value;
  202. }
  203. [SpecialName]
  204. public void DeleteMember(string name) {
  205. _dict.__delitem__(name);
  206. }
  207. #endregion
  208. public PythonDictionary/*!*/ __dict__ {
  209. get {
  210. return _dict;
  211. }
  212. }
  213. #region Dictionary Storage
  214. /// <summary>
  215. /// Provides a dictionary storage implementation whose storage is local to
  216. /// the thread.
  217. /// </summary>
  218. private class ThreadLocalDictionaryStorage : DictionaryStorage {
  219. private readonly Microsoft.Scripting.Utils.ThreadLocal<CommonDictionaryStorage> _storage = new Microsoft.Scripting.Utils.ThreadLocal<CommonDictionaryStorage>();
  220. public override void Add(object key, object value) {
  221. GetStorage().Add(key, value);
  222. }
  223. public override bool Contains(object key) {
  224. return GetStorage().Contains(key);
  225. }
  226. public override bool Remove(object key) {
  227. return GetStorage().Remove(key);
  228. }
  229. public override bool TryGetValue(object key, out object value) {
  230. return GetStorage().TryGetValue(key, out value);
  231. }
  232. public override int Count {
  233. get { return GetStorage().Count; }
  234. }
  235. public override void Clear() {
  236. GetStorage().Clear();
  237. }
  238. public override List<KeyValuePair<object, object>>/*!*/ GetItems() {
  239. return GetStorage().GetItems();
  240. }
  241. private CommonDictionaryStorage/*!*/ GetStorage() {
  242. return _storage.GetOrCreate(() => new CommonDictionaryStorage());
  243. }
  244. }
  245. #endregion
  246. }
  247. }
  248. }