Skip to content

Commit 07b9655

Browse files
committed
Add GetNativeThreadID method in PythonEngine and different PyThreadState_SetAsyncExc calls for OS and Python version
1 parent d075db3 commit 07b9655

File tree

4 files changed

+70
-29
lines changed

4 files changed

+70
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1010
### Added
1111

1212
- Ability to instantiate new .NET arrays using `Array[T](dim1, dim2, ...)` syntax
13-
- Add Interrupt method in PythonEngine
13+
- Add GetNativeThreadID and Interrupt methods in PythonEngine
1414

1515
### Changed
1616
- Drop support for Python 2, 3.4, and 3.5

src/embed_tests/TestInterrupt.cs

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11

22
using System;
3-
using System.Runtime.InteropServices;
43
using System.Threading;
54
using System.Threading.Tasks;
65

@@ -14,15 +13,6 @@ public class TestInterrupt
1413
{
1514
private IntPtr _threadState;
1615

17-
[DllImport("Kernel32", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]
18-
private static extern uint GetCurrentThreadId();
19-
20-
[DllImport("libc", EntryPoint = "pthread_self")]
21-
private static extern IntPtr pthread_selfLinux();
22-
23-
[DllImport("pthread", EntryPoint = "pthread_self", CallingConvention = CallingConvention.Cdecl)]
24-
private static extern ulong pthread_selfOSX();
25-
2616
[OneTimeSetUp]
2717
public void SetUp()
2818
{
@@ -44,21 +34,9 @@ public void InterruptTest()
4434
ulong nativeThreadId = 0;
4535
Task.Factory.StartNew(() =>
4636
{
47-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
48-
{
49-
nativeThreadId = GetCurrentThreadId();
50-
}
51-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
52-
{
53-
nativeThreadId = (ulong)pthread_selfLinux();
54-
}
55-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
56-
{
57-
nativeThreadId = pthread_selfOSX();
58-
}
59-
6037
using (Py.GIL())
6138
{
39+
nativeThreadId = PythonEngine.GetNativeThreadID();
6240
runSimpleStringReturnValue = PythonEngine.RunSimpleString(@"
6341
import time
6442

src/runtime/pythonengine.cs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ namespace Python.Runtime
1212
/// </summary>
1313
public class PythonEngine : IDisposable
1414
{
15+
[DllImport("Kernel32", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]
16+
private static extern uint GetCurrentThreadId();
17+
18+
[DllImport("libc", EntryPoint = "pthread_self")]
19+
private static extern IntPtr pthread_selfLinux();
20+
21+
[DllImport("pthread", EntryPoint = "pthread_self", CallingConvention = CallingConvention.Cdecl)]
22+
private static extern ulong pthread_selfOSX();
23+
1524
public static ShutdownMode ShutdownMode
1625
{
1726
get => Runtime.ShutdownMode;
@@ -567,14 +576,59 @@ public static void Exec(string code, IntPtr? globals = null, IntPtr? locals = nu
567576
}
568577
}
569578

579+
/// <summary>
580+
/// Gets the native thread ID.
581+
/// </summary>
582+
/// <returns>The native thread ID.</returns>
583+
public static ulong GetNativeThreadID()
584+
{
585+
if (Runtime.PyVersion >= new Version(3, 8))
586+
{
587+
dynamic threading = Py.Import("threading");
588+
return threading.get_native_id();
589+
}
590+
591+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
592+
{
593+
return GetCurrentThreadId();
594+
}
595+
596+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
597+
{
598+
return (ulong)pthread_selfLinux();
599+
}
600+
601+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
602+
{
603+
return pthread_selfOSX();
604+
}
605+
606+
return 0;
607+
}
608+
570609
/// <summary>
571610
/// Interrupts the execution of a thread.
572611
/// </summary>
573-
/// <param name="nativeThreadId">The native thread id.</param>
612+
/// <param name="nativeThreadID">The native thread ID.</param>
574613
/// <returns>The number of thread states modified; this is normally one, but will be zero if the thread id isn’t found.</returns>
575-
public static int Interrupt(ulong nativeThreadId)
614+
public static int Interrupt(ulong nativeThreadID)
576615
{
577-
return Runtime.PyThreadState_SetAsyncExc(nativeThreadId, Exceptions.KeyboardInterrupt);
616+
if (Runtime.PyVersion >= new Version(3, 7))
617+
{
618+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
619+
{
620+
return Runtime.PyThreadState_SetAsyncExc37Windows(nativeThreadID, Exceptions.KeyboardInterrupt);
621+
}
622+
623+
return Runtime.PyThreadState_SetAsyncExc37NonWindows((UIntPtr)nativeThreadID, Exceptions.KeyboardInterrupt);
624+
}
625+
626+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
627+
{
628+
return Runtime.PyThreadState_SetAsyncExc36Windows((long)nativeThreadID, Exceptions.KeyboardInterrupt);
629+
}
630+
631+
return Runtime.PyThreadState_SetAsyncExc36NonWindows((IntPtr)nativeThreadID, Exceptions.KeyboardInterrupt);
578632
}
579633

580634
/// <summary>

src/runtime/runtime.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,8 +2143,17 @@ internal static void Py_CLEAR(ref IntPtr ob)
21432143
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
21442144
internal static extern int Py_AddPendingCall(IntPtr func, IntPtr arg);
21452145

2146-
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
2147-
internal static extern int PyThreadState_SetAsyncExc(ulong id, IntPtr exc);
2146+
[DllImport(_PythonDll, EntryPoint = "PyThreadState_SetAsyncExc", CallingConvention = CallingConvention.Cdecl)]
2147+
internal static extern int PyThreadState_SetAsyncExc37Windows(ulong id, IntPtr exc);
2148+
2149+
[DllImport(_PythonDll, EntryPoint = "PyThreadState_SetAsyncExc", CallingConvention = CallingConvention.Cdecl)]
2150+
internal static extern int PyThreadState_SetAsyncExc36Windows(long id, IntPtr exc);
2151+
2152+
[DllImport(_PythonDll, EntryPoint = "PyThreadState_SetAsyncExc", CallingConvention = CallingConvention.Cdecl)]
2153+
internal static extern int PyThreadState_SetAsyncExc37NonWindows(UIntPtr id, IntPtr exc);
2154+
2155+
[DllImport(_PythonDll, EntryPoint = "PyThreadState_SetAsyncExc", CallingConvention = CallingConvention.Cdecl)]
2156+
internal static extern int PyThreadState_SetAsyncExc36NonWindows(IntPtr id, IntPtr exc);
21482157

21492158
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
21502159
internal static extern int Py_MakePendingCalls();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy