Implemented PROCESS_CallUserSignalProc().
[wine/hacks.git] / loader / task.c
blobf48c20f5257d46bca7f59eb439f2f6b6a1340219
1 /*
2 * Task functions
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <unistd.h>
12 #include "wine/winbase16.h"
13 #include "user.h"
14 #include "callback.h"
15 #include "drive.h"
16 #include "file.h"
17 #include "global.h"
18 #include "instance.h"
19 #include "message.h"
20 #include "miscemu.h"
21 #include "module.h"
22 #include "neexe.h"
23 #include "peexe.h"
24 #include "pe_image.h"
25 #include "process.h"
26 #include "queue.h"
27 #include "selectors.h"
28 #include "stackframe.h"
29 #include "task.h"
30 #include "thread.h"
31 #include "toolhelp.h"
32 #include "winnt.h"
33 #include "winsock.h"
34 #include "thread.h"
35 #include "syslevel.h"
36 #include "debug.h"
37 #include "dosexe.h"
38 #include "dde_proc.h"
39 #include "server.h"
41 /* Min. number of thunks allocated when creating a new segment */
42 #define MIN_THUNKS 32
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 /***********************************************************************
66 * TASK_InstallTHHook
68 void TASK_InstallTHHook( THHOOK *pNewThhook )
70 THHOOK *pOldThhook = pThhook;
72 pThhook = pNewThhook? pNewThhook : &DefaultThhook;
74 *pThhook = *pOldThhook;
77 /***********************************************************************
78 * TASK_GetNextTask
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 /***********************************************************************
89 * TASK_LinkTask
91 static void TASK_LinkTask( HTASK16 hTask )
93 HTASK16 *prevTask;
94 TDB *pTask;
96 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
97 prevTask = &hFirstTask;
98 while (*prevTask)
100 TDB *prevTaskPtr = (TDB *)GlobalLock16( *prevTask );
101 if (prevTaskPtr->priority >= pTask->priority) break;
102 prevTask = &prevTaskPtr->hNext;
104 pTask->hNext = *prevTask;
105 *prevTask = hTask;
106 nTaskCount++;
110 /***********************************************************************
111 * TASK_UnlinkTask
113 static void TASK_UnlinkTask( HTASK16 hTask )
115 HTASK16 *prevTask;
116 TDB *pTask;
118 prevTask = &hFirstTask;
119 while (*prevTask && (*prevTask != hTask))
121 pTask = (TDB *)GlobalLock16( *prevTask );
122 prevTask = &pTask->hNext;
124 if (*prevTask)
126 pTask = (TDB *)GlobalLock16( *prevTask );
127 *prevTask = pTask->hNext;
128 pTask->hNext = 0;
129 nTaskCount--;
134 /***********************************************************************
135 * TASK_CreateThunks
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 )
142 int i;
143 WORD free;
144 THUNKS *pThunk;
146 pThunk = (THUNKS *)((BYTE *)GlobalLock16( handle ) + offset);
147 pThunk->next = 0;
148 pThunk->magic = THUNK_MAGIC;
149 pThunk->free = (int)&pThunk->thunks - (int)pThunk;
150 free = pThunk->free;
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 /***********************************************************************
161 * TASK_AllocThunk
163 * Allocate a thunk for MakeProcInstance().
165 static SEGPTR TASK_AllocThunk( HTASK16 hTask )
167 TDB *pTask;
168 THUNKS *pThunk;
169 WORD sel, base;
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)
177 sel = pThunk->next;
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 );
184 pThunk->next = sel;
186 pThunk = (THUNKS *)GlobalLock16( sel );
187 base = 0;
189 base += pThunk->free;
190 pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free);
191 return PTR_SEG_OFF_TO_SEGPTR( sel, base );
195 /***********************************************************************
196 * TASK_FreeThunk
198 * Free a MakeProcInstance() thunk.
200 static BOOL TASK_FreeThunk( HTASK16 hTask, SEGPTR thunk )
202 TDB *pTask;
203 THUNKS *pThunk;
204 WORD sel, base;
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)))
212 sel = pThunk->next;
213 pThunk = (THUNKS *)GlobalLock16( sel );
214 base = 0;
216 if (!sel) return FALSE;
217 *(WORD *)((BYTE *)pThunk + LOWORD(thunk) - base) = pThunk->free;
218 pThunk->free = LOWORD(thunk) - base;
219 return TRUE;
223 /***********************************************************************
224 * TASK_CallToStart
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 );
236 CLIENT_InitThread();
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" );
250 ExitProcess( 1 );
252 else if (pModule->dos_image)
254 DOSVM_Enter( NULL );
255 ExitProcess( 0 );
257 else
259 /* Registers at initialization must be:
260 * ax zero
261 * bx stack size in bytes
262 * cx heap size in bytes
263 * si previous app instance
264 * di current app instance
265 * bp zero
266 * es selector to the PSP
267 * ds dgroup of the application
268 * ss stack selector
269 * sp top of the stack
271 CONTEXT context;
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" );
290 ExitProcess( 1 );
295 /***********************************************************************
296 * TASK_Create
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)
305 HTASK16 hTask;
306 TDB *pTask;
307 LPSTR cmd_line;
308 WORD sp;
309 char *stack32Top;
310 char name[10];
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 */
325 pTask->nEvents = 0;
326 pTask->hSelf = hTask;
327 pTask->flags = 0;
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;
341 pTask->thdb = thdb;
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 );
361 /* Fill the PDB */
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 */
407 if ( hInstance )
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;
422 frame16->fs = 0;
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);
433 frame32->edi = 0;
434 frame32->esi = 0;
435 frame32->edx = 0;
436 frame32->ecx = 0;
437 frame32->ebx = 0;
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 );
448 return TRUE;
451 /***********************************************************************
452 * TASK_StartTask
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
457 * global task list.
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 ) )
481 pTask->nEvents++;
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() ) )
487 OldYield16();
488 else
489 EVENT_WakeUp();
491 else
493 /* To start a 32-bit task, we spawn its initial thread. */
495 SYSDEPS_SpawnThread( pTask->thdb );
500 /***********************************************************************
501 * TASK_DeleteTask
503 static void TASK_DeleteTask( HTASK16 hTask )
505 TDB *pTask;
506 HGLOBAL16 hPDB;
508 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
509 hPDB = pTask->hPDB;
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 /***********************************************************************
538 * TASK_KillTask
540 void TASK_KillTask( HTASK16 hTask )
542 TDB *pTask;
544 /* Enter the Win16Lock to protect global data structures */
545 SYSLEVEL_EnterWin16Lock();
547 if ( !hTask ) hTask = GetCurrentTask();
548 pTask = (TDB *)GlobalLock16( hTask );
549 if ( !pTask )
551 SYSLEVEL_LeaveWin16Lock();
552 return;
555 TRACE(task, "Killing task %04x\n", hTask );
557 /* Delete active sockets */
559 if( pTask->pwsi )
560 WINSOCK_DeleteTaskWSI( pTask, pTask->pwsi );
562 #ifdef MZ_SUPPORTED
564 /* Kill DOS VM task */
565 NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
566 if ( pModule->lpDosTask )
567 MZ_KillModule( pModule->lpDosTask );
569 #endif
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 );
581 if (nTaskCount <= 1)
583 TRACE(task, "this is the last task, exiting\n" );
584 USER_ExitWindows();
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 );
597 if( nTaskCount )
599 TDB* p = (TDB *)GlobalLock16( hFirstTask );
600 while( p )
602 if( p->hYieldTo == hTask ) p->hYieldTo = 0;
603 p = (TDB *)GlobalLock16( p->hNext );
607 pTask->nEvents = 0;
609 if ( hLockedTask == hTask )
610 hLockedTask = 0;
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 );
617 hTaskToKill = 0;
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;
631 else
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);
651 return;
654 assert(hCurrentTask == GetCurrentTask());
656 TRACE(task, "Killing current task %04x\n", hCurrentTask );
658 TASK_KillTask( 0 );
660 TASK_YieldToSystem();
662 /* We should never return from this Yield() */
664 ERR(task,"Return of the living dead %04x!!!\n", hCurrentTask);
665 exit(1);
668 /***********************************************************************
669 * TASK_Reschedule
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;
681 HTASK16 hTask = 0;
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;
693 if (newframe32)
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;
709 return FALSE;
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());
719 #ifdef CONFIG_IPC
720 /* FIXME: What about the Win16Lock ??? */
721 dde_reschedule();
722 #endif
723 /* First check if there's a task to kill */
725 if (hTaskToKill && (hTaskToKill != hCurrentTask))
727 TASK_DeleteTask( hTaskToKill );
728 hTaskToKill = 0;
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 );
748 while (!hTask)
750 /* Find a task that has an event pending */
752 hTask = hFirstTask;
753 while (hTask)
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;
763 if (hTask) break;
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
818 the old task ... */
820 SYSLEVEL_ReleaseWin16Lock();
822 hCurrentTask = hTask;
823 SET_CUR_THREAD( pNewTask->thdb );
824 pNewTask->ss_sp = pNewTask->thdb->cur_stack;
826 SYSLEVEL_RestoreWin16Lock();
828 return FALSE;
832 /***********************************************************************
833 * TASK_YieldToSystem
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);
843 return;
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 )
874 TDB *pTask;
875 NE_MODULE *pModule;
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 );
887 if (context)
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;
906 else
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 )
942 TDB *pTask;
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);
950 return TRUE;
953 if (pTask->nEvents > 0)
955 pTask->nEvents--;
956 return FALSE;
958 TASK_YieldToSystem();
960 /* When we get back here, we have an event */
962 if (pTask->nEvents > 0) pTask->nEvents--;
963 return TRUE;
967 /***********************************************************************
968 * PostEvent (KERNEL.31)
970 void WINAPI PostEvent16( HTASK16 hTask )
972 TDB *pTask;
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 );
980 return;
983 pTask->nEvents++;
985 if ( !THREAD_IsWin16( THREAD_Current() ) )
987 /* wake-up the scheduler waiting in EVENT_WaitNetEvent */
988 EVENT_WakeUp();
993 /***********************************************************************
994 * SetPriority (KERNEL.32)
996 void WINAPI SetPriority16( HTASK16 hTask, INT16 delta )
998 TDB *pTask;
999 INT16 newpriority;
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 );
1010 pTask->priority--;
1014 /***********************************************************************
1015 * LockCurrentTask (KERNEL.33)
1017 HTASK16 WINAPI LockCurrentTask16( BOOL16 bLock )
1019 if (bLock) hLockedTask = GetCurrentTask();
1020 else hLockedTask = 0;
1021 return hLockedTask;
1025 /***********************************************************************
1026 * IsTaskLocked (KERNEL.122)
1028 HTASK16 WINAPI IsTaskLocked16(void)
1030 return hLockedTask;
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);
1044 return;
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);
1063 return;
1066 TRACE(task, "%04x: DirectedYield(%04x)\n", pCurTask->hSelf, hTask );
1068 pCurTask->hYieldTo = hTask;
1069 OldYield16();
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();
1083 else OldYield16();
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 );
1094 return 0;
1097 /***********************************************************************
1098 * MakeProcInstance16 (KERNEL.51)
1100 FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
1102 BYTE *thunk,*lfunc;
1103 SEGPTR thunkaddr;
1105 if (!func) {
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 )
1149 HANDLE16 handle;
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) );
1158 else
1159 handle = GlobalHandle16( HIWORD(proc) );
1161 return handle;
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;
1172 WORD segNr;
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;
1184 if ( pModule )
1185 for ( segNr = 0; segNr < pModule->seg_count; segNr++, pSeg++ )
1186 if ( GlobalHandleToSel16(pSeg->hSeg) == selector )
1187 break;
1189 if ( pModule && segNr >= pModule->seg_count )
1190 pSeg = NULL;
1192 else
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 )
1226 HQUEUE16 hPrev;
1227 TDB *pTask;
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 );
1237 return hPrev;
1241 /***********************************************************************
1242 * GetTaskQueue (KERNEL.35)
1244 HQUEUE16 WINAPI GetTaskQueue16( HTASK16 hTask )
1246 TDB *pTask;
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;
1261 if ( thdb )
1263 thdb->teb.queue = hQueue;
1265 if ( GetTaskQueue16( thdb->process->task ) == oldQueue )
1266 SetTaskQueue16( thdb->process->task, hQueue );
1269 return oldQueue;
1272 /***********************************************************************
1273 * GetThreadQueue (KERNEL.464)
1275 HQUEUE16 WINAPI GetThreadQueue16( DWORD thread )
1277 THDB *thdb = NULL;
1278 if ( !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 )
1293 THDB *thdb = NULL;
1294 if ( !thread )
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 )
1326 TDB *pTask;
1327 STACK16FRAME *oldFrame, *newFrame;
1328 INSTANCEDATA *pData;
1329 UINT16 copySize;
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)
1342 + 2 * sizeof(WORD);
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 );
1361 newFrame->bp = ptr;
1362 *(WORD *)PTR_SEG_OFF_TO_LIN( seg, ptr ) = 0; /* clear previous bp */
1366 /***********************************************************************
1367 * SwitchStackBack (KERNEL.109)
1369 void WINAPI SwitchStackBack16( CONTEXT *context )
1371 TDB *pTask;
1372 STACK16FRAME *oldFrame, *newFrame;
1373 INSTANCEDATA *pData;
1375 if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
1376 if (!(pData = (INSTANCEDATA *)GlobalLock16(SELECTOROF(pTask->thdb->cur_stack))))
1377 return;
1378 if (!pData->old_ss_sp)
1380 WARN( task, "No previous SwitchStackTo\n" );
1381 return;
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)
1453 TDB *pTask;
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 );
1469 return len;
1473 /***********************************************************************
1474 * GetExeVersion (KERNEL.105)
1476 WORD WINAPI GetExeVersion16(void)
1478 TDB *pTask;
1480 if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
1481 return pTask->version;
1485 /***********************************************************************
1486 * SetErrorMode16 (KERNEL.107)
1488 UINT16 WINAPI SetErrorMode16( UINT16 mode )
1490 TDB *pTask;
1491 UINT16 oldMode;
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;
1497 return oldMode;
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)
1515 TDB *pTask;
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)
1527 return nTaskCount;
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)
1539 TDB *pTask;
1541 if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
1542 return pTask->hInstance;
1545 /***********************************************************************
1546 * GetDummyModuleHandleDS (KERNEL.602)
1548 VOID WINAPI GetDummyModuleHandleDS16( CONTEXT *context )
1550 TDB *pTask;
1551 WORD selector;
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 )
1567 TDB *pTask;
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 )
1582 TDB *pTask;
1583 FARPROC16 oldProc;
1585 if (!hTask) hTask = GetCurrentTask();
1586 if (!(pTask = (TDB *)GlobalLock16( hTask ))) return NULL;
1587 oldProc = (FARPROC16)pTask->userhandler;
1588 pTask->userhandler = (USERSIGNALPROC)proc;
1589 return oldProc;
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 */
1604 if (newmode != 4)
1606 TDB *pTask;
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;
1614 return 0;
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 )
1626 TDB *pTask;
1628 if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
1629 pTask->discardhandler = proc;
1633 /***********************************************************************
1634 * GetExePtr (KERNEL.133)
1636 static HMODULE16 GetExePtrHelper( HANDLE16 handle, HTASK16 *hTask )
1638 char *ptr;
1639 HANDLE16 owner;
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;
1649 while (*hTask)
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;
1668 while (*hTask)
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;
1678 return 0;
1681 HMODULE16 WINAPI GetExePtr( HANDLE16 handle )
1683 HTASK16 dummy;
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];
1691 HTASK16 hTask = 0;
1692 HMODULE16 hModule;
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 )
1715 TDB *pTask;
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;
1738 return TRUE;
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 )
1766 TDB *pTask;
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;