4 * Copyright 1995 Alexandre Julliard
12 #include "wine/winbase16.h"
27 #include "selectors.h"
28 #include "stackframe.h"
41 /* Min. number of thunks allocated when creating a new segment */
44 /* Pointer to function to switch to a larger stack */
45 int (*IF1632_CallLargeStack
)( int (*func
)(), void *arg
) = NULL
;
47 /* Pointer to debugger callback routine */
48 void (*TASK_AddTaskEntryBreakpoint
)( HTASK16 hTask
) = NULL
;
50 static THHOOK DefaultThhook
= { 0 };
51 THHOOK
*pThhook
= &DefaultThhook
;
53 #define hCurrentTask (pThhook->CurTDB)
54 #define hFirstTask (pThhook->HeadTDB)
55 #define hLockedTask (pThhook->LockTDB)
57 static HTASK16 hTaskToKill
= 0;
58 static UINT16 nTaskCount
= 0;
60 static void TASK_YieldToSystem( void );
62 extern BOOL THREAD_InitDone
;
65 /***********************************************************************
68 void TASK_InstallTHHook( THHOOK
*pNewThhook
)
70 THHOOK
*pOldThhook
= pThhook
;
72 pThhook
= pNewThhook
? pNewThhook
: &DefaultThhook
;
74 *pThhook
= *pOldThhook
;
77 /***********************************************************************
80 HTASK16
TASK_GetNextTask( HTASK16 hTask
)
82 TDB
* pTask
= (TDB
*)GlobalLock16(hTask
);
84 if (pTask
->hNext
) return pTask
->hNext
;
85 return (hFirstTask
!= hTask
) ? hFirstTask
: 0;
88 /***********************************************************************
91 static void TASK_LinkTask( HTASK16 hTask
)
96 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return;
97 prevTask
= &hFirstTask
;
100 TDB
*prevTaskPtr
= (TDB
*)GlobalLock16( *prevTask
);
101 if (prevTaskPtr
->priority
>= pTask
->priority
) break;
102 prevTask
= &prevTaskPtr
->hNext
;
104 pTask
->hNext
= *prevTask
;
110 /***********************************************************************
113 static void TASK_UnlinkTask( HTASK16 hTask
)
118 prevTask
= &hFirstTask
;
119 while (*prevTask
&& (*prevTask
!= hTask
))
121 pTask
= (TDB
*)GlobalLock16( *prevTask
);
122 prevTask
= &pTask
->hNext
;
126 pTask
= (TDB
*)GlobalLock16( *prevTask
);
127 *prevTask
= pTask
->hNext
;
134 /***********************************************************************
137 * Create a thunk free-list in segment 'handle', starting from offset 'offset'
138 * and containing 'count' entries.
140 static void TASK_CreateThunks( HGLOBAL16 handle
, WORD offset
, WORD count
)
146 pThunk
= (THUNKS
*)((BYTE
*)GlobalLock16( handle
) + offset
);
148 pThunk
->magic
= THUNK_MAGIC
;
149 pThunk
->free
= (int)&pThunk
->thunks
- (int)pThunk
;
151 for (i
= 0; i
< count
-1; i
++)
153 free
+= 8; /* Offset of next thunk */
154 pThunk
->thunks
[4*i
] = free
;
156 pThunk
->thunks
[4*i
] = 0; /* Last thunk */
160 /***********************************************************************
163 * Allocate a thunk for MakeProcInstance().
165 static SEGPTR
TASK_AllocThunk( HTASK16 hTask
)
171 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return 0;
172 sel
= pTask
->hCSAlias
;
173 pThunk
= &pTask
->thunks
;
174 base
= (int)pThunk
- (int)pTask
;
175 while (!pThunk
->free
)
178 if (!sel
) /* Allocate a new segment */
180 sel
= GLOBAL_Alloc( GMEM_FIXED
, sizeof(THUNKS
) + (MIN_THUNKS
-1)*8,
181 pTask
->hPDB
, TRUE
, FALSE
, FALSE
);
182 if (!sel
) return (SEGPTR
)0;
183 TASK_CreateThunks( sel
, 0, MIN_THUNKS
);
186 pThunk
= (THUNKS
*)GlobalLock16( sel
);
189 base
+= pThunk
->free
;
190 pThunk
->free
= *(WORD
*)((BYTE
*)pThunk
+ pThunk
->free
);
191 return PTR_SEG_OFF_TO_SEGPTR( sel
, base
);
195 /***********************************************************************
198 * Free a MakeProcInstance() thunk.
200 static BOOL
TASK_FreeThunk( HTASK16 hTask
, SEGPTR thunk
)
206 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return 0;
207 sel
= pTask
->hCSAlias
;
208 pThunk
= &pTask
->thunks
;
209 base
= (int)pThunk
- (int)pTask
;
210 while (sel
&& (sel
!= HIWORD(thunk
)))
213 pThunk
= (THUNKS
*)GlobalLock16( sel
);
216 if (!sel
) return FALSE
;
217 *(WORD
*)((BYTE
*)pThunk
+ LOWORD(thunk
) - base
) = pThunk
->free
;
218 pThunk
->free
= LOWORD(thunk
) - base
;
223 /***********************************************************************
226 * 32-bit entry point for a new task. This function is responsible for
227 * setting up the registers and jumping to the 16-bit entry point.
229 static void TASK_CallToStart(void)
231 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
232 NE_MODULE
*pModule
= NE_GetPtr( pTask
->hModule
);
233 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
235 SET_CUR_THREAD( pTask
->thdb
);
238 /* Terminate the stack frame chain */
239 memset(THREAD_STACK16( pTask
->thdb
), '\0', sizeof(STACK16FRAME
));
241 /* Call USER signal proc */
242 PROCESS_CallUserSignalProc( USIG_THREAD_INIT
, 0 ); /* for initial thread */
243 PROCESS_CallUserSignalProc( USIG_PROCESS_INIT
, 0 );
244 PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED
, 0 );
245 PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING
, 0 );
247 if (pModule
->flags
& NE_FFLAGS_WIN32
)
249 ERR( task
, "Called for Win32 task!\n" );
252 else if (pModule
->dos_image
)
259 /* Registers at initialization must be:
261 * bx stack size in bytes
262 * cx heap size in bytes
263 * si previous app instance
264 * di current app instance
266 * es selector to the PSP
267 * ds dgroup of the application
269 * sp top of the stack
273 memset( &context
, 0, sizeof(context
) );
274 CS_reg(&context
) = GlobalHandleToSel16(pSegTable
[pModule
->cs
- 1].hSeg
);
275 DS_reg(&context
) = GlobalHandleToSel16(pSegTable
[pModule
->dgroup
- 1].hSeg
);
276 ES_reg(&context
) = pTask
->hPDB
;
277 EIP_reg(&context
) = pModule
->ip
;
278 EBX_reg(&context
) = pModule
->stack_size
;
279 ECX_reg(&context
) = pModule
->heap_size
;
280 EDI_reg(&context
) = context
.SegDs
;
282 TRACE(task
, "Starting main program: cs:ip=%04lx:%04x ds=%04lx ss:sp=%04x:%04x\n",
283 CS_reg(&context
), IP_reg(&context
), DS_reg(&context
),
284 SELECTOROF(pTask
->thdb
->cur_stack
),
285 OFFSETOF(pTask
->thdb
->cur_stack
) );
287 Callbacks
->CallRegisterShortProc( &context
, 0 );
288 /* This should never return */
289 ERR( task
, "Main program returned! (should never happen)\n" );
295 /***********************************************************************
298 * NOTE: This routine might be called by a Win32 thread. We don't have
299 * any real problems with that, since we operated merely on a private
300 * TDB structure that is not yet linked into the task list.
302 BOOL
TASK_Create( THDB
*thdb
, NE_MODULE
*pModule
, HINSTANCE16 hInstance
,
303 HINSTANCE16 hPrevInstance
, UINT16 cmdShow
)
311 STACK16FRAME
*frame16
;
312 STACK32FRAME
*frame32
;
313 PDB
*pdb32
= thdb
->process
;
314 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
316 /* Allocate the task structure */
318 hTask
= GLOBAL_Alloc( GMEM_FIXED
| GMEM_ZEROINIT
, sizeof(TDB
),
319 pModule
->self
, FALSE
, FALSE
, FALSE
);
320 if (!hTask
) return FALSE
;
321 pTask
= (TDB
*)GlobalLock16( hTask
);
323 /* Fill the task structure */
326 pTask
->hSelf
= hTask
;
329 if (pModule
->flags
& NE_FFLAGS_WIN32
)
330 pTask
->flags
|= TDBF_WIN32
;
331 if (pModule
->lpDosTask
)
332 pTask
->flags
|= TDBF_WINOLDAP
;
334 pTask
->version
= pModule
->expected_version
;
335 pTask
->hInstance
= hInstance
? hInstance
: pModule
->self
;
336 pTask
->hPrevInstance
= hPrevInstance
;
337 pTask
->hModule
= pModule
->self
;
338 pTask
->hParent
= GetCurrentTask();
339 pTask
->magic
= TDB_MAGIC
;
340 pTask
->nCmdShow
= cmdShow
;
342 pTask
->curdrive
= DRIVE_GetCurrentDrive() | 0x80;
343 strcpy( pTask
->curdir
, "\\" );
344 lstrcpynA( pTask
->curdir
+ 1, DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() ),
345 sizeof(pTask
->curdir
) - 1 );
347 /* Create the thunks block */
349 TASK_CreateThunks( hTask
, (int)&pTask
->thunks
- (int)pTask
, 7 );
351 /* Copy the module name */
353 GetModuleName16( pModule
->self
, name
, sizeof(name
) );
354 strncpy( pTask
->module_name
, name
, sizeof(pTask
->module_name
) );
356 /* Allocate a selector for the PDB */
358 pTask
->hPDB
= GLOBAL_CreateBlock( GMEM_FIXED
, &pTask
->pdb
, sizeof(PDB16
),
359 pModule
->self
, FALSE
, FALSE
, FALSE
, NULL
);
363 pTask
->pdb
.int20
= 0x20cd;
364 pTask
->pdb
.dispatcher
[0] = 0x9a; /* ljmp */
365 PUT_DWORD(&pTask
->pdb
.dispatcher
[1], (DWORD
)NE_GetEntryPoint(
366 GetModuleHandle16("KERNEL"), 102 )); /* KERNEL.102 is DOS3Call() */
367 pTask
->pdb
.savedint22
= INT_GetPMHandler( 0x22 );
368 pTask
->pdb
.savedint23
= INT_GetPMHandler( 0x23 );
369 pTask
->pdb
.savedint24
= INT_GetPMHandler( 0x24 );
370 pTask
->pdb
.fileHandlesPtr
=
371 PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel16(pTask
->hPDB
),
372 (int)&((PDB16
*)0)->fileHandles
);
373 pTask
->pdb
.hFileHandles
= 0;
374 memset( pTask
->pdb
.fileHandles
, 0xff, sizeof(pTask
->pdb
.fileHandles
) );
375 pTask
->pdb
.environment
= pdb32
->env_db
->env_sel
;
376 pTask
->pdb
.nbFiles
= 20;
378 /* Fill the command line */
380 cmd_line
= pdb32
->env_db
->cmd_line
;
381 while (*cmd_line
&& (*cmd_line
!= ' ') && (*cmd_line
!= '\t')) cmd_line
++;
382 while ((*cmd_line
== ' ') || (*cmd_line
== '\t')) cmd_line
++;
383 lstrcpynA( pTask
->pdb
.cmdLine
+1, cmd_line
, sizeof(pTask
->pdb
.cmdLine
)-1);
384 pTask
->pdb
.cmdLine
[0] = strlen( pTask
->pdb
.cmdLine
+ 1 );
386 /* Get the compatibility flags */
388 pTask
->compat_flags
= GetProfileIntA( "Compatibility", name
, 0 );
390 /* Allocate a code segment alias for the TDB */
392 pTask
->hCSAlias
= GLOBAL_CreateBlock( GMEM_FIXED
, (void *)pTask
,
393 sizeof(TDB
), pTask
->hPDB
, TRUE
,
394 FALSE
, FALSE
, NULL
);
396 /* Set the owner of the environment block */
398 FarSetOwner16( pTask
->pdb
.environment
, pTask
->hPDB
);
400 /* Default DTA overwrites command-line */
402 pTask
->dta
= PTR_SEG_OFF_TO_SEGPTR( pTask
->hPDB
,
403 (int)&pTask
->pdb
.cmdLine
- (int)&pTask
->pdb
);
405 /* If we have a DGROUP/hInstance, use it for 16-bit stack */
409 if (!(sp
= pModule
->sp
))
410 sp
= pSegTable
[pModule
->ss
-1].minsize
+ pModule
->stack_size
;
411 sp
&= ~1; sp
-= sizeof(STACK16FRAME
);
412 pTask
->thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR( hInstance
, sp
);
415 /* Create the 16-bit stack frame */
417 pTask
->thdb
->cur_stack
-= sizeof(STACK16FRAME
);
418 frame16
= (STACK16FRAME
*)PTR_SEG_TO_LIN( pTask
->thdb
->cur_stack
);
419 frame16
->ebp
= OFFSETOF( pTask
->thdb
->cur_stack
) + (int)&((STACK16FRAME
*)0)->bp
;
420 frame16
->bp
= LOWORD(frame16
->ebp
);
421 frame16
->ds
= frame16
->es
= hInstance
;
423 frame16
->entry_point
= 0;
424 frame16
->entry_cs
= 0;
425 frame16
->mutex_count
= 1; /* TASK_Reschedule is called from 16-bit code */
426 /* The remaining fields will be initialized in TASK_Reschedule */
428 /* Create the 32-bit stack frame */
430 stack32Top
= (char*)pTask
->thdb
->teb
.stack_top
;
431 frame16
->frame32
= frame32
= (STACK32FRAME
*)stack32Top
- 1;
432 frame32
->frame16
= pTask
->thdb
->cur_stack
+ sizeof(STACK16FRAME
);
438 frame32
->retaddr
= (DWORD
)TASK_CallToStart
;
439 /* The remaining fields will be initialized in TASK_Reschedule */
441 /* Enter task handle into thread and process */
443 pTask
->thdb
->teb
.htask16
= pTask
->thdb
->process
->task
= hTask
;
445 TRACE(task
, "module='%s' cmdline='%s' task=%04x\n",
446 name
, cmd_line
, hTask
);
451 /***********************************************************************
454 * NOTE: This routine might be called by a Win32 thread. Thus, we need
455 * to be careful to protect global data structures. We do this
456 * by entering the Win16Lock while linking the task into the
459 void TASK_StartTask( HTASK16 hTask
)
461 TDB
*pTask
= (TDB
*)GlobalLock16( hTask
);
462 if ( !pTask
) return;
464 /* Add the task to the linked list */
466 SYSLEVEL_EnterWin16Lock();
467 TASK_LinkTask( hTask
);
468 SYSLEVEL_LeaveWin16Lock();
470 TRACE(task
, "linked task %04x\n", hTask
);
472 /* If requested, add entry point breakpoint */
474 if ( TASK_AddTaskEntryBreakpoint
)
475 TASK_AddTaskEntryBreakpoint( hTask
);
477 /* Get the task up and running. */
479 if ( THREAD_IsWin16( pTask
->thdb
) )
483 /* If we ourselves are a 16-bit task, we simply Yield().
484 If we are 32-bit however, we need to signal the scheduler. */
486 if ( THREAD_IsWin16( THREAD_Current() ) )
493 /* To start a 32-bit task, we spawn its initial thread. */
495 SYSDEPS_SpawnThread( pTask
->thdb
);
500 /***********************************************************************
503 static void TASK_DeleteTask( HTASK16 hTask
)
508 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return;
511 pTask
->magic
= 0xdead; /* invalidate signature */
513 /* Delete the Win32 part of the task */
515 /* PROCESS_FreePDB( pTask->thdb->process ); FIXME */
516 /* K32OBJ_DecCount( &pTask->thdb->header ); FIXME */
518 /* Free the selector aliases */
520 GLOBAL_FreeBlock( pTask
->hCSAlias
);
521 GLOBAL_FreeBlock( pTask
->hPDB
);
523 /* Free the task module */
525 FreeModule16( pTask
->hModule
);
527 /* Free the task structure itself */
529 GlobalFree16( hTask
);
531 /* Free all memory used by this task (including the 32-bit stack, */
532 /* the environment block and the thunk segments). */
534 GlobalFreeAll16( hPDB
);
537 /***********************************************************************
540 void TASK_KillTask( HTASK16 hTask
)
544 /* Enter the Win16Lock to protect global data structures */
545 SYSLEVEL_EnterWin16Lock();
547 if ( !hTask
) hTask
= GetCurrentTask();
548 pTask
= (TDB
*)GlobalLock16( hTask
);
551 SYSLEVEL_LeaveWin16Lock();
555 TRACE(task
, "Killing task %04x\n", hTask
);
557 /* Delete active sockets */
560 WINSOCK_DeleteTaskWSI( pTask
, pTask
->pwsi
);
564 /* Kill DOS VM task */
565 NE_MODULE
*pModule
= NE_GetPtr( pTask
->hModule
);
566 if ( pModule
->lpDosTask
)
567 MZ_KillModule( pModule
->lpDosTask
);
571 /* Perform USER cleanup */
573 if (pTask
->userhandler
)
574 pTask
->userhandler( hTask
, USIG16_TERMINATION
, 0,
575 pTask
->hInstance
, pTask
->hQueue
);
577 PROCESS_CallUserSignalProc( USIG_PROCESS_EXIT
, 0 );
578 PROCESS_CallUserSignalProc( USIG_THREAD_EXIT
, 0 ); /* FIXME */
579 PROCESS_CallUserSignalProc( USIG_PROCESS_DESTROY
, 0 );
583 TRACE(task
, "this is the last task, exiting\n" );
587 /* FIXME: Hack! Send a message to the initial task so that
588 * the GetMessage wakes up and the initial task can check whether
589 * it is the only remaining one and terminate itself ...
590 * The initial task should probably install hooks or something
591 * to get informed about task termination :-/
593 Callout
.PostAppMessage16( PROCESS_Initial()->task
, WM_NULL
, 0, 0 );
595 /* Remove the task from the list to be sure we never switch back to it */
596 TASK_UnlinkTask( hTask
);
599 TDB
* p
= (TDB
*)GlobalLock16( hFirstTask
);
602 if( p
->hYieldTo
== hTask
) p
->hYieldTo
= 0;
603 p
= (TDB
*)GlobalLock16( p
->hNext
);
609 if ( hLockedTask
== hTask
)
612 if ( hTaskToKill
&& ( hTaskToKill
!= hCurrentTask
) )
614 /* If another task is already marked for destruction, */
615 /* we can kill it now, as we are in another context. */
616 TASK_DeleteTask( hTaskToKill
);
621 * If hTask is not the task currently scheduled by the Win16
622 * scheduler, we simply delete it; otherwise we mark it for
623 * destruction. Note that if the current task is a 32-bit
624 * one, hCurrentTask is *different* from GetCurrentTask()!
626 if ( hTask
== hCurrentTask
)
628 assert( hTaskToKill
== 0 || hTaskToKill
== hCurrentTask
);
629 hTaskToKill
= hCurrentTask
;
632 TASK_DeleteTask( hTask
);
634 SYSLEVEL_LeaveWin16Lock();
638 /***********************************************************************
639 * TASK_KillCurrentTask
641 * Kill the currently running task. As it's not possible to kill the
642 * current task like this, it is simply marked for destruction, and will
643 * be killed when either TASK_Reschedule or this function is called again
644 * in the context of another task.
646 void TASK_KillCurrentTask( INT16 exitCode
)
648 if ( !THREAD_IsWin16( THREAD_Current() ) )
650 FIXME(task
, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel
);
654 assert(hCurrentTask
== GetCurrentTask());
656 TRACE(task
, "Killing current task %04x\n", hCurrentTask
);
660 TASK_YieldToSystem();
662 /* We should never return from this Yield() */
664 ERR(task
,"Return of the living dead %04x!!!\n", hCurrentTask
);
668 /***********************************************************************
671 * This is where all the magic of task-switching happens!
673 * Note: This function should only be called via the TASK_YieldToSystem()
674 * wrapper, to make sure that all the context is saved correctly.
676 * It must not call functions that may yield control.
678 BOOL
TASK_Reschedule(void)
680 TDB
*pOldTask
= NULL
, *pNewTask
;
682 STACK16FRAME
*newframe16
;
683 BOOL pending
= FALSE
;
685 /* Get the initial task up and running */
686 if (!hCurrentTask
&& GetCurrentTask())
688 /* We need to remove one pair of stackframes (exept for Winelib) */
689 STACK16FRAME
*oldframe16
= CURRENT_STACK16
;
690 STACK32FRAME
*oldframe32
= oldframe16
->frame32
;
691 STACK16FRAME
*newframe16
= PTR_SEG_TO_LIN( oldframe32
->frame16
);
692 STACK32FRAME
*newframe32
= newframe16
->frame32
;
695 newframe16
->entry_ip
= oldframe16
->entry_ip
;
696 newframe16
->entry_cs
= oldframe16
->entry_cs
;
697 newframe16
->ip
= oldframe16
->ip
;
698 newframe16
->cs
= oldframe16
->cs
;
699 newframe32
->ebp
= oldframe32
->ebp
;
700 newframe32
->restore_addr
= oldframe32
->restore_addr
;
701 newframe32
->codeselector
= oldframe32
->codeselector
;
703 THREAD_Current()->cur_stack
= oldframe32
->frame16
;
706 hCurrentTask
= GetCurrentTask();
707 pNewTask
= (TDB
*)GlobalLock16( hCurrentTask
);
708 pNewTask
->ss_sp
= pNewTask
->thdb
->cur_stack
;
712 /* NOTE: As we are entered from 16-bit code, we hold the Win16Lock.
713 We hang onto it thoughout most of this routine, so that accesses
714 to global variables (most notably the task list) are protected. */
715 assert(hCurrentTask
== GetCurrentTask());
717 TRACE(task
, "entered with hTask %04x (pid %d)\n", hCurrentTask
, getpid());
720 /* FIXME: What about the Win16Lock ??? */
723 /* First check if there's a task to kill */
725 if (hTaskToKill
&& (hTaskToKill
!= hCurrentTask
))
727 TASK_DeleteTask( hTaskToKill
);
731 /* Find a task to yield to */
733 pOldTask
= (TDB
*)GlobalLock16( hCurrentTask
);
734 if (pOldTask
&& pOldTask
->hYieldTo
)
736 /* check for DirectedYield() */
738 hTask
= pOldTask
->hYieldTo
;
739 pNewTask
= (TDB
*)GlobalLock16( hTask
);
740 if( !pNewTask
|| !pNewTask
->nEvents
) hTask
= 0;
741 pOldTask
->hYieldTo
= 0;
744 /* extract hardware events only! */
746 if (!hTask
) pending
= EVENT_WaitNetEvent( FALSE
, TRUE
);
750 /* Find a task that has an event pending */
755 pNewTask
= (TDB
*)GlobalLock16( hTask
);
757 TRACE(task
, "\ttask = %04x, events = %i\n", hTask
, pNewTask
->nEvents
);
759 if (pNewTask
->nEvents
) break;
760 hTask
= pNewTask
->hNext
;
762 if (hLockedTask
&& (hTask
!= hLockedTask
)) hTask
= 0;
765 /* If a non-hardware event is pending, return to TASK_YieldToSystem
766 temporarily to process it safely */
767 if (pending
) return TRUE
;
769 /* No task found, wait for some events to come in */
771 /* NOTE: We release the Win16Lock while waiting for events. This is to enable
772 Win32 threads to thunk down to 16-bit temporarily. Since Win16
773 tasks won't execute and Win32 threads are not allowed to enter
774 TASK_Reschedule anyway, there should be no re-entrancy problem ... */
776 SYSLEVEL_ReleaseWin16Lock();
777 pending
= EVENT_WaitNetEvent( TRUE
, TRUE
);
778 SYSLEVEL_RestoreWin16Lock();
781 if (hTask
== hCurrentTask
)
783 TRACE(task
, "returning to the current task(%04x)\n", hTask
);
784 return FALSE
; /* Nothing to do */
786 pNewTask
= (TDB
*)GlobalLock16( hTask
);
787 TRACE(task
, "Switching to task %04x (%.8s)\n",
788 hTask
, pNewTask
->module_name
);
790 /* Make the task the last in the linked list (round-robin scheduling) */
792 pNewTask
->priority
++;
793 TASK_UnlinkTask( hTask
);
794 TASK_LinkTask( hTask
);
795 pNewTask
->priority
--;
797 /* Finish initializing the new task stack if necessary */
799 newframe16
= THREAD_STACK16( pNewTask
->thdb
);
800 if (!newframe16
->entry_cs
)
802 STACK16FRAME
*oldframe16
= CURRENT_STACK16
;
803 STACK32FRAME
*oldframe32
= oldframe16
->frame32
;
804 STACK32FRAME
*newframe32
= newframe16
->frame32
;
805 newframe16
->entry_ip
= oldframe16
->entry_ip
;
806 newframe16
->entry_cs
= oldframe16
->entry_cs
;
807 newframe16
->ip
= oldframe16
->ip
;
808 newframe16
->cs
= oldframe16
->cs
;
809 newframe32
->ebp
= oldframe32
->ebp
;
810 newframe32
->restore_addr
= oldframe32
->restore_addr
;
811 newframe32
->codeselector
= oldframe32
->codeselector
;
814 /* Switch to the new stack */
816 /* NOTE: We need to release/restore the Win16Lock, as the task
817 switched to might be at another recursion level than
820 SYSLEVEL_ReleaseWin16Lock();
822 hCurrentTask
= hTask
;
823 SET_CUR_THREAD( pNewTask
->thdb
);
824 pNewTask
->ss_sp
= pNewTask
->thdb
->cur_stack
;
826 SYSLEVEL_RestoreWin16Lock();
832 /***********************************************************************
835 * Scheduler interface, this way we ensure that all "unsafe" events are
836 * processed outside the scheduler.
838 static void TASK_YieldToSystem( void )
840 if ( !THREAD_IsWin16( THREAD_Current() ) )
842 FIXME(task
, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel
);
846 if ( Callbacks
->CallTaskRescheduleProc() )
848 /* NOTE: We get here only when no task has an event. This means also
849 the current task, so we shouldn't actually return to the
850 caller here. But, we need to do so, as the EVENT_WaitNetEvent
851 call could lead to a complex series of inter-task SendMessage
852 calls which might leave this task in a state where it again
853 has no event, but where its queue's wakeMask is also reset
854 to zero. Reentering TASK_Reschedule in this state would be
855 suicide. Hence, we do return to the caller after processing
856 non-hardware events. Actually, this should not hurt anyone,
857 as the caller must be WaitEvent, and thus the QUEUE_WaitBits
858 loop in USER. Should there actually be no message pending
859 for this task after processing non-hardware events, that loop
860 will simply return to WaitEvent. */
862 EVENT_WaitNetEvent( FALSE
, FALSE
);
867 /***********************************************************************
868 * InitTask (KERNEL.91)
870 * Called by the application startup code.
872 void WINAPI
InitTask16( CONTEXT
*context
)
876 SEGTABLEENTRY
*pSegTable
;
877 INSTANCEDATA
*pinstance
;
878 LONG stacklow
, stackhi
;
880 if (context
) EAX_reg(context
) = 0;
881 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return;
882 if (!(pModule
= NE_GetPtr( pTask
->hModule
))) return;
884 /* Initialize implicitly loaded DLLs */
885 NE_InitializeDLLs( pTask
->hModule
);
889 /* Registers on return are:
890 * ax 1 if OK, 0 on error
891 * cx stack limit in bytes
892 * dx cmdShow parameter
893 * si instance handle of the previous instance
894 * di instance handle of the new task
895 * es:bx pointer to command-line inside PSP
897 * 0 (=%bp) is pushed on the stack
899 SEGPTR ptr
= STACK16_PUSH( pTask
->thdb
, sizeof(WORD
) );
900 *(WORD
*)PTR_SEG_TO_LIN(ptr
) = 0;
901 SP_reg(context
) -= 2;
903 EAX_reg(context
) = 1;
905 if (!pTask
->pdb
.cmdLine
[0]) EBX_reg(context
) = 0x80;
908 LPBYTE p
= &pTask
->pdb
.cmdLine
[1];
909 while ((*p
== ' ') || (*p
== '\t')) p
++;
910 EBX_reg(context
) = 0x80 + (p
- pTask
->pdb
.cmdLine
);
912 ECX_reg(context
) = pModule
->stack_size
;
913 EDX_reg(context
) = pTask
->nCmdShow
;
914 ESI_reg(context
) = (DWORD
)pTask
->hPrevInstance
;
915 EDI_reg(context
) = (DWORD
)pTask
->hInstance
;
916 ES_reg (context
) = (WORD
)pTask
->hPDB
;
919 /* Initialize the local heap */
920 if ( pModule
->heap_size
)
922 LocalInit16( pTask
->hInstance
, 0, pModule
->heap_size
);
925 /* Initialize the INSTANCEDATA structure */
926 pSegTable
= NE_SEG_TABLE( pModule
);
927 stacklow
= pSegTable
[pModule
->ss
- 1].minsize
;
928 stackhi
= stacklow
+ pModule
->stack_size
;
929 if (stackhi
> 0xffff) stackhi
= 0xffff;
930 pinstance
= (INSTANCEDATA
*)PTR_SEG_OFF_TO_LIN(CURRENT_DS
, 0);
931 pinstance
->stackbottom
= stackhi
; /* yup, that's right. Confused me too. */
932 pinstance
->stacktop
= stacklow
;
933 pinstance
->stackmin
= OFFSETOF( pTask
->thdb
->cur_stack
);
937 /***********************************************************************
938 * WaitEvent (KERNEL.30)
940 BOOL16 WINAPI
WaitEvent16( HTASK16 hTask
)
944 if (!hTask
) hTask
= GetCurrentTask();
945 pTask
= (TDB
*)GlobalLock16( hTask
);
947 if ( !THREAD_IsWin16( THREAD_Current() ) )
949 FIXME(task
, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel
);
953 if (pTask
->nEvents
> 0)
958 TASK_YieldToSystem();
960 /* When we get back here, we have an event */
962 if (pTask
->nEvents
> 0) pTask
->nEvents
--;
967 /***********************************************************************
968 * PostEvent (KERNEL.31)
970 void WINAPI
PostEvent16( HTASK16 hTask
)
974 if (!hTask
) hTask
= GetCurrentTask();
975 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return;
977 if ( !THREAD_IsWin16( pTask
->thdb
) )
979 FIXME( task
, "called for Win32 thread (%04x)!\n", pTask
->thdb
->teb_sel
);
985 if ( !THREAD_IsWin16( THREAD_Current() ) )
987 /* wake-up the scheduler waiting in EVENT_WaitNetEvent */
993 /***********************************************************************
994 * SetPriority (KERNEL.32)
996 void WINAPI
SetPriority16( HTASK16 hTask
, INT16 delta
)
1001 if (!hTask
) hTask
= GetCurrentTask();
1002 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return;
1003 newpriority
= pTask
->priority
+ delta
;
1004 if (newpriority
< -32) newpriority
= -32;
1005 else if (newpriority
> 15) newpriority
= 15;
1007 pTask
->priority
= newpriority
+ 1;
1008 TASK_UnlinkTask( hTask
);
1009 TASK_LinkTask( hTask
);
1014 /***********************************************************************
1015 * LockCurrentTask (KERNEL.33)
1017 HTASK16 WINAPI
LockCurrentTask16( BOOL16 bLock
)
1019 if (bLock
) hLockedTask
= GetCurrentTask();
1020 else hLockedTask
= 0;
1025 /***********************************************************************
1026 * IsTaskLocked (KERNEL.122)
1028 HTASK16 WINAPI
IsTaskLocked16(void)
1034 /***********************************************************************
1035 * OldYield (KERNEL.117)
1037 void WINAPI
OldYield16(void)
1039 TDB
*pCurTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
1041 if ( !THREAD_IsWin16( THREAD_Current() ) )
1043 FIXME(task
, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel
);
1047 if (pCurTask
) pCurTask
->nEvents
++; /* Make sure we get back here */
1048 TASK_YieldToSystem();
1049 if (pCurTask
) pCurTask
->nEvents
--;
1053 /***********************************************************************
1054 * DirectedYield (KERNEL.150)
1056 void WINAPI
DirectedYield16( HTASK16 hTask
)
1058 TDB
*pCurTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
1060 if ( !THREAD_IsWin16( THREAD_Current() ) )
1062 FIXME(task
, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel
);
1066 TRACE(task
, "%04x: DirectedYield(%04x)\n", pCurTask
->hSelf
, hTask
);
1068 pCurTask
->hYieldTo
= hTask
;
1071 TRACE(task
, "%04x: back from DirectedYield(%04x)\n", pCurTask
->hSelf
, hTask
);
1074 /***********************************************************************
1075 * Yield16 (KERNEL.29)
1077 void WINAPI
Yield16(void)
1079 TDB
*pCurTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
1081 if (pCurTask
) pCurTask
->hYieldTo
= 0;
1082 if (pCurTask
&& pCurTask
->hQueue
) Callout
.UserYield16();
1086 /***********************************************************************
1087 * KERNEL_490 (KERNEL.490)
1089 HTASK16 WINAPI
KERNEL_490( HTASK16 someTask
)
1091 if ( !someTask
) return 0;
1093 FIXME( task
, "(%04x): stub\n", someTask
);
1097 /***********************************************************************
1098 * MakeProcInstance16 (KERNEL.51)
1100 FARPROC16 WINAPI
MakeProcInstance16( FARPROC16 func
, HANDLE16 hInstance
)
1106 ERR(task
, "Ouch ! MakeProcInstance called with func == NULL !\n");
1107 return (FARPROC16
)0; /* Windows seems to do the same */
1109 if (!hInstance
) hInstance
= CURRENT_DS
;
1110 thunkaddr
= TASK_AllocThunk( GetCurrentTask() );
1111 if (!thunkaddr
) return (FARPROC16
)0;
1112 thunk
= PTR_SEG_TO_LIN( thunkaddr
);
1113 lfunc
= PTR_SEG_TO_LIN( func
);
1115 TRACE(task
, "(%08lx,%04x): got thunk %08lx\n",
1116 (DWORD
)func
, hInstance
, (DWORD
)thunkaddr
);
1117 if (((lfunc
[0]==0x8c) && (lfunc
[1]==0xd8)) ||
1118 ((lfunc
[0]==0x1e) && (lfunc
[1]==0x58))
1120 FIXME(task
,"thunk would be useless for %p, overwriting with nop;nop;\n", func
);
1121 lfunc
[0]=0x90; /* nop */
1122 lfunc
[1]=0x90; /* nop */
1125 *thunk
++ = 0xb8; /* movw instance, %ax */
1126 *thunk
++ = (BYTE
)(hInstance
& 0xff);
1127 *thunk
++ = (BYTE
)(hInstance
>> 8);
1128 *thunk
++ = 0xea; /* ljmp func */
1129 *(DWORD
*)thunk
= (DWORD
)func
;
1130 return (FARPROC16
)thunkaddr
;
1134 /***********************************************************************
1135 * FreeProcInstance16 (KERNEL.52)
1137 void WINAPI
FreeProcInstance16( FARPROC16 func
)
1139 TRACE(task
, "(%08lx)\n", (DWORD
)func
);
1140 TASK_FreeThunk( GetCurrentTask(), (SEGPTR
)func
);
1144 /**********************************************************************
1145 * GetCodeHandle (KERNEL.93)
1147 HANDLE16 WINAPI
GetCodeHandle16( FARPROC16 proc
)
1150 BYTE
*thunk
= (BYTE
*)PTR_SEG_TO_LIN( proc
);
1152 /* Return the code segment containing 'proc'. */
1153 /* Not sure if this is really correct (shouldn't matter that much). */
1155 /* Check if it is really a thunk */
1156 if ((thunk
[0] == 0xb8) && (thunk
[3] == 0xea))
1157 handle
= GlobalHandle16( thunk
[6] + (thunk
[7] << 8) );
1159 handle
= GlobalHandle16( HIWORD(proc
) );
1164 /**********************************************************************
1165 * GetCodeInfo (KERNEL.104)
1167 VOID WINAPI
GetCodeInfo16( FARPROC16 proc
, SEGINFO
*segInfo
)
1169 BYTE
*thunk
= (BYTE
*)PTR_SEG_TO_LIN( proc
);
1170 NE_MODULE
*pModule
= NULL
;
1171 SEGTABLEENTRY
*pSeg
= NULL
;
1174 /* proc is either a thunk, or else a pair of module handle
1175 and segment number. In the first case, we also need to
1176 extract module and segment number. */
1178 if ((thunk
[0] == 0xb8) && (thunk
[3] == 0xea))
1180 WORD selector
= thunk
[6] + (thunk
[7] << 8);
1181 pModule
= NE_GetPtr( GlobalHandle16( selector
) );
1182 pSeg
= pModule
? NE_SEG_TABLE( pModule
) : NULL
;
1185 for ( segNr
= 0; segNr
< pModule
->seg_count
; segNr
++, pSeg
++ )
1186 if ( GlobalHandleToSel16(pSeg
->hSeg
) == selector
)
1189 if ( pModule
&& segNr
>= pModule
->seg_count
)
1194 pModule
= NE_GetPtr( HIWORD( proc
) );
1195 segNr
= LOWORD( proc
);
1197 if ( pModule
&& segNr
< pModule
->seg_count
)
1198 pSeg
= NE_SEG_TABLE( pModule
) + segNr
;
1201 /* fill in segment information */
1203 segInfo
->offSegment
= pSeg
? pSeg
->filepos
: 0;
1204 segInfo
->cbSegment
= pSeg
? pSeg
->size
: 0;
1205 segInfo
->flags
= pSeg
? pSeg
->flags
: 0;
1206 segInfo
->cbAlloc
= pSeg
? pSeg
->minsize
: 0;
1207 segInfo
->h
= pSeg
? pSeg
->hSeg
: 0;
1208 segInfo
->alignShift
= pModule
? pModule
->alignment
: 0;
1212 /**********************************************************************
1213 * DefineHandleTable16 (KERNEL.94)
1215 BOOL16 WINAPI
DefineHandleTable16( WORD wOffset
)
1217 return TRUE
; /* FIXME */
1221 /***********************************************************************
1222 * SetTaskQueue (KERNEL.34)
1224 HQUEUE16 WINAPI
SetTaskQueue16( HTASK16 hTask
, HQUEUE16 hQueue
)
1229 if (!hTask
) hTask
= GetCurrentTask();
1230 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return 0;
1232 hPrev
= pTask
->hQueue
;
1233 pTask
->hQueue
= hQueue
;
1235 TIMER_SwitchQueue( hPrev
, hQueue
);
1241 /***********************************************************************
1242 * GetTaskQueue (KERNEL.35)
1244 HQUEUE16 WINAPI
GetTaskQueue16( HTASK16 hTask
)
1248 if (!hTask
) hTask
= GetCurrentTask();
1249 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return 0;
1250 return pTask
->hQueue
;
1253 /***********************************************************************
1254 * SetThreadQueue (KERNEL.463)
1256 HQUEUE16 WINAPI
SetThreadQueue16( DWORD thread
, HQUEUE16 hQueue
)
1258 THDB
*thdb
= thread
? THREAD_IdToTHDB( thread
) : THREAD_Current();
1259 HQUEUE16 oldQueue
= thdb
? thdb
->teb
.queue
: 0;
1263 thdb
->teb
.queue
= hQueue
;
1265 if ( GetTaskQueue16( thdb
->process
->task
) == oldQueue
)
1266 SetTaskQueue16( thdb
->process
->task
, hQueue
);
1272 /***********************************************************************
1273 * GetThreadQueue (KERNEL.464)
1275 HQUEUE16 WINAPI
GetThreadQueue16( DWORD thread
)
1279 thdb
= THREAD_Current();
1280 else if ( HIWORD(thread
) )
1281 thdb
= THREAD_IdToTHDB( thread
);
1282 else if ( IsTask16( (HTASK16
)thread
) )
1283 thdb
= ((TDB
*)GlobalLock16( (HANDLE16
)thread
))->thdb
;
1285 return (HQUEUE16
)(thdb
? thdb
->teb
.queue
: 0);
1288 /***********************************************************************
1289 * SetFastQueue (KERNEL.624)
1291 VOID WINAPI
SetFastQueue16( DWORD thread
, HANDLE hQueue
)
1295 thdb
= THREAD_Current();
1296 else if ( HIWORD(thread
) )
1297 thdb
= THREAD_IdToTHDB( thread
);
1298 else if ( IsTask16( (HTASK16
)thread
) )
1299 thdb
= ((TDB
*)GlobalLock16( (HANDLE16
)thread
))->thdb
;
1301 if ( thdb
) thdb
->teb
.queue
= (HQUEUE16
) hQueue
;
1304 /***********************************************************************
1305 * GetFastQueue (KERNEL.625)
1307 HANDLE WINAPI
GetFastQueue16( void )
1309 THDB
*thdb
= THREAD_Current();
1310 if (!thdb
) return 0;
1312 if (!thdb
->teb
.queue
)
1313 Callout
.InitThreadInput16( 0, THREAD_IsWin16(thdb
)? 4 : 5 );
1315 if (!thdb
->teb
.queue
)
1316 FIXME( task
, "(): should initialize thread-local queue, expect failure!\n" );
1318 return (HANDLE
)thdb
->teb
.queue
;
1321 /***********************************************************************
1322 * SwitchStackTo (KERNEL.108)
1324 void WINAPI
SwitchStackTo16( WORD seg
, WORD ptr
, WORD top
)
1327 STACK16FRAME
*oldFrame
, *newFrame
;
1328 INSTANCEDATA
*pData
;
1331 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return;
1332 if (!(pData
= (INSTANCEDATA
*)GlobalLock16( seg
))) return;
1333 TRACE(task
, "old=%04x:%04x new=%04x:%04x\n",
1334 SELECTOROF( pTask
->thdb
->cur_stack
),
1335 OFFSETOF( pTask
->thdb
->cur_stack
), seg
, ptr
);
1337 /* Save the old stack */
1339 oldFrame
= THREAD_STACK16( pTask
->thdb
);
1340 /* pop frame + args and push bp */
1341 pData
->old_ss_sp
= pTask
->thdb
->cur_stack
+ sizeof(STACK16FRAME
)
1343 *(WORD
*)PTR_SEG_TO_LIN(pData
->old_ss_sp
) = oldFrame
->bp
;
1344 pData
->stacktop
= top
;
1345 pData
->stackmin
= ptr
;
1346 pData
->stackbottom
= ptr
;
1348 /* Switch to the new stack */
1350 /* Note: we need to take the 3 arguments into account; otherwise,
1351 * the stack will underflow upon return from this function.
1353 copySize
= oldFrame
->bp
- OFFSETOF(pData
->old_ss_sp
);
1354 copySize
+= 3 * sizeof(WORD
) + sizeof(STACK16FRAME
);
1355 pTask
->thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR( seg
, ptr
- copySize
);
1356 newFrame
= THREAD_STACK16( pTask
->thdb
);
1358 /* Copy the stack frame and the local variables to the new stack */
1360 memmove( newFrame
, oldFrame
, copySize
);
1362 *(WORD
*)PTR_SEG_OFF_TO_LIN( seg
, ptr
) = 0; /* clear previous bp */
1366 /***********************************************************************
1367 * SwitchStackBack (KERNEL.109)
1369 void WINAPI
SwitchStackBack16( CONTEXT
*context
)
1372 STACK16FRAME
*oldFrame
, *newFrame
;
1373 INSTANCEDATA
*pData
;
1375 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return;
1376 if (!(pData
= (INSTANCEDATA
*)GlobalLock16(SELECTOROF(pTask
->thdb
->cur_stack
))))
1378 if (!pData
->old_ss_sp
)
1380 WARN( task
, "No previous SwitchStackTo\n" );
1383 TRACE(task
, "restoring stack %04x:%04x\n",
1384 SELECTOROF(pData
->old_ss_sp
), OFFSETOF(pData
->old_ss_sp
) );
1386 oldFrame
= THREAD_STACK16( pTask
->thdb
);
1388 /* Pop bp from the previous stack */
1390 BP_reg(context
) = *(WORD
*)PTR_SEG_TO_LIN(pData
->old_ss_sp
);
1391 pData
->old_ss_sp
+= sizeof(WORD
);
1393 /* Switch back to the old stack */
1395 pTask
->thdb
->cur_stack
= pData
->old_ss_sp
- sizeof(STACK16FRAME
);
1396 SS_reg(context
) = SELECTOROF(pData
->old_ss_sp
);
1397 ESP_reg(context
) = OFFSETOF(pData
->old_ss_sp
) - sizeof(DWORD
); /*ret addr*/
1398 pData
->old_ss_sp
= 0;
1400 /* Build a stack frame for the return */
1402 newFrame
= THREAD_STACK16( pTask
->thdb
);
1403 newFrame
->frame32
= oldFrame
->frame32
;
1404 if (TRACE_ON(relay
))
1406 newFrame
->entry_ip
= oldFrame
->entry_ip
;
1407 newFrame
->entry_cs
= oldFrame
->entry_cs
;
1412 /***********************************************************************
1413 * GetTaskQueueDS (KERNEL.118)
1415 void WINAPI
GetTaskQueueDS16( CONTEXT
*context
)
1417 DS_reg(context
) = GlobalHandleToSel16( GetTaskQueue16(0) );
1421 /***********************************************************************
1422 * GetTaskQueueES (KERNEL.119)
1424 void WINAPI
GetTaskQueueES16( CONTEXT
*context
)
1426 ES_reg(context
) = GlobalHandleToSel16( GetTaskQueue16(0) );
1430 /***********************************************************************
1431 * GetCurrentTask (KERNEL.36)
1433 HTASK16 WINAPI
GetCurrentTask(void)
1435 return THREAD_InitDone
? PROCESS_Current()->task
: 0;
1438 DWORD WINAPI
WIN16_GetCurrentTask(void)
1440 /* This is the version used by relay code; the first task is */
1441 /* returned in the high word of the result */
1442 return MAKELONG( GetCurrentTask(), hFirstTask
);
1446 /***********************************************************************
1447 * GetCurrentPDB (KERNEL.37)
1449 * UNDOC: returns PSP of KERNEL in high word
1451 DWORD WINAPI
GetCurrentPDB16(void)
1455 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return 0;
1456 return MAKELONG(pTask
->hPDB
, 0); /* FIXME */
1460 /***********************************************************************
1461 * GetInstanceData (KERNEL.54)
1463 INT16 WINAPI
GetInstanceData16( HINSTANCE16 instance
, WORD buffer
, INT16 len
)
1465 char *ptr
= (char *)GlobalLock16( instance
);
1466 if (!ptr
|| !len
) return 0;
1467 if ((int)buffer
+ len
>= 0x10000) len
= 0x10000 - buffer
;
1468 memcpy( (char *)GlobalLock16(CURRENT_DS
) + buffer
, ptr
+ buffer
, len
);
1473 /***********************************************************************
1474 * GetExeVersion (KERNEL.105)
1476 WORD WINAPI
GetExeVersion16(void)
1480 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return 0;
1481 return pTask
->version
;
1485 /***********************************************************************
1486 * SetErrorMode16 (KERNEL.107)
1488 UINT16 WINAPI
SetErrorMode16( UINT16 mode
)
1493 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return 0;
1494 oldMode
= pTask
->error_mode
;
1495 pTask
->error_mode
= mode
;
1496 pTask
->thdb
->process
->error_mode
= mode
;
1501 /***********************************************************************
1502 * SetErrorMode32 (KERNEL32.486)
1504 UINT WINAPI
SetErrorMode( UINT mode
)
1506 return SetErrorMode16( (UINT16
)mode
);
1510 /***********************************************************************
1511 * GetDOSEnvironment (KERNEL.131)
1513 SEGPTR WINAPI
GetDOSEnvironment16(void)
1517 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return 0;
1518 return PTR_SEG_OFF_TO_SEGPTR( pTask
->pdb
.environment
, 0 );
1522 /***********************************************************************
1523 * GetNumTasks (KERNEL.152)
1525 UINT16 WINAPI
GetNumTasks16(void)
1531 /***********************************************************************
1532 * GetTaskDS (KERNEL.155)
1534 * Note: this function apparently returns a DWORD with LOWORD == HIWORD.
1535 * I don't think we need to bother with this.
1537 HINSTANCE16 WINAPI
GetTaskDS16(void)
1541 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return 0;
1542 return pTask
->hInstance
;
1545 /***********************************************************************
1546 * GetDummyModuleHandleDS (KERNEL.602)
1548 VOID WINAPI
GetDummyModuleHandleDS16( CONTEXT
*context
)
1553 AX_reg( context
) = 0;
1554 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return;
1555 if (!(pTask
->flags
& TDBF_WIN32
)) return;
1557 selector
= GlobalHandleToSel16( pTask
->hModule
);
1558 DS_reg( context
) = selector
;
1559 AX_reg( context
) = selector
;
1562 /***********************************************************************
1563 * IsTask (KERNEL.320)
1565 BOOL16 WINAPI
IsTask16( HTASK16 hTask
)
1569 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return FALSE
;
1570 if (GlobalSize16( hTask
) < sizeof(TDB
)) return FALSE
;
1571 return (pTask
->magic
== TDB_MAGIC
);
1575 /***********************************************************************
1576 * SetTaskSignalProc (KERNEL.38)
1578 * Real 16-bit interface is provided by the THUNK_SetTaskSignalProc.
1580 FARPROC16 WINAPI
SetTaskSignalProc( HTASK16 hTask
, FARPROC16 proc
)
1585 if (!hTask
) hTask
= GetCurrentTask();
1586 if (!(pTask
= (TDB
*)GlobalLock16( hTask
))) return NULL
;
1587 oldProc
= (FARPROC16
)pTask
->userhandler
;
1588 pTask
->userhandler
= (USERSIGNALPROC
)proc
;
1593 /***********************************************************************
1594 * SetSigHandler (KERNEL.140)
1596 WORD WINAPI
SetSigHandler16( FARPROC16 newhandler
, FARPROC16
* oldhandler
,
1597 UINT16
*oldmode
, UINT16 newmode
, UINT16 flag
)
1599 FIXME(task
,"(%p,%p,%p,%d,%d), unimplemented.\n",
1600 newhandler
,oldhandler
,oldmode
,newmode
,flag
);
1602 if (flag
!= 1) return 0;
1603 if (!newmode
) newhandler
= NULL
; /* Default handler */
1608 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return 0;
1609 if (oldmode
) *oldmode
= pTask
->signal_flags
;
1610 pTask
->signal_flags
= newmode
;
1611 if (oldhandler
) *oldhandler
= pTask
->sighandler
;
1612 pTask
->sighandler
= newhandler
;
1618 /***********************************************************************
1619 * GlobalNotify (KERNEL.154)
1621 * Note that GlobalNotify does _not_ return the old NotifyProc
1622 * -- contrary to LocalNotify !!
1624 VOID WINAPI
GlobalNotify16( FARPROC16 proc
)
1628 if (!(pTask
= (TDB
*)GlobalLock16( GetCurrentTask() ))) return;
1629 pTask
->discardhandler
= proc
;
1633 /***********************************************************************
1634 * GetExePtr (KERNEL.133)
1636 static HMODULE16
GetExePtrHelper( HANDLE16 handle
, HTASK16
*hTask
)
1641 /* Check for module handle */
1643 if (!(ptr
= GlobalLock16( handle
))) return 0;
1644 if (((NE_MODULE
*)ptr
)->magic
== IMAGE_OS2_SIGNATURE
) return handle
;
1646 /* Search for this handle inside all tasks */
1648 *hTask
= hFirstTask
;
1651 TDB
*pTask
= (TDB
*)GlobalLock16( *hTask
);
1652 if ((*hTask
== handle
) ||
1653 (pTask
->hInstance
== handle
) ||
1654 (pTask
->hQueue
== handle
) ||
1655 (pTask
->hPDB
== handle
)) return pTask
->hModule
;
1656 *hTask
= pTask
->hNext
;
1659 /* Check the owner for module handle */
1661 owner
= FarGetOwner16( handle
);
1662 if (!(ptr
= GlobalLock16( owner
))) return 0;
1663 if (((NE_MODULE
*)ptr
)->magic
== IMAGE_OS2_SIGNATURE
) return owner
;
1665 /* Search for the owner inside all tasks */
1667 *hTask
= hFirstTask
;
1670 TDB
*pTask
= (TDB
*)GlobalLock16( *hTask
);
1671 if ((*hTask
== owner
) ||
1672 (pTask
->hInstance
== owner
) ||
1673 (pTask
->hQueue
== owner
) ||
1674 (pTask
->hPDB
== owner
)) return pTask
->hModule
;
1675 *hTask
= pTask
->hNext
;
1681 HMODULE16 WINAPI
GetExePtr( HANDLE16 handle
)
1684 return GetExePtrHelper( handle
, &dummy
);
1687 void WINAPI
WIN16_GetExePtr( CONTEXT
*context
)
1689 WORD
*stack
= PTR_SEG_OFF_TO_LIN(SS_reg(context
), SP_reg(context
));
1690 HANDLE16 handle
= (HANDLE16
)stack
[2];
1694 hModule
= GetExePtrHelper( handle
, &hTask
);
1696 AX_reg(context
) = CX_reg(context
) = hModule
;
1697 if (hTask
) ES_reg(context
) = hTask
;
1700 /***********************************************************************
1701 * TaskFirst (TOOLHELP.63)
1703 BOOL16 WINAPI
TaskFirst16( TASKENTRY
*lpte
)
1705 lpte
->hNext
= hFirstTask
;
1706 return TaskNext16( lpte
);
1710 /***********************************************************************
1711 * TaskNext (TOOLHELP.64)
1713 BOOL16 WINAPI
TaskNext16( TASKENTRY
*lpte
)
1716 INSTANCEDATA
*pInstData
;
1718 TRACE(toolhelp
, "(%p): task=%04x\n", lpte
, lpte
->hNext
);
1719 if (!lpte
->hNext
) return FALSE
;
1720 pTask
= (TDB
*)GlobalLock16( lpte
->hNext
);
1721 if (!pTask
|| pTask
->magic
!= TDB_MAGIC
) return FALSE
;
1722 pInstData
= (INSTANCEDATA
*)PTR_SEG_OFF_TO_LIN( pTask
->hInstance
, 0 );
1723 lpte
->hTask
= lpte
->hNext
;
1724 lpte
->hTaskParent
= pTask
->hParent
;
1725 lpte
->hInst
= pTask
->hInstance
;
1726 lpte
->hModule
= pTask
->hModule
;
1727 lpte
->wSS
= SELECTOROF( pTask
->thdb
->cur_stack
);
1728 lpte
->wSP
= OFFSETOF( pTask
->thdb
->cur_stack
);
1729 lpte
->wStackTop
= pInstData
->stacktop
;
1730 lpte
->wStackMinimum
= pInstData
->stackmin
;
1731 lpte
->wStackBottom
= pInstData
->stackbottom
;
1732 lpte
->wcEvents
= pTask
->nEvents
;
1733 lpte
->hQueue
= pTask
->hQueue
;
1734 strncpy( lpte
->szModule
, pTask
->module_name
, 8 );
1735 lpte
->szModule
[8] = '\0';
1736 lpte
->wPSPOffset
= 0x100; /*??*/
1737 lpte
->hNext
= pTask
->hNext
;
1742 /***********************************************************************
1743 * TaskFindHandle (TOOLHELP.65)
1745 BOOL16 WINAPI
TaskFindHandle16( TASKENTRY
*lpte
, HTASK16 hTask
)
1747 lpte
->hNext
= hTask
;
1748 return TaskNext16( lpte
);
1752 /***********************************************************************
1753 * GetAppCompatFlags16 (KERNEL.354)
1755 DWORD WINAPI
GetAppCompatFlags16( HTASK16 hTask
)
1757 return GetAppCompatFlags( hTask
);
1761 /***********************************************************************
1762 * GetAppCompatFlags32 (USER32.206)
1764 DWORD WINAPI
GetAppCompatFlags( HTASK hTask
)
1768 if (!hTask
) hTask
= GetCurrentTask();
1769 if (!(pTask
=(TDB
*)GlobalLock16( (HTASK16
)hTask
))) return 0;
1770 if (GlobalSize16(hTask
) < sizeof(TDB
)) return 0;
1771 return pTask
->compat_flags
;