1- // cannot include this header because it also has definitions
2- #include "windows.h"
3- #include "compat.h"
4- #include "vmp_stack.h"
1+ # include "vmprof_win.h"
2+
3+ volatile int thread_started = 0 ;
4+ volatile int enabled = 0 ;
55
66HANDLE write_mutex ;
77
@@ -12,7 +12,20 @@ int prepare_concurrent_bufs(void)
1212 return 0 ;
1313}
1414
15- #include <tlhelp32.h>
15+ int vmprof_register_virtual_function (char * code_name , intptr_t code_uid ,
16+ int auto_retry )
17+ {
18+ char buf [2048 ];
19+ long namelen ;
20+
21+ namelen = (long )strnlen (code_name , 1023 );
22+ buf [0 ] = MARKER_VIRTUAL_IP ;
23+ * (intptr_t * )(buf + 1 ) = code_uid ;
24+ * (long * )(buf + 1 + sizeof (intptr_t )) = namelen ;
25+ memcpy (buf + 1 + sizeof (intptr_t ) + sizeof (long ), code_name , namelen );
26+ vmp_write_all (buf , 1 + sizeof (intptr_t ) + sizeof (long ) + namelen );
27+ return 0 ;
28+ }
1629
1730int vmp_write_all (const char * buf , size_t bufsize )
1831{
@@ -40,3 +53,168 @@ int vmp_write_all(const char *buf, size_t bufsize)
4053 return 0 ;
4154}
4255
56+ HANDLE write_mutex ;
57+
58+ #include "vmprof_common.h"
59+
60+ int vmprof_snapshot_thread (DWORD thread_id , PY_WIN_THREAD_STATE * tstate , prof_stacktrace_s * stack )
61+ {
62+ HRESULT result ;
63+ HANDLE hThread ;
64+ int depth ;
65+ CONTEXT ctx ;
66+ #ifdef RPYTHON_LL2CTYPES
67+ return 0 ; // not much we can do
68+ #else
69+ #if !defined(RPY_TLOFS_thread_ident ) && defined(RPYTHON_VMPROF )
70+ return 0 ; // we can't freeze threads, unsafe
71+ #else
72+ hThread = OpenThread (THREAD_ALL_ACCESS , FALSE, thread_id );
73+ if (!hThread ) {
74+ return -1 ;
75+ }
76+ result = SuspendThread (hThread );
77+ if (result == 0xffffffff )
78+ return -1 ; // possible, e.g. attached debugger or thread alread suspended
79+ // find the correct thread
80+ #ifdef RPYTHON_VMPROF
81+ ctx .ContextFlags = CONTEXT_FULL ;
82+ if (!GetThreadContext (hThread , & ctx ))
83+ return -1 ;
84+ depth = get_stack_trace (tstate -> vmprof_tl_stack ,
85+ stack -> stack , MAX_STACK_DEPTH - 2 , ctx .Eip );
86+ stack -> depth = depth ;
87+ stack -> stack [depth ++ ] = thread_id ;
88+ stack -> count = 1 ;
89+ stack -> marker = MARKER_STACKTRACE ;
90+ ResumeThread (hThread );
91+ return depth ;
92+ #else
93+ depth = vmp_walk_and_record_stack (tstate -> frame , stack -> stack ,
94+ MAX_STACK_DEPTH , 0 , 0 );
95+ stack -> depth = depth ;
96+ stack -> stack [depth ++ ] = (void * )((ULONG_PTR )thread_id );
97+ stack -> count = 1 ;
98+ stack -> marker = MARKER_STACKTRACE ;
99+ ResumeThread (hThread );
100+ return depth ;
101+ #endif
102+
103+ #endif
104+ #endif
105+ }
106+
107+ #ifndef RPYTHON_VMPROF
108+ static
109+ PY_WIN_THREAD_STATE * get_current_thread_state (void )
110+ {
111+ #if PY_MAJOR_VERSION < 3
112+ return _PyThreadState_Current ;
113+ #elif PY_VERSION_HEX < 0x03050200
114+ return (PyThreadState * ) _Py_atomic_load_relaxed (& _PyThreadState_Current );
115+ #else
116+ return _PyThreadState_UncheckedGet ();
117+ #endif
118+ }
119+ #endif
120+
121+ long __stdcall vmprof_mainloop (void * arg )
122+ {
123+ #ifdef RPYTHON_LL2CTYPES
124+ // for tests only
125+ return 0 ;
126+ #else
127+ // it is not a test case!
128+ PY_WIN_THREAD_STATE * tstate ;
129+ HANDLE hThreadSnap = INVALID_HANDLE_VALUE ;
130+ prof_stacktrace_s * stack = (prof_stacktrace_s * )malloc (SINGLE_BUF_SIZE );
131+ int depth ;
132+ #ifndef RPYTHON_VMPROF
133+ // cpython version
134+ while (1 ) {
135+ Sleep (vmprof_get_profile_interval_usec () * 1000 );
136+ if (!enabled ) {
137+ continue ;
138+ }
139+ tstate = get_current_thread_state ();
140+ if (!tstate )
141+ continue ;
142+ depth = vmprof_snapshot_thread (tstate -> thread_id , tstate , stack );
143+ if (depth > 0 ) {
144+ vmp_write_all ((char * )stack + offsetof(prof_stacktrace_s , marker ),
145+ SIZEOF_PROF_STACKTRACE + depth * sizeof (void * ));
146+ }
147+ }
148+ #else
149+ // pypy version
150+ while (1 ) {
151+ //Sleep(vmprof_get_profile_interval_usec() * 1000);
152+ Sleep (10 );
153+ if (!enabled ) {
154+ continue ;
155+ }
156+ _RPython_ThreadLocals_Acquire ();
157+ tstate = _RPython_ThreadLocals_Head (); // the first one is one behind head
158+ tstate = _RPython_ThreadLocals_Enum (tstate );
159+ while (tstate ) {
160+ if (tstate -> ready == 42 ) {
161+ depth = vmprof_snapshot_thread (tstate -> thread_ident , tstate , stack );
162+ if (depth > 0 ) {
163+ vmp_write_all ((char * )stack + offsetof(prof_stacktrace_s , marker ),
164+ depth * sizeof (void * ) +
165+ sizeof (struct prof_stacktrace_s ) -
166+ offsetof(struct prof_stacktrace_s , marker ));
167+ }
168+ }
169+ tstate = _RPython_ThreadLocals_Enum (tstate );
170+ }
171+ _RPython_ThreadLocals_Release ();
172+ }
173+ #endif
174+ #endif
175+ }
176+
177+ RPY_EXTERN
178+ int vmprof_enable (int memory , int native , int real_time )
179+ {
180+ if (!thread_started ) {
181+ if (!CreateThread (NULL , 0 , vmprof_mainloop , NULL , 0 , NULL )) {
182+ return -1 ;
183+ }
184+ thread_started = 1 ;
185+ }
186+ enabled = 1 ;
187+ return 0 ;
188+ }
189+
190+ RPY_EXTERN
191+ int vmprof_disable (void )
192+ {
193+ char marker = MARKER_TRAILER ;
194+ (void )vmp_write_time_now (MARKER_TRAILER );
195+
196+ enabled = 0 ;
197+ vmp_set_profile_fileno (-1 );
198+ return 0 ;
199+ }
200+
201+ RPY_EXTERN
202+ void vmprof_ignore_signals (int ignored )
203+ {
204+ enabled = !ignored ;
205+ }
206+
207+ int vmp_native_enable (void )
208+ {
209+ return 0 ;
210+ }
211+
212+ void vmp_native_disable (void )
213+ {
214+ }
215+
216+ int get_stack_trace (PY_WIN_THREAD_STATE * current , void * * result ,
217+ int max_depth , intptr_t pc )
218+ {
219+ return 0 ;
220+ }
0 commit comments