msvcrt: Throw throw_scheduler_resource_allocation_error on Context tls index allocati...
[wine.git] / dlls / msvcrt / scheduler.c
blob1ab79064e33730f454a187c3c103aac25586bd36
1 /*
2 * msvcrt.dll C++ objects
4 * Copyright 2017 Piotr Caban
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winternl.h"
27 #include "wine/debug.h"
28 #include "msvcrt.h"
29 #include "cppexcept.h"
30 #include "cxx.h"
32 #if _MSVCR_VER >= 100
34 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36 static int context_id = -1;
38 #ifdef __i386__
40 #define DEFINE_VTBL_WRAPPER(off) \
41 __ASM_GLOBAL_FUNC(vtbl_wrapper_ ## off, \
42 "popl %eax\n\t" \
43 "popl %ecx\n\t" \
44 "pushl %eax\n\t" \
45 "movl 0(%ecx), %eax\n\t" \
46 "jmp *" #off "(%eax)\n\t")
48 DEFINE_VTBL_WRAPPER(0);
49 DEFINE_VTBL_WRAPPER(4);
50 DEFINE_VTBL_WRAPPER(8);
51 DEFINE_VTBL_WRAPPER(20);
53 #endif
55 typedef struct {
56 const vtable_ptr *vtable;
57 } Context;
58 #define call_Context_GetId(this) CALL_VTBL_FUNC(this, 0, \
59 unsigned int, (const Context*), (this))
60 #define call_Context_GetVirtualProcessorId(this) CALL_VTBL_FUNC(this, 4, \
61 unsigned int, (const Context*), (this))
62 #define call_Context_GetScheduleGroupId(this) CALL_VTBL_FUNC(this, 8, \
63 unsigned int, (const Context*), (this))
64 #define call_Context_dtor(this, flags) CALL_VTBL_FUNC(this, 20, \
65 Context*, (Context*, unsigned int), (this, flags))
67 typedef struct {
68 Context context;
69 unsigned int id;
70 } ExternalContextBase;
71 extern const vtable_ptr MSVCRT_ExternalContextBase_vtable;
72 static void ExternalContextBase_ctor(ExternalContextBase*);
74 static int context_tls_index = TLS_OUT_OF_INDEXES;
76 static Context* try_get_current_context(void)
78 if (context_tls_index == TLS_OUT_OF_INDEXES)
79 return NULL;
80 return TlsGetValue(context_tls_index);
83 static Context* get_current_context(void)
85 Context *ret;
87 if (context_tls_index == TLS_OUT_OF_INDEXES) {
88 int tls_index = TlsAlloc();
89 if (tls_index == TLS_OUT_OF_INDEXES) {
90 throw_scheduler_resource_allocation_error(NULL,
91 HRESULT_FROM_WIN32(GetLastError()));
92 return NULL;
95 if(InterlockedCompareExchange(&context_tls_index, tls_index, TLS_OUT_OF_INDEXES) != TLS_OUT_OF_INDEXES)
96 TlsFree(tls_index);
99 ret = TlsGetValue(context_tls_index);
100 if (!ret) {
101 ExternalContextBase *context = MSVCRT_operator_new(sizeof(ExternalContextBase));
102 ExternalContextBase_ctor(context);
103 TlsSetValue(context_tls_index, context);
104 ret = &context->context;
106 return ret;
109 /* ?CurrentContext@Context@Concurrency@@SAPAV12@XZ */
110 /* ?CurrentContext@Context@Concurrency@@SAPEAV12@XZ */
111 Context* __cdecl Context_CurrentContext(void)
113 TRACE("()\n");
114 return get_current_context();
117 /* ?Id@Context@Concurrency@@SAIXZ */
118 unsigned int __cdecl Context_Id(void)
120 Context *ctx = try_get_current_context();
121 TRACE("()\n");
122 return ctx ? call_Context_GetId(ctx) : -1;
125 /* ?Block@Context@Concurrency@@SAXXZ */
126 void __cdecl Context_Block(void)
128 FIXME("()\n");
131 /* ?Yield@Context@Concurrency@@SAXXZ */
132 void __cdecl Context_Yield(void)
134 FIXME("()\n");
137 /* ?_SpinYield@Context@Concurrency@@SAXXZ */
138 void __cdecl Context__SpinYield(void)
140 FIXME("()\n");
143 /* ?IsCurrentTaskCollectionCanceling@Context@Concurrency@@SA_NXZ */
144 MSVCRT_bool __cdecl Context_IsCurrentTaskCollectionCanceling(void)
146 FIXME("()\n");
147 return FALSE;
150 /* ?Oversubscribe@Context@Concurrency@@SAX_N@Z */
151 void __cdecl Context_Oversubscribe(MSVCRT_bool begin)
153 FIXME("(%x)\n", begin);
156 /* ?ScheduleGroupId@Context@Concurrency@@SAIXZ */
157 unsigned int __cdecl Context_ScheduleGroupId(void)
159 Context *ctx = try_get_current_context();
160 TRACE("()\n");
161 return ctx ? call_Context_GetScheduleGroupId(ctx) : -1;
164 /* ?VirtualProcessorId@Context@Concurrency@@SAIXZ */
165 unsigned int __cdecl Context_VirtualProcessorId(void)
167 Context *ctx = try_get_current_context();
168 FIXME("()\n");
169 return ctx ? call_Context_GetVirtualProcessorId(ctx) : -1;
172 DEFINE_THISCALL_WRAPPER(ExternalContextBase_GetId, 4)
173 unsigned int __thiscall ExternalContextBase_GetId(const ExternalContextBase *this)
175 TRACE("(%p)->()\n", this);
176 return this->id;
179 DEFINE_THISCALL_WRAPPER(ExternalContextBase_GetVirtualProcessorId, 4)
180 unsigned int __thiscall ExternalContextBase_GetVirtualProcessorId(const ExternalContextBase *this)
182 FIXME("(%p)->() stub\n", this);
183 return -1;
186 DEFINE_THISCALL_WRAPPER(ExternalContextBase_GetScheduleGroupId, 4)
187 unsigned int __thiscall ExternalContextBase_GetScheduleGroupId(const ExternalContextBase *this)
189 FIXME("(%p)->() stub\n", this);
190 return -1;
193 DEFINE_THISCALL_WRAPPER(ExternalContextBase_Unblock, 4)
194 void __thiscall ExternalContextBase_Unblock(ExternalContextBase *this)
196 FIXME("(%p)->() stub\n", this);
199 DEFINE_THISCALL_WRAPPER(ExternalContextBase_IsSynchronouslyBlocked, 4)
200 MSVCRT_bool __thiscall ExternalContextBase_IsSynchronouslyBlocked(const ExternalContextBase *this)
202 FIXME("(%p)->() stub\n", this);
203 return FALSE;
206 static void ExternalContextBase_dtor(ExternalContextBase *this)
210 DEFINE_THISCALL_WRAPPER(ExternalContextBase_vector_dtor, 8)
211 Context* __thiscall ExternalContextBase_vector_dtor(ExternalContextBase *this, unsigned int flags)
213 TRACE("(%p %x)\n", this, flags);
214 if(flags & 2) {
215 /* we have an array, with the number of elements stored before the first object */
216 INT_PTR i, *ptr = (INT_PTR *)this-1;
218 for(i=*ptr-1; i>=0; i--)
219 ExternalContextBase_dtor(this+i);
220 MSVCRT_operator_delete(ptr);
221 } else {
222 ExternalContextBase_dtor(this);
223 if(flags & 1)
224 MSVCRT_operator_delete(this);
227 return &this->context;
230 static void ExternalContextBase_ctor(ExternalContextBase *this)
232 TRACE("(%p)->()\n", this);
233 this->context.vtable = &MSVCRT_ExternalContextBase_vtable;
234 this->id = InterlockedIncrement(&context_id);
237 extern const vtable_ptr MSVCRT_type_info_vtable;
238 DEFINE_RTTI_DATA0(Context, 0, ".?AVContext@Concurrency@@")
239 DEFINE_RTTI_DATA1(ContextBase, 0, &Context_rtti_base_descriptor, ".?AVContextBase@details@Concurrency@@")
240 DEFINE_RTTI_DATA2(ExternalContextBase, 0, &ContextBase_rtti_base_descriptor,
241 &Context_rtti_base_descriptor, ".?AVExternalContextBase@details@Concurrency@@")
243 #ifndef __GNUC__
244 void __asm_dummy_vtables(void) {
245 #endif
246 __ASM_VTABLE(ExternalContextBase,
247 VTABLE_ADD_FUNC(ExternalContextBase_GetId)
248 VTABLE_ADD_FUNC(ExternalContextBase_GetVirtualProcessorId)
249 VTABLE_ADD_FUNC(ExternalContextBase_GetScheduleGroupId)
250 VTABLE_ADD_FUNC(ExternalContextBase_Unblock)
251 VTABLE_ADD_FUNC(ExternalContextBase_IsSynchronouslyBlocked)
252 VTABLE_ADD_FUNC(ExternalContextBase_vector_dtor));
253 #ifndef __GNUC__
255 #endif
257 void msvcrt_init_scheduler(void *base)
259 #ifdef __x86_64__
260 init_Context_rtti(base);
261 init_ContextBase_rtti(base);
262 init_ExternalContextBase_rtti(base);
263 #endif
266 void msvcrt_free_scheduler(void)
268 if (context_tls_index != TLS_OUT_OF_INDEXES)
269 TlsFree(context_tls_index);
272 void msvcrt_free_scheduler_thread(void)
274 Context *context = try_get_current_context();
275 if (!context) return;
276 call_Context_dtor(context, 1);
279 #endif /* _MSVCR_VER >= 100 */