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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * - proper handling of 16-bit stack and signal stack
25 #include "wine/port.h"
30 #define NONAMELESSUNION
35 #include "wine/exception.h"
36 #include "wine/library.h"
40 LPVOID param
; /* 00 fiber param */
41 void *except
; /* 04 saved exception handlers list */
42 void *stack_base
; /* 08 top of fiber stack */
43 void *stack_limit
; /* 0c fiber stack low-water mark */
44 void *stack_allocation
; /* 10 base of the fiber stack allocation */
45 sigjmp_buf jmpbuf
; /* 14 setjmp buffer (on Windows: CONTEXT) */
46 DWORD flags
; /* fiber flags */
47 LPFIBER_START_ROUTINE start
; /* start routine */
51 /* call the fiber initial function once we have switched stack */
52 static void start_fiber( void *arg
)
54 struct fiber_data
*fiber
= arg
;
55 LPFIBER_START_ROUTINE start
= fiber
->start
;
60 start( fiber
->param
);
63 __EXCEPT(UnhandledExceptionFilter
)
65 TerminateThread( GetCurrentThread(), GetExceptionCode() );
71 /***********************************************************************
72 * CreateFiber (KERNEL32.@)
74 LPVOID WINAPI
CreateFiber( SIZE_T stack
, LPFIBER_START_ROUTINE start
, LPVOID param
)
76 return CreateFiberEx( stack
, 0, 0, start
, param
);
80 /***********************************************************************
81 * CreateFiberEx (KERNEL32.@)
83 LPVOID WINAPI
CreateFiberEx( SIZE_T stack_commit
, SIZE_T stack_reserve
, DWORD flags
,
84 LPFIBER_START_ROUTINE start
, LPVOID param
)
86 struct fiber_data
*fiber
;
88 if (!(fiber
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber
) )))
90 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
94 /* FIXME: should use the thread stack allocation routines here */
95 if (!stack_reserve
) stack_reserve
= 1024*1024;
96 if(!(fiber
->stack_allocation
= VirtualAlloc( 0, stack_reserve
, MEM_COMMIT
, PAGE_READWRITE
)))
98 HeapFree( GetProcessHeap(), 0, fiber
);
101 fiber
->stack_base
= (char *)fiber
->stack_allocation
+ stack_reserve
;
102 fiber
->stack_limit
= fiber
->stack_allocation
;
103 fiber
->param
= param
;
104 fiber
->except
= (void *)-1;
105 fiber
->start
= start
;
106 fiber
->flags
= flags
;
111 /***********************************************************************
112 * DeleteFiber (KERNEL32.@)
114 void WINAPI
DeleteFiber( LPVOID fiber_ptr
)
116 struct fiber_data
*fiber
= fiber_ptr
;
119 if (fiber
== NtCurrentTeb()->Tib
.u
.FiberData
)
121 HeapFree( GetProcessHeap(), 0, fiber
);
124 VirtualFree( fiber
->stack_allocation
, 0, MEM_RELEASE
);
125 HeapFree( GetProcessHeap(), 0, fiber
);
129 /***********************************************************************
130 * ConvertThreadToFiber (KERNEL32.@)
132 LPVOID WINAPI
ConvertThreadToFiber( LPVOID param
)
134 return ConvertThreadToFiberEx( param
, 0 );
138 /***********************************************************************
139 * ConvertThreadToFiberEx (KERNEL32.@)
141 LPVOID WINAPI
ConvertThreadToFiberEx( LPVOID param
, DWORD flags
)
143 struct fiber_data
*fiber
;
145 if (!(fiber
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber
) )))
147 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
150 fiber
->param
= param
;
151 fiber
->except
= NtCurrentTeb()->Tib
.ExceptionList
;
152 fiber
->stack_base
= NtCurrentTeb()->Tib
.StackBase
;
153 fiber
->stack_limit
= NtCurrentTeb()->Tib
.StackLimit
;
154 fiber
->stack_allocation
= NtCurrentTeb()->DeallocationStack
;
156 fiber
->flags
= flags
;
157 NtCurrentTeb()->Tib
.u
.FiberData
= fiber
;
162 /***********************************************************************
163 * ConvertFiberToThread (KERNEL32.@)
165 BOOL WINAPI
ConvertFiberToThread(void)
167 struct fiber_data
*fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
171 NtCurrentTeb()->Tib
.u
.FiberData
= NULL
;
172 HeapFree( GetProcessHeap(), 0, fiber
);
178 /***********************************************************************
179 * SwitchToFiber (KERNEL32.@)
181 void WINAPI
SwitchToFiber( LPVOID fiber
)
183 struct fiber_data
*new_fiber
= fiber
;
184 struct fiber_data
*current_fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
186 current_fiber
->except
= NtCurrentTeb()->Tib
.ExceptionList
;
187 current_fiber
->stack_limit
= NtCurrentTeb()->Tib
.StackLimit
;
188 /* stack_allocation and stack_base never change */
190 /* FIXME: should save floating point context if requested in fiber->flags */
191 if (!sigsetjmp( current_fiber
->jmpbuf
, 1 ))
193 NtCurrentTeb()->Tib
.u
.FiberData
= new_fiber
;
194 NtCurrentTeb()->Tib
.ExceptionList
= new_fiber
->except
;
195 NtCurrentTeb()->Tib
.StackBase
= new_fiber
->stack_base
;
196 NtCurrentTeb()->Tib
.StackLimit
= new_fiber
->stack_limit
;
197 NtCurrentTeb()->DeallocationStack
= new_fiber
->stack_allocation
;
198 if (new_fiber
->start
) /* first time */
199 wine_switch_to_stack( start_fiber
, new_fiber
, new_fiber
->stack_base
);
201 siglongjmp( new_fiber
->jmpbuf
, 1 );