Document [WinMM] drivers options.
[wine/multimedia.git] / scheduler / fiber.c
blob570aa41f87ce58fe1d4be863130789f22c322c6d
1 /*
2 * Fiber support
4 * Copyright 2002 Alexandre Julliard
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * FIXME:
21 * - proper handling of 16-bit stack and signal stack
24 #include <setjmp.h>
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "thread.h"
30 struct fiber_data
32 LPVOID param; /* 00 fiber param */
33 void *except; /* 04 saved exception handlers list */
34 void *stack_top; /* 08 top of fiber stack */
35 void *stack_low; /* 0c fiber stack low-water mark */
36 void *stack_base; /* 10 base of the fiber stack */
37 jmp_buf jmpbuf; /* 14 setjmp buffer (on Windows: CONTEXT) */
38 DWORD flags; /* fiber flags */
39 LPFIBER_START_ROUTINE start; /* start routine */
43 /* call the fiber initial function once we have switched stack */
44 static void start_fiber(void)
46 struct fiber_data *fiber = NtCurrentTeb()->fiber;
47 LPFIBER_START_ROUTINE start = fiber->start;
49 fiber->start = NULL;
50 start( fiber->param );
51 ExitThread( 1 );
55 /***********************************************************************
56 * CreateFiber (KERNEL32.@)
58 LPVOID WINAPI CreateFiber( SIZE_T stack, LPFIBER_START_ROUTINE start, LPVOID param )
60 return CreateFiberEx( stack, 0, 0, start, param );
64 /***********************************************************************
65 * CreateFiberEx (KERNEL32.@)
67 LPVOID WINAPI CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD flags,
68 LPFIBER_START_ROUTINE start, LPVOID param )
70 struct fiber_data *fiber;
72 if (!(fiber = HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber) )))
74 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
75 return NULL;
78 /* FIXME: should use the thread stack allocation routines here */
79 if (!stack_reserve) stack_reserve = 1024*1024;
80 if(!(fiber->stack_base = VirtualAlloc( 0, stack_reserve, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
82 HeapFree( GetProcessHeap(), 0, fiber );
83 return NULL;
85 fiber->stack_top = (char *)fiber->stack_base + stack_reserve;
86 fiber->stack_low = fiber->stack_base;
87 fiber->param = param;
88 fiber->except = (void *)-1;
89 fiber->start = start;
90 fiber->flags = flags;
91 return fiber;
95 /***********************************************************************
96 * DeleteFiber (KERNEL32.@)
98 void WINAPI DeleteFiber( LPVOID fiber_ptr )
100 struct fiber_data *fiber = fiber_ptr;
102 if (!fiber) return;
103 if (fiber == NtCurrentTeb()->fiber)
105 HeapFree( GetProcessHeap(), 0, fiber );
106 ExitThread(1);
108 VirtualFree( fiber->stack_base, 0, MEM_RELEASE );
109 HeapFree( GetProcessHeap(), 0, fiber );
113 /***********************************************************************
114 * ConvertThreadToFiber (KERNEL32.@)
116 LPVOID WINAPI ConvertThreadToFiber( LPVOID param )
118 return ConvertThreadToFiberEx( param, 0 );
122 /***********************************************************************
123 * ConvertThreadToFiberEx (KERNEL32.@)
125 LPVOID WINAPI ConvertThreadToFiberEx( LPVOID param, DWORD flags )
127 struct fiber_data *fiber;
129 if (!(fiber = HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber) )))
131 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
132 return NULL;
134 fiber->param = param;
135 fiber->except = NtCurrentTeb()->except;
136 fiber->stack_top = NtCurrentTeb()->stack_top;
137 fiber->stack_low = NtCurrentTeb()->stack_low;
138 fiber->stack_base = NtCurrentTeb()->stack_base;
139 fiber->start = NULL;
140 fiber->flags = flags;
141 NtCurrentTeb()->fiber = fiber;
142 return fiber;
146 /***********************************************************************
147 * ConvertFiberToThread (KERNEL32.@)
149 BOOL WINAPI ConvertFiberToThread(void)
151 struct fiber_data *fiber = NtCurrentTeb()->fiber;
153 if (fiber)
155 NtCurrentTeb()->fiber = NULL;
156 HeapFree( GetProcessHeap(), 0, fiber );
158 return TRUE;
162 /***********************************************************************
163 * SwitchToFiber (KERNEL32.@)
165 void WINAPI SwitchToFiber( LPVOID fiber )
167 struct fiber_data *new_fiber = fiber;
168 struct fiber_data *current_fiber = NtCurrentTeb()->fiber;
170 current_fiber->except = NtCurrentTeb()->except;
171 current_fiber->stack_low = NtCurrentTeb()->stack_low;
172 /* stack_base and stack_top never change */
174 /* FIXME: should save floating point context if requested in fiber->flags */
175 if (!setjmp( current_fiber->jmpbuf ))
177 NtCurrentTeb()->fiber = new_fiber;
178 NtCurrentTeb()->except = new_fiber->except;
179 NtCurrentTeb()->stack_top = new_fiber->stack_top;
180 NtCurrentTeb()->stack_low = new_fiber->stack_low;
181 NtCurrentTeb()->stack_base = new_fiber->stack_base;
182 if (new_fiber->start) /* first time */
183 SYSDEPS_SwitchToThreadStack( start_fiber );
184 else
185 longjmp( new_fiber->jmpbuf, 1 );