task.c 48.2 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2
 * Task functions
Alexandre Julliard's avatar
Alexandre Julliard committed
3
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4 5 6
 * Copyright 1995 Alexandre Julliard
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
7 8
#include <stdlib.h>
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
9
#include <assert.h>
10
#include <unistd.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
11

12
#include "wine/winbase16.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
13
#include "user.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
14
#include "callback.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
15
#include "drive.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
16
#include "file.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
17 18
#include "global.h"
#include "instance.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
19
#include "message.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
20
#include "miscemu.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
21 22
#include "module.h"
#include "neexe.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
23
#include "pe_image.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include "process.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include "queue.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
26
#include "selectors.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
27
#include "stackframe.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include "task.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
29
#include "thread.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
30
#include "toolhelp.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
31
#include "winnt.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
32
#include "winsock.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33
#include "syslevel.h"
34
#include "debugtools.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
35
#include "dosexe.h"
36
#include "services.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
37
#include "server.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39
DEFAULT_DEBUG_CHANNEL(task)
40 41 42
DECLARE_DEBUG_CHANNEL(relay)
DECLARE_DEBUG_CHANNEL(toolhelp)

Alexandre Julliard's avatar
Alexandre Julliard committed
43 44
  /* Min. number of thunks allocated when creating a new segment */
#define MIN_THUNKS  32
Alexandre Julliard's avatar
Alexandre Julliard committed
45

Alexandre Julliard's avatar
Alexandre Julliard committed
46

Alexandre Julliard's avatar
Alexandre Julliard committed
47 48 49 50 51 52 53
static THHOOK DefaultThhook = { 0 };
THHOOK *pThhook = &DefaultThhook;

#define hCurrentTask (pThhook->CurTDB)
#define hFirstTask   (pThhook->HeadTDB)
#define hLockedTask  (pThhook->LockTDB)

Alexandre Julliard's avatar
Alexandre Julliard committed
54
static UINT16 nTaskCount = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
55

56
static HTASK initial_task;
Alexandre Julliard's avatar
Alexandre Julliard committed
57

Alexandre Julliard's avatar
Alexandre Julliard committed
58 59 60 61 62 63 64 65 66 67 68
/***********************************************************************
 *	     TASK_InstallTHHook
 */
void TASK_InstallTHHook( THHOOK *pNewThhook )
{
     THHOOK *pOldThhook = pThhook;

     pThhook = pNewThhook? pNewThhook : &DefaultThhook;

     *pThhook = *pOldThhook;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
69

Alexandre Julliard's avatar
Alexandre Julliard committed
70 71 72
/***********************************************************************
 *	     TASK_GetNextTask
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
73
HTASK16 TASK_GetNextTask( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
74
{
Alexandre Julliard's avatar
Alexandre Julliard committed
75
    TDB* pTask = (TDB*)GlobalLock16(hTask);
Alexandre Julliard's avatar
Alexandre Julliard committed
76 77 78 79 80

    if (pTask->hNext) return pTask->hNext;
    return (hFirstTask != hTask) ? hFirstTask : 0; 
}

Alexandre Julliard's avatar
Alexandre Julliard committed
81 82
/***********************************************************************
 *           TASK_LinkTask
Alexandre Julliard's avatar
Alexandre Julliard committed
83
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
84
static void TASK_LinkTask( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
85
{
Alexandre Julliard's avatar
Alexandre Julliard committed
86
    HTASK16 *prevTask;
Alexandre Julliard's avatar
Alexandre Julliard committed
87 88
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
89
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
90 91 92
    prevTask = &hFirstTask;
    while (*prevTask)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
93
        TDB *prevTaskPtr = (TDB *)GlobalLock16( *prevTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
94 95 96 97 98 99
        if (prevTaskPtr->priority >= pTask->priority) break;
        prevTask = &prevTaskPtr->hNext;
    }
    pTask->hNext = *prevTask;
    *prevTask = hTask;
    nTaskCount++;
Alexandre Julliard's avatar
Alexandre Julliard committed
100 101 102
}


Alexandre Julliard's avatar
Alexandre Julliard committed
103 104
/***********************************************************************
 *           TASK_UnlinkTask
Alexandre Julliard's avatar
Alexandre Julliard committed
105
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
106
static void TASK_UnlinkTask( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
107
{
Alexandre Julliard's avatar
Alexandre Julliard committed
108
    HTASK16 *prevTask;
Alexandre Julliard's avatar
Alexandre Julliard committed
109 110 111 112 113
    TDB *pTask;

    prevTask = &hFirstTask;
    while (*prevTask && (*prevTask != hTask))
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
114
        pTask = (TDB *)GlobalLock16( *prevTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
115 116 117 118
        prevTask = &pTask->hNext;
    }
    if (*prevTask)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
119
        pTask = (TDB *)GlobalLock16( *prevTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
120 121 122 123
        *prevTask = pTask->hNext;
        pTask->hNext = 0;
        nTaskCount--;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
124 125 126
}


Alexandre Julliard's avatar
Alexandre Julliard committed
127 128 129 130 131
/***********************************************************************
 *           TASK_CreateThunks
 *
 * Create a thunk free-list in segment 'handle', starting from offset 'offset'
 * and containing 'count' entries.
Alexandre Julliard's avatar
Alexandre Julliard committed
132
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
133
static void TASK_CreateThunks( HGLOBAL16 handle, WORD offset, WORD count )
Alexandre Julliard's avatar
Alexandre Julliard committed
134
{
Alexandre Julliard's avatar
Alexandre Julliard committed
135 136 137 138
    int i;
    WORD free;
    THUNKS *pThunk;

Alexandre Julliard's avatar
Alexandre Julliard committed
139
    pThunk = (THUNKS *)((BYTE *)GlobalLock16( handle ) + offset);
Alexandre Julliard's avatar
Alexandre Julliard committed
140 141 142 143 144 145 146 147 148 149
    pThunk->next = 0;
    pThunk->magic = THUNK_MAGIC;
    pThunk->free = (int)&pThunk->thunks - (int)pThunk;
    free = pThunk->free;
    for (i = 0; i < count-1; i++)
    {
        free += 8;  /* Offset of next thunk */
        pThunk->thunks[4*i] = free;
    }
    pThunk->thunks[4*i] = 0;  /* Last thunk */
Alexandre Julliard's avatar
Alexandre Julliard committed
150 151 152
}


Alexandre Julliard's avatar
Alexandre Julliard committed
153 154 155 156
/***********************************************************************
 *           TASK_AllocThunk
 *
 * Allocate a thunk for MakeProcInstance().
Alexandre Julliard's avatar
Alexandre Julliard committed
157
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
158
static SEGPTR TASK_AllocThunk( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
159
{
Alexandre Julliard's avatar
Alexandre Julliard committed
160 161 162 163
    TDB *pTask;
    THUNKS *pThunk;
    WORD sel, base;
    
Alexandre Julliard's avatar
Alexandre Julliard committed
164
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178
    sel = pTask->hCSAlias;
    pThunk = &pTask->thunks;
    base = (int)pThunk - (int)pTask;
    while (!pThunk->free)
    {
        sel = pThunk->next;
        if (!sel)  /* Allocate a new segment */
        {
            sel = GLOBAL_Alloc( GMEM_FIXED, sizeof(THUNKS) + (MIN_THUNKS-1)*8,
                                pTask->hPDB, TRUE, FALSE, FALSE );
            if (!sel) return (SEGPTR)0;
            TASK_CreateThunks( sel, 0, MIN_THUNKS );
            pThunk->next = sel;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
179
        pThunk = (THUNKS *)GlobalLock16( sel );
Alexandre Julliard's avatar
Alexandre Julliard committed
180 181 182 183
        base = 0;
    }
    base += pThunk->free;
    pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free);
Alexandre Julliard's avatar
Alexandre Julliard committed
184
    return PTR_SEG_OFF_TO_SEGPTR( sel, base );
Alexandre Julliard's avatar
Alexandre Julliard committed
185 186 187 188 189 190 191 192
}


/***********************************************************************
 *           TASK_FreeThunk
 *
 * Free a MakeProcInstance() thunk.
 */
193
static BOOL TASK_FreeThunk( HTASK16 hTask, SEGPTR thunk )
Alexandre Julliard's avatar
Alexandre Julliard committed
194 195 196 197 198
{
    TDB *pTask;
    THUNKS *pThunk;
    WORD sel, base;
    
Alexandre Julliard's avatar
Alexandre Julliard committed
199
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
200 201 202 203 204 205
    sel = pTask->hCSAlias;
    pThunk = &pTask->thunks;
    base = (int)pThunk - (int)pTask;
    while (sel && (sel != HIWORD(thunk)))
    {
        sel = pThunk->next;
Alexandre Julliard's avatar
Alexandre Julliard committed
206
        pThunk = (THUNKS *)GlobalLock16( sel );
Alexandre Julliard's avatar
Alexandre Julliard committed
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
        base = 0;
    }
    if (!sel) return FALSE;
    *(WORD *)((BYTE *)pThunk + LOWORD(thunk) - base) = pThunk->free;
    pThunk->free = LOWORD(thunk) - base;
    return TRUE;
}


/***********************************************************************
 *           TASK_CallToStart
 *
 * 32-bit entry point for a new task. This function is responsible for
 * setting up the registers and jumping to the 16-bit entry point.
 */
222
void TASK_CallToStart(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
223
{
Alexandre Julliard's avatar
Alexandre Julliard committed
224
    TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
Alexandre Julliard's avatar
Alexandre Julliard committed
225
    NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
Alexandre Julliard's avatar
Alexandre Julliard committed
226
    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
227
    CONTEXT86 context;
228

229 230 231 232 233
    SYSLEVEL_EnterWin16Lock();

    /* Add task to 16-bit scheduler pool if necessary */
    if ( hCurrentTask != GetCurrentTask() )
        TASK_Reschedule();
234 235 236 237 238 239 240 241 242 243 244 245 246

    /* Registers at initialization must be:
     * ax   zero
     * bx   stack size in bytes
     * cx   heap size in bytes
     * si   previous app instance
     * di   current app instance
     * bp   zero
     * es   selector to the PSP
     * ds   dgroup of the application
     * ss   stack selector
     * sp   top of the stack
     */
Alexandre Julliard's avatar
Alexandre Julliard committed
247

248 249
    memset( &context, 0, sizeof(context) );
    CS_reg(&context)  = GlobalHandleToSel16(pSegTable[pModule->cs - 1].hSeg);
250
    DS_reg(&context)  = GlobalHandleToSel16(pTask->hInstance);
251 252 253 254
    ES_reg(&context)  = pTask->hPDB;
    EIP_reg(&context) = pModule->ip;
    EBX_reg(&context) = pModule->stack_size;
    ECX_reg(&context) = pModule->heap_size;
255 256
    EDI_reg(&context) = pTask->hInstance;
    ESI_reg(&context) = pTask->hPrevInstance;
257

258 259 260 261
    TRACE("Starting main program: cs:ip=%04lx:%04lx ds=%04lx ss:sp=%04x:%04x\n",
          CS_reg(&context), EIP_reg(&context), DS_reg(&context),
          SELECTOROF(pTask->teb->cur_stack),
          OFFSETOF(pTask->teb->cur_stack) );
262 263

    Callbacks->CallRegisterShortProc( &context, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
264 265 266 267
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
268
 *           TASK_Create
Alexandre Julliard's avatar
Alexandre Julliard committed
269
 *
270 271 272 273
 * NOTE: This routine might be called by a Win32 thread. Thus, we need
 *       to be careful to protect global data structures. We do this
 *       by entering the Win16Lock while linking the task into the
 *       global task list.
Alexandre Julliard's avatar
Alexandre Julliard committed
274
 */
275
BOOL TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline, BYTE len )
Alexandre Julliard's avatar
Alexandre Julliard committed
276
{
Alexandre Julliard's avatar
Alexandre Julliard committed
277
    HTASK16 hTask;
278
    TDB *pTask;
Alexandre Julliard's avatar
Alexandre Julliard committed
279
    char name[10];
280
    PDB *pdb32 = PROCESS_Current();
Alexandre Julliard's avatar
Alexandre Julliard committed
281 282 283 284

      /* Allocate the task structure */

    hTask = GLOBAL_Alloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB),
Alexandre Julliard's avatar
Alexandre Julliard committed
285
                          pModule->self, FALSE, FALSE, FALSE );
286
    if (!hTask) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
287
    pTask = (TDB *)GlobalLock16( hTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
288

Alexandre Julliard's avatar
Alexandre Julliard committed
289
    /* Fill the task structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
290

291
    pTask->nEvents       = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
292 293
    pTask->hSelf         = hTask;
    pTask->flags         = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
294

295 296
    if (teb->tibflags & TEBF_WIN32) pTask->flags |= TDBF_WIN32;
    if (pModule->lpDosTask) pTask->flags |= TDBF_WINOLDAP;
Alexandre Julliard's avatar
Alexandre Julliard committed
297

298 299 300 301 302
    pTask->hInstance     = pModule->self;
    pTask->hPrevInstance = 0;
    /* NOTE: for 16-bit tasks, the instance handles are updated later on
             in NE_InitProcess */

Alexandre Julliard's avatar
Alexandre Julliard committed
303
    pTask->version       = pModule->expected_version;
Alexandre Julliard's avatar
Alexandre Julliard committed
304
    pTask->hModule       = pModule->self;
Alexandre Julliard's avatar
Alexandre Julliard committed
305
    pTask->hParent       = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
306 307
    pTask->magic         = TDB_MAGIC;
    pTask->nCmdShow      = cmdShow;
308
    pTask->teb           = teb;
Alexandre Julliard's avatar
Alexandre Julliard committed
309 310
    pTask->curdrive      = DRIVE_GetCurrentDrive() | 0x80;
    strcpy( pTask->curdir, "\\" );
311
    lstrcpynA( pTask->curdir + 1, DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() ),
Alexandre Julliard's avatar
Alexandre Julliard committed
312
                 sizeof(pTask->curdir) - 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
313 314 315 316 317 318 319

      /* Create the thunks block */

    TASK_CreateThunks( hTask, (int)&pTask->thunks - (int)pTask, 7 );

      /* Copy the module name */

320
    GetModuleName16( pModule->self, name, sizeof(name) );
Alexandre Julliard's avatar
Alexandre Julliard committed
321 322
    strncpy( pTask->module_name, name, sizeof(pTask->module_name) );

Alexandre Julliard's avatar
Alexandre Julliard committed
323 324
      /* Allocate a selector for the PDB */

325
    pTask->hPDB = GLOBAL_CreateBlock( GMEM_FIXED, &pTask->pdb, sizeof(PDB16),
Alexandre Julliard's avatar
Alexandre Julliard committed
326
                                    pModule->self, FALSE, FALSE, FALSE, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
327

Alexandre Julliard's avatar
Alexandre Julliard committed
328 329 330
      /* Fill the PDB */

    pTask->pdb.int20 = 0x20cd;
Alexandre Julliard's avatar
Alexandre Julliard committed
331
    pTask->pdb.dispatcher[0] = 0x9a;  /* ljmp */
Alexandre Julliard's avatar
Alexandre Julliard committed
332
    PUT_DWORD(&pTask->pdb.dispatcher[1], (DWORD)NE_GetEntryPoint(
Alexandre Julliard's avatar
Alexandre Julliard committed
333
           GetModuleHandle16("KERNEL"), 102 ));  /* KERNEL.102 is DOS3Call() */
Alexandre Julliard's avatar
Alexandre Julliard committed
334 335 336
    pTask->pdb.savedint22 = INT_GetPMHandler( 0x22 );
    pTask->pdb.savedint23 = INT_GetPMHandler( 0x23 );
    pTask->pdb.savedint24 = INT_GetPMHandler( 0x24 );
Alexandre Julliard's avatar
Alexandre Julliard committed
337
    pTask->pdb.fileHandlesPtr =
338 339
        PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel16(pTask->hPDB),
                               (int)&((PDB16 *)0)->fileHandles );
Alexandre Julliard's avatar
Alexandre Julliard committed
340
    pTask->pdb.hFileHandles = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
341
    memset( pTask->pdb.fileHandles, 0xff, sizeof(pTask->pdb.fileHandles) );
Alexandre Julliard's avatar
Alexandre Julliard committed
342
    pTask->pdb.environment    = pdb32->env_db->env_sel;
Alexandre Julliard's avatar
Alexandre Julliard committed
343
    pTask->pdb.nbFiles        = 20;
Alexandre Julliard's avatar
Alexandre Julliard committed
344 345 346

    /* Fill the command line */

347 348 349 350 351 352 353 354 355 356 357
    if (!cmdline)
    {
        cmdline = pdb32->env_db->cmd_line;
        while (*cmdline && (*cmdline != ' ') && (*cmdline != '\t')) cmdline++;
        while ((*cmdline == ' ') || (*cmdline == '\t')) cmdline++;
        len = strlen(cmdline);
    }
    if (len >= sizeof(pTask->pdb.cmdLine)) len = sizeof(pTask->pdb.cmdLine)-1;
    pTask->pdb.cmdLine[0] = len;
    memcpy( pTask->pdb.cmdLine + 1, cmdline, len );
    /* pTask->pdb.cmdLine[len+1] = 0; */
Alexandre Julliard's avatar
Alexandre Julliard committed
358 359 360

      /* Get the compatibility flags */

361
    pTask->compat_flags = GetProfileIntA( "Compatibility", name, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
362 363 364 365 366

      /* Allocate a code segment alias for the TDB */

    pTask->hCSAlias = GLOBAL_CreateBlock( GMEM_FIXED, (void *)pTask,
                                          sizeof(TDB), pTask->hPDB, TRUE,
Alexandre Julliard's avatar
Alexandre Julliard committed
367
                                          FALSE, FALSE, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
368 369 370

      /* Set the owner of the environment block */

371
    FarSetOwner16( pTask->pdb.environment, pTask->hPDB );
Alexandre Julliard's avatar
Alexandre Julliard committed
372 373 374

      /* Default DTA overwrites command-line */

Alexandre Julliard's avatar
Alexandre Julliard committed
375 376
    pTask->dta = PTR_SEG_OFF_TO_SEGPTR( pTask->hPDB, 
                                (int)&pTask->pdb.cmdLine - (int)&pTask->pdb );
Alexandre Julliard's avatar
Alexandre Julliard committed
377

378 379 380 381 382 383 384 385
    /* Create scheduler event for 16-bit tasks */

    if ( !(pTask->flags & TDBF_WIN32) )
    {
        pTask->hEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
        pTask->hEvent = ConvertToGlobalHandle( pTask->hEvent );
    }

386 387
    /* Enter task handle into thread and process */
 
388
    teb->htask16 = hTask;
389 390
    if (!initial_task) initial_task = hTask;

391
    TRACE("module='%s' cmdline='%.*s' task=%04x\n", name, *cmdline, cmdline+1, hTask );
392

Alexandre Julliard's avatar
Alexandre Julliard committed
393 394 395 396 397 398
    /* Add the task to the linked list */

    SYSLEVEL_EnterWin16Lock();
    TASK_LinkTask( hTask );
    SYSLEVEL_LeaveWin16Lock();

399
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
400 401
}

Alexandre Julliard's avatar
Alexandre Julliard committed
402 403 404
/***********************************************************************
 *           TASK_DeleteTask
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
405
static void TASK_DeleteTask( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
406 407
{
    TDB *pTask;
Alexandre Julliard's avatar
Alexandre Julliard committed
408
    HGLOBAL16 hPDB;
Alexandre Julliard's avatar
Alexandre Julliard committed
409

Alexandre Julliard's avatar
Alexandre Julliard committed
410
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
411
    hPDB = pTask->hPDB;
Alexandre Julliard's avatar
Alexandre Julliard committed
412

Alexandre Julliard's avatar
Alexandre Julliard committed
413 414
    pTask->magic = 0xdead; /* invalidate signature */

Alexandre Julliard's avatar
Alexandre Julliard committed
415
    /* Free the selector aliases */
Alexandre Julliard's avatar
Alexandre Julliard committed
416 417 418 419

    GLOBAL_FreeBlock( pTask->hCSAlias );
    GLOBAL_FreeBlock( pTask->hPDB );

420 421 422 423
    /* Free the task module */

    FreeModule16( pTask->hModule );

Alexandre Julliard's avatar
Alexandre Julliard committed
424
    /* Free the task structure itself */
Alexandre Julliard's avatar
Alexandre Julliard committed
425

Alexandre Julliard's avatar
Alexandre Julliard committed
426
    GlobalFree16( hTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
427 428 429 430

    /* Free all memory used by this task (including the 32-bit stack, */
    /* the environment block and the thunk segments). */

431
    GlobalFreeAll16( hPDB );
Alexandre Julliard's avatar
Alexandre Julliard committed
432 433 434
}

/***********************************************************************
435
 *           TASK_KillTask
Alexandre Julliard's avatar
Alexandre Julliard committed
436
 */
437
void TASK_KillTask( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
438
{
439
    TDB *pTask; 
Alexandre Julliard's avatar
Alexandre Julliard committed
440

441 442 443 444 445 446
    /* Enter the Win16Lock to protect global data structures */
    SYSLEVEL_EnterWin16Lock();

    if ( !hTask ) hTask = GetCurrentTask();
    pTask = (TDB *)GlobalLock16( hTask );
    if ( !pTask ) 
Alexandre Julliard's avatar
Alexandre Julliard committed
447
    {
448
        SYSLEVEL_LeaveWin16Lock();
Alexandre Julliard's avatar
Alexandre Julliard committed
449 450 451
        return;
    }

452
    TRACE("Killing task %04x\n", hTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
453

Alexandre Julliard's avatar
Alexandre Julliard committed
454
#ifdef MZ_SUPPORTED
455
{
Alexandre Julliard's avatar
Alexandre Julliard committed
456
    /* Kill DOS VM task */
457
    NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
Alexandre Julliard's avatar
Alexandre Julliard committed
458 459
    if ( pModule->lpDosTask )
        MZ_KillModule( pModule->lpDosTask );
460
}
Alexandre Julliard's avatar
Alexandre Julliard committed
461 462
#endif

Alexandre Julliard's avatar
Alexandre Julliard committed
463 464
    /* Perform USER cleanup */

465
    TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
466 467 468
    PROCESS_CallUserSignalProc( USIG_PROCESS_EXIT, 0 );
    PROCESS_CallUserSignalProc( USIG_THREAD_EXIT, 0 );
    PROCESS_CallUserSignalProc( USIG_PROCESS_DESTROY, 0 );
469

470
    if (nTaskCount <= 1)
Alexandre Julliard's avatar
Alexandre Julliard committed
471
    {
472
        TRACE("this is the last task, exiting\n" );
473
        ExitKernel16();
Alexandre Julliard's avatar
Alexandre Julliard committed
474 475
    }

476 477 478 479 480 481
    /* FIXME: Hack! Send a message to the initial task so that
     * the GetMessage wakes up and the initial task can check whether
     * it is the only remaining one and terminate itself ...
     * The initial task should probably install hooks or something
     * to get informed about task termination :-/
     */
482
    Callout.PostAppMessage16( initial_task, WM_NULL, 0, 0 );
483

Alexandre Julliard's avatar
Alexandre Julliard committed
484
    /* Remove the task from the list to be sure we never switch back to it */
485
    TASK_UnlinkTask( hTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
486 487 488 489 490
    if( nTaskCount )
    {
        TDB* p = (TDB *)GlobalLock16( hFirstTask );
        while( p )
        {
491
            if( p->hYieldTo == hTask ) p->hYieldTo = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
492 493 494 495 496
            p = (TDB *)GlobalLock16( p->hNext );
        }
    }

    pTask->nEvents = 0;
497 498 499 500

    if ( hLockedTask == hTask )
        hLockedTask = 0;

501
    TASK_DeleteTask( hTask );
502

503
    /* When deleting the current task ... */
504 505
    if ( hTask == hCurrentTask )
    {
506
        DWORD lockCount;
507

508 509 510 511 512
        /* ... schedule another one ... */
        TASK_Reschedule();

        /* ... and completely release the Win16Lock, just in case. */
        ReleaseThunkLock( &lockCount );
513 514 515 516

        return;
    }

517
    SYSLEVEL_LeaveWin16Lock();
Alexandre Julliard's avatar
Alexandre Julliard committed
518 519 520 521 522 523 524
}

/***********************************************************************
 *           TASK_Reschedule
 *
 * This is where all the magic of task-switching happens!
 *
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
 * 16-bit Windows performs non-preemptive (cooperative) multitasking.
 * This means that each 16-bit task runs until it voluntarily yields 
 * control, at which point the scheduler gets active and selects the
 * next task to run.
 *
 * In Wine, all processes, even 16-bit ones, are scheduled preemptively
 * by the standard scheduler of the underlying OS.  As many 16-bit apps
 * *rely* on the behaviour of the Windows scheduler, however, we have
 * to simulate that behaviour.
 *
 * This is achieved as follows: every 16-bit task is at time (except
 * during task creation and deletion) in one of two states: either it
 * is the one currently running, then the global variable hCurrentTask
 * contains its task handle, or it is not currently running, then it
 * is blocked on a special scheduler event, a global handle to which
 * is stored in the task struct.
 *
 * When the current task yields control, this routine gets called. Its
 * purpose is to determine the next task to be active, signal the 
 * scheduler event of that task, and then put the current task to sleep
 * waiting for *its* scheduler event to get signalled again.
 *
 * This routine can get called in a few other special situations as well:
 *
 * - On creation of a 16-bit task, the Unix process executing the task
 *   calls TASK_Reschedule once it has completed its initialization.
 *   At this point, the task needs to be blocked until its scheduler
 *   event is signalled the first time (this will be done by the parent
 *   process to get the task up and running).
 *
 * - When the task currently running terminates itself, this routine gets
 *   called and has to schedule another task, *without* blocking the 
 *   terminating task.
 *
 * - When a 32-bit thread posts an event for a 16-bit task, it might be
 *   the case that *no* 16-bit task is currently running.  In this case
 *   the task that has now an event pending is to be scheduled.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
563
 */
564
void TASK_Reschedule(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
565
{
566 567 568 569
    TDB *pOldTask = NULL, *pNewTask = NULL;
    HTASK16 hOldTask = 0, hNewTask = 0;
    enum { MODE_YIELD, MODE_SLEEP, MODE_WAKEUP } mode;
    DWORD lockCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
570

571
    SYSLEVEL_EnterWin16Lock();
572

573 574 575
    /* Check what we need to do */
    hOldTask = GetCurrentTask();
    pOldTask = (TDB *)GlobalLock16( hOldTask );
576 577
    TRACE( "entered with hCurrentTask %04x by hTask %04x (pid %ld)\n", 
           hCurrentTask, hOldTask, (long) getpid() );
578

579
    if ( pOldTask && THREAD_IsWin16( NtCurrentTeb() ) )
580 581
    {
        /* We are called by an active (non-deleted) 16-bit task */
582

583 584 585 586
        /* If we don't even have a current task, or else the current
           task has yielded, we'll need to schedule a new task and
           (possibly) put the calling task to sleep.  Otherwise, we
           only block the caller. */
Alexandre Julliard's avatar
Alexandre Julliard committed
587

588 589 590 591 592 593 594 595
        if ( !hCurrentTask || hCurrentTask == hOldTask )
            mode = MODE_YIELD;
        else
            mode = MODE_SLEEP;
    }
    else
    {
        /* We are called by a deleted 16-bit task or a 32-bit thread */
Alexandre Julliard's avatar
Alexandre Julliard committed
596

597 598 599
        /* The only situation where we need to do something is if we
           now do not have a current task.  Then, we'll need to wake up
           some task that has events pending. */
Alexandre Julliard's avatar
Alexandre Julliard committed
600

601 602 603 604 605 606 607 608
        if ( !hCurrentTask || hCurrentTask == hOldTask )
            mode = MODE_WAKEUP;
        else
        {
            /* nothing to do */
            SYSLEVEL_LeaveWin16Lock();
            return;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
609
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
610

611 612
    /* Find a task to yield to: check for DirectedYield() */
    if ( mode == MODE_YIELD && pOldTask && pOldTask->hYieldTo )
Alexandre Julliard's avatar
Alexandre Julliard committed
613
    {
614 615 616
        hNewTask = pOldTask->hYieldTo;
        pNewTask = (TDB *)GlobalLock16( hNewTask );
        if( !pNewTask || !pNewTask->nEvents) hNewTask = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
617
        pOldTask->hYieldTo = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
618 619
    }

620 621
    /* Find a task to yield to: check for pending events */
    if ( (mode == MODE_YIELD || mode == MODE_WAKEUP) && !hNewTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
622
    {
623 624
        hNewTask = hFirstTask;
        while (hNewTask)
Alexandre Julliard's avatar
Alexandre Julliard committed
625
        {
626
            pNewTask = (TDB *)GlobalLock16( hNewTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
627

628
            TRACE( "\ttask = %04x, events = %i\n", hNewTask, pNewTask->nEvents );
Alexandre Julliard's avatar
Alexandre Julliard committed
629

Alexandre Julliard's avatar
Alexandre Julliard committed
630
            if (pNewTask->nEvents) break;
631
            hNewTask = pNewTask->hNext;
Alexandre Julliard's avatar
Alexandre Julliard committed
632
        }
633
        if (hLockedTask && (hNewTask != hLockedTask)) hNewTask = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
634
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
635

636
    /* If we are still the task with highest priority, just return ... */
637
    if ( mode == MODE_YIELD && hNewTask && hNewTask == hCurrentTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
638
    {
639
        TRACE("returning to the current task (%04x)\n", hCurrentTask );
640 641
        SYSLEVEL_LeaveWin16Lock();

642 643
        /* Allow Win32 threads to thunk down even while a Win16 task is
           in a tight PeekMessage() or Yield() loop ... */
644 645 646
        ReleaseThunkLock( &lockCount );
        RestoreThunkLock( lockCount );
        return;
Alexandre Julliard's avatar
Alexandre Julliard committed
647
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
648

649 650
    /* If no task to yield to found, suspend 16-bit scheduler ... */
    if ( mode == MODE_YIELD && !hNewTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
651
    {
652
        TRACE("No currently active task\n");
653
        hCurrentTask = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
654
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
655

656 657 658
    /* If we found a task to wake up, do it ... */
    if ( (mode == MODE_YIELD || mode == MODE_WAKEUP) && hNewTask )
    {
659
        TRACE("Switching to task %04x (%.8s)\n",
660
                      hNewTask, pNewTask->module_name );
Alexandre Julliard's avatar
Alexandre Julliard committed
661

662 663 664 665
        pNewTask->priority++;
        TASK_UnlinkTask( hNewTask );
        TASK_LinkTask( hNewTask );
        pNewTask->priority--;
Alexandre Julliard's avatar
Alexandre Julliard committed
666

667 668
        hCurrentTask = hNewTask;
        SetEvent( pNewTask->hEvent );
Alexandre Julliard's avatar
Alexandre Julliard committed
669

670
        /* This is set just in case some app reads it ... */
671
        pNewTask->ss_sp = pNewTask->teb->cur_stack;
672
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
673

674 675
    /* If we need to put the current task to sleep, do it ... */
    if ( (mode == MODE_YIELD || mode == MODE_SLEEP) && hOldTask != hCurrentTask )
676
    {
677
        ResetEvent( pOldTask->hEvent );
Alexandre Julliard's avatar
Alexandre Julliard committed
678

679 680 681 682 683
        ReleaseThunkLock( &lockCount );
        SYSLEVEL_CheckNotLevel( 1 );
        WaitForSingleObject( pOldTask->hEvent, INFINITE );
        RestoreThunkLock( lockCount );
    }
684

685
    SYSLEVEL_LeaveWin16Lock();
Alexandre Julliard's avatar
Alexandre Julliard committed
686 687 688 689
}

/***********************************************************************
 *           InitTask  (KERNEL.91)
Alexandre Julliard's avatar
Alexandre Julliard committed
690 691
 *
 * Called by the application startup code.
Alexandre Julliard's avatar
Alexandre Julliard committed
692
 */
693
void WINAPI InitTask16( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
694 695
{
    TDB *pTask;
Alexandre Julliard's avatar
Alexandre Julliard committed
696
    INSTANCEDATA *pinstance;
697
    SEGPTR ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
698

699
    EAX_reg(context) = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
700
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
701 702 703 704 705 706 707

    /* Note: we need to trust that BX/CX contain the stack/heap sizes, 
       as some apps, notably Visual Basic apps, *modify* the heap/stack
       size of the instance data segment before calling InitTask() */

    /* Initialize the INSTANCEDATA structure */
    pinstance = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN(CURRENT_DS, 0);
708
    pinstance->stackmin    = OFFSETOF( pTask->teb->cur_stack ) + sizeof( STACK16FRAME );
709 710 711 712 713 714
    pinstance->stackbottom = pinstance->stackmin; /* yup, that's right. Confused me too. */
    pinstance->stacktop    = ( pinstance->stackmin > BX_reg(context)? 
                               pinstance->stackmin - BX_reg(context) : 0 ) + 150; 

    /* Initialize the local heap */
    if ( CX_reg(context) )
715
        LocalInit16( GlobalHandleToSel16(pTask->hInstance), 0, CX_reg(context) );
Alexandre Julliard's avatar
Alexandre Julliard committed
716

Alexandre Julliard's avatar
Alexandre Julliard committed
717
    /* Initialize implicitly loaded DLLs */
Alexandre Julliard's avatar
Alexandre Julliard committed
718
    NE_InitializeDLLs( pTask->hModule );
719
    NE_DllProcessAttach( pTask->hModule );
Alexandre Julliard's avatar
Alexandre Julliard committed
720

721 722 723 724 725 726 727 728 729 730
    /* Registers on return are:
     * ax     1 if OK, 0 on error
     * cx     stack limit in bytes
     * dx     cmdShow parameter
     * si     instance handle of the previous instance
     * di     instance handle of the new task
     * es:bx  pointer to command-line inside PSP
     *
     * 0 (=%bp) is pushed on the stack
     */
731
    ptr = stack16_push( sizeof(WORD) );
732
    *(WORD *)PTR_SEG_TO_LIN(ptr) = 0;
733
    ESP_reg(context) -= 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
734

735 736 737 738
    EAX_reg(context) = 1;
        
    if (!pTask->pdb.cmdLine[0]) EBX_reg(context) = 0x80;
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
739
    {
740 741 742 743 744 745 746 747 748
        LPBYTE p = &pTask->pdb.cmdLine[1];
        while ((*p == ' ') || (*p == '\t')) p++;
        EBX_reg(context) = 0x80 + (p - pTask->pdb.cmdLine);
    }
    ECX_reg(context) = pinstance->stacktop;
    EDX_reg(context) = pTask->nCmdShow;
    ESI_reg(context) = (DWORD)pTask->hPrevInstance;
    EDI_reg(context) = (DWORD)pTask->hInstance;
    ES_reg (context) = (WORD)pTask->hPDB;
Alexandre Julliard's avatar
Alexandre Julliard committed
749 750 751 752 753
}


/***********************************************************************
 *           WaitEvent  (KERNEL.30)
Alexandre Julliard's avatar
Alexandre Julliard committed
754
 */
755
BOOL16 WINAPI WaitEvent16( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
756
{
Alexandre Julliard's avatar
Alexandre Julliard committed
757 758
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
759
    if (!hTask) hTask = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
760
    pTask = (TDB *)GlobalLock16( hTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
761

762
    if ( !THREAD_IsWin16( NtCurrentTeb() ) )
Alexandre Julliard's avatar
Alexandre Julliard committed
763
    {
764
        FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
Alexandre Julliard's avatar
Alexandre Julliard committed
765 766 767
        return TRUE;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
768 769 770 771 772
    if (pTask->nEvents > 0)
    {
        pTask->nEvents--;
        return FALSE;
    }
773
    TASK_Reschedule();
Alexandre Julliard's avatar
Alexandre Julliard committed
774

Alexandre Julliard's avatar
Alexandre Julliard committed
775
    /* When we get back here, we have an event */
Alexandre Julliard's avatar
Alexandre Julliard committed
776

Alexandre Julliard's avatar
Alexandre Julliard committed
777
    if (pTask->nEvents > 0) pTask->nEvents--;
Alexandre Julliard's avatar
Alexandre Julliard committed
778 779 780 781 782 783 784
    return TRUE;
}


/***********************************************************************
 *           PostEvent  (KERNEL.31)
 */
785
void WINAPI PostEvent16( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
786 787 788
{
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
789
    if (!hTask) hTask = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
790
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
791

792
    if ( !THREAD_IsWin16( pTask->teb ) )
793
    {
794
        FIXME("called for Win32 thread (%04x)!\n", pTask->teb->teb_sel );
795 796 797
        return;
    }

798
    pTask->nEvents++;
799 800

    /* If we are a 32-bit task, we might need to wake up the 16-bit scheduler */
801
    if ( !THREAD_IsWin16( NtCurrentTeb() ) )
802
        TASK_Reschedule();
Alexandre Julliard's avatar
Alexandre Julliard committed
803 804 805 806 807 808
}


/***********************************************************************
 *           SetPriority  (KERNEL.32)
 */
809
void WINAPI SetPriority16( HTASK16 hTask, INT16 delta )
Alexandre Julliard's avatar
Alexandre Julliard committed
810 811
{
    TDB *pTask;
Alexandre Julliard's avatar
Alexandre Julliard committed
812
    INT16 newpriority;
Alexandre Julliard's avatar
Alexandre Julliard committed
813

Alexandre Julliard's avatar
Alexandre Julliard committed
814
    if (!hTask) hTask = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
815
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
816 817 818 819 820 821 822 823 824 825 826
    newpriority = pTask->priority + delta;
    if (newpriority < -32) newpriority = -32;
    else if (newpriority > 15) newpriority = 15;

    pTask->priority = newpriority + 1;
    TASK_UnlinkTask( hTask );
    TASK_LinkTask( hTask );
    pTask->priority--;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
827 828 829
/***********************************************************************
 *           LockCurrentTask  (KERNEL.33)
 */
830
HTASK16 WINAPI LockCurrentTask16( BOOL16 bLock )
Alexandre Julliard's avatar
Alexandre Julliard committed
831
{
Alexandre Julliard's avatar
Alexandre Julliard committed
832
    if (bLock) hLockedTask = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
833 834 835 836 837 838 839 840
    else hLockedTask = 0;
    return hLockedTask;
}


/***********************************************************************
 *           IsTaskLocked  (KERNEL.122)
 */
841
HTASK16 WINAPI IsTaskLocked16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
842 843 844 845 846
{
    return hLockedTask;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
847 848 849
/***********************************************************************
 *           OldYield  (KERNEL.117)
 */
850
void WINAPI OldYield16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
851
{
Alexandre Julliard's avatar
Alexandre Julliard committed
852 853
    TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );

854
    if ( !THREAD_IsWin16( NtCurrentTeb() ) )
Alexandre Julliard's avatar
Alexandre Julliard committed
855
    {
856
        FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
Alexandre Julliard's avatar
Alexandre Julliard committed
857 858
        return;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
859 860

    if (pCurTask) pCurTask->nEvents++;  /* Make sure we get back here */
861
    TASK_Reschedule();
Alexandre Julliard's avatar
Alexandre Julliard committed
862 863 864
    if (pCurTask) pCurTask->nEvents--;
}

865 866 867 868 869 870 871 872 873 874
/***********************************************************************
 *           WIN32_OldYield16  (KERNEL.447)
 */
void WINAPI WIN32_OldYield16(void)
{
   DWORD count;

   ReleaseThunkLock(&count);
   RestoreThunkLock(count);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
875 876 877 878

/***********************************************************************
 *           DirectedYield  (KERNEL.150)
 */
879
void WINAPI DirectedYield16( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
880
{
Alexandre Julliard's avatar
Alexandre Julliard committed
881 882
    TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );

883
    if ( !THREAD_IsWin16( NtCurrentTeb() ) )
Alexandre Julliard's avatar
Alexandre Julliard committed
884
    {
885
        FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
Alexandre Julliard's avatar
Alexandre Julliard committed
886 887 888
        return;
    }

889
    TRACE("%04x: DirectedYield(%04x)\n", pCurTask->hSelf, hTask );
Alex Korobka's avatar
Alex Korobka committed
890

Alexandre Julliard's avatar
Alexandre Julliard committed
891
    pCurTask->hYieldTo = hTask;
892
    OldYield16();
Alex Korobka's avatar
Alex Korobka committed
893

894
    TRACE("%04x: back from DirectedYield(%04x)\n", pCurTask->hSelf, hTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
895 896
}

Alexandre Julliard's avatar
Alexandre Julliard committed
897
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
898
 *           Yield16  (KERNEL.29)
Alexandre Julliard's avatar
Alexandre Julliard committed
899
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
900
void WINAPI Yield16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
901
{
Alexandre Julliard's avatar
Alexandre Julliard committed
902 903
    TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );

Alexandre Julliard's avatar
Alexandre Julliard committed
904
    if (pCurTask) pCurTask->hYieldTo = 0;
905 906
    if (pCurTask && pCurTask->hQueue) Callout.UserYield16();
    else OldYield16();
Alexandre Julliard's avatar
Alexandre Julliard committed
907 908
}

909 910 911 912 913 914 915
/***********************************************************************
 *           KERNEL_490  (KERNEL.490)
 */
HTASK16 WINAPI KERNEL_490( HTASK16 someTask )
{
    if ( !someTask ) return 0;

916
    FIXME("(%04x): stub\n", someTask );
917 918
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
919 920

/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
921
 *           MakeProcInstance16  (KERNEL.51)
Alexandre Julliard's avatar
Alexandre Julliard committed
922
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
923
FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance )
Alexandre Julliard's avatar
Alexandre Julliard committed
924
{
Alexandre Julliard's avatar
Alexandre Julliard committed
925
    BYTE *thunk,*lfunc;
Alexandre Julliard's avatar
Alexandre Julliard committed
926
    SEGPTR thunkaddr;
927 928 929
    WORD hInstanceSelector;

    hInstanceSelector = GlobalHandleToSel16(hInstance);
Alexandre Julliard's avatar
Alexandre Julliard committed
930

931
    TRACE("(%08lx, %04x);\n", (DWORD)func, hInstance);
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947

    if (!HIWORD(func)) {
      /* Win95 actually protects via SEH, but this is better for debugging */
      ERR("Ouch ! Called with invalid func 0x%08lx !\n", (DWORD)func);
      return (FARPROC16)0;
    }

    if (hInstance)
    {
	if ( (!(hInstance & 4)) ||
	     ((hInstance != 0xffff) && IS_SELECTOR_FREE(hInstance|7)) )
 	{
	    ERR("Invalid hInstance (%04x) passed to MakeProcInstance !\n",
		hInstance);
	    return 0;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
948
    }
949

950
    if ( (CURRENT_DS != hInstanceSelector)
951 952
      && (hInstance != 0)
      && (hInstance != 0xffff) )
Uwe Bonnes's avatar
Uwe Bonnes committed
953
    {
954
	/* calling MPI with a foreign DSEG is invalid ! */
955
        ERR("Problem with hInstance? Got %04x, using %04x instead\n",
956
                   hInstance,CURRENT_DS);
Uwe Bonnes's avatar
Uwe Bonnes committed
957
    }
958 959 960 961 962

    /* Always use the DSEG that MPI was entered with.
     * We used to set hInstance to GetTaskDS16(), but this should be wrong
     * as CURRENT_DS provides the DSEG value we need.
     * ("calling" DS, *not* "task" DS !) */
963 964
    hInstanceSelector = CURRENT_DS;
    hInstance = GlobalHandle16(hInstanceSelector);
965 966 967 968 969

    /* no thunking for DLLs */
    if (NE_GetPtr(FarGetOwner16(hInstance))->flags & NE_FFLAGS_LIBMODULE)
	return func;

Alexandre Julliard's avatar
Alexandre Julliard committed
970
    thunkaddr = TASK_AllocThunk( GetCurrentTask() );
Alexandre Julliard's avatar
Alexandre Julliard committed
971
    if (!thunkaddr) return (FARPROC16)0;
Alexandre Julliard's avatar
Alexandre Julliard committed
972
    thunk = PTR_SEG_TO_LIN( thunkaddr );
Alexandre Julliard's avatar
Alexandre Julliard committed
973
    lfunc = PTR_SEG_TO_LIN( func );
Alexandre Julliard's avatar
Alexandre Julliard committed
974

975 976
    TRACE("(%08lx,%04x): got thunk %08lx\n",
          (DWORD)func, hInstance, (DWORD)thunkaddr );
977 978
    if (((lfunc[0]==0x8c) && (lfunc[1]==0xd8)) || /* movw %ds, %ax */
    	((lfunc[0]==0x1e) && (lfunc[1]==0x58))    /* pushw %ds, popw %ax */
Alexandre Julliard's avatar
Alexandre Julliard committed
979
    ) {
980
    	FIXME("This was the (in)famous \"thunk useless\" warning. We thought we have to overwrite with nop;nop;, but this isn't true.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
981
    }
982

Alexandre Julliard's avatar
Alexandre Julliard committed
983
    *thunk++ = 0xb8;    /* movw instance, %ax */
984 985
    *thunk++ = (BYTE)(hInstanceSelector & 0xff);
    *thunk++ = (BYTE)(hInstanceSelector >> 8);
Alexandre Julliard's avatar
Alexandre Julliard committed
986 987
    *thunk++ = 0xea;    /* ljmp func */
    *(DWORD *)thunk = (DWORD)func;
Alexandre Julliard's avatar
Alexandre Julliard committed
988
    return (FARPROC16)thunkaddr;
989
    /* CX reg indicates if thunkaddr != NULL, implement if needed */
Alexandre Julliard's avatar
Alexandre Julliard committed
990 991 992 993
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
994
 *           FreeProcInstance16  (KERNEL.52)
Alexandre Julliard's avatar
Alexandre Julliard committed
995
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
996
void WINAPI FreeProcInstance16( FARPROC16 func )
Alexandre Julliard's avatar
Alexandre Julliard committed
997
{
998
    TRACE("(%08lx)\n", (DWORD)func );
Alexandre Julliard's avatar
Alexandre Julliard committed
999
    TASK_FreeThunk( GetCurrentTask(), (SEGPTR)func );
Alexandre Julliard's avatar
Alexandre Julliard committed
1000 1001
}

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
/**********************************************************************
 *	    TASK_GetCodeSegment
 * 
 * Helper function for GetCodeHandle/GetCodeInfo: Retrieve the module 
 * and logical segment number of a given code segment.
 *
 * 'proc' either *is* already a pair of module handle and segment number,
 * in which case there's nothing to do.  Otherwise, it is a pointer to
 * a function, and we need to retrieve the code segment.  If the pointer
 * happens to point to a thunk, we'll retrieve info about the code segment
 * where the function pointed to by the thunk resides, not the thunk itself.
 *
 * FIXME: if 'proc' is a SNOOP16 return stub, we should retrieve info about
 *        the function the snoop code will return to ...
 *
 */
static BOOL TASK_GetCodeSegment( FARPROC16 proc, NE_MODULE **ppModule, 
                                 SEGTABLEENTRY **ppSeg, int *pSegNr )
{
    NE_MODULE *pModule = NULL;
    SEGTABLEENTRY *pSeg = NULL;
    int segNr;

    /* Try pair of module handle / segment number */
    pModule = (NE_MODULE *) GlobalLock16( HIWORD( proc ) );
    if ( pModule && pModule->magic == IMAGE_OS2_SIGNATURE )
    {
        segNr = LOWORD( proc );
        if ( segNr && segNr <= pModule->seg_count )
            pSeg = NE_SEG_TABLE( pModule ) + segNr-1;
    }

    /* Try thunk or function */
    else 
    {
        BYTE *thunk = (BYTE *)PTR_SEG_TO_LIN( proc );
        WORD selector;

        if ((thunk[0] == 0xb8) && (thunk[3] == 0xea))
            selector = thunk[6] + (thunk[7] << 8);
        else
            selector = HIWORD( proc );

        pModule = NE_GetPtr( GlobalHandle16( selector ) );
        pSeg = pModule? NE_SEG_TABLE( pModule ) : NULL;

        if ( pModule )
            for ( segNr = 1; segNr <= pModule->seg_count; segNr++, pSeg++ )
                if ( GlobalHandleToSel16(pSeg->hSeg) == selector )
                    break;

        if ( pModule && segNr > pModule->seg_count )
            pSeg = NULL;
    }

    /* Abort if segment not found */

    if ( !pModule || !pSeg )
        return FALSE;

    /* Return segment data */

    if ( ppModule ) *ppModule = pModule;
    if ( ppSeg    ) *ppSeg    = pSeg;
    if ( pSegNr   ) *pSegNr   = segNr;

    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1070 1071

/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1072
 *	    GetCodeHandle    (KERNEL.93)
Alexandre Julliard's avatar
Alexandre Julliard committed
1073
 */
1074
HANDLE16 WINAPI GetCodeHandle16( FARPROC16 proc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1075
{
1076
    SEGTABLEENTRY *pSeg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1077

1078 1079
    if ( !TASK_GetCodeSegment( proc, NULL, &pSeg, NULL ) )
        return (HANDLE16)0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1080

1081
    return pSeg->hSeg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1082 1083
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1084 1085 1086
/**********************************************************************
 *	    GetCodeInfo    (KERNEL.104)
 */
1087
BOOL16 WINAPI GetCodeInfo16( FARPROC16 proc, SEGINFO *segInfo )
Alexandre Julliard's avatar
Alexandre Julliard committed
1088
{
1089 1090 1091
    NE_MODULE *pModule;
    SEGTABLEENTRY *pSeg;
    int segNr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1092

1093 1094
    if ( !TASK_GetCodeSegment( proc, &pModule, &pSeg, &segNr ) )
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1095

1096
    /* Fill in segment information */
Alexandre Julliard's avatar
Alexandre Julliard committed
1097

1098 1099 1100 1101 1102 1103
    segInfo->offSegment = pSeg->filepos;
    segInfo->cbSegment  = pSeg->size;
    segInfo->flags      = pSeg->flags;
    segInfo->cbAlloc    = pSeg->minsize;
    segInfo->h          = pSeg->hSeg;
    segInfo->alignShift = pModule->alignment;
Alexandre Julliard's avatar
Alexandre Julliard committed
1104

1105 1106
    if ( segNr == pModule->dgroup )
        segInfo->cbAlloc += pModule->heap_size + pModule->stack_size;
Alexandre Julliard's avatar
Alexandre Julliard committed
1107

1108
    /* Return module handle in %es */
Alexandre Julliard's avatar
Alexandre Julliard committed
1109

1110
    CURRENT_STACK16->es = GlobalHandleToSel16( pModule->self );
Alexandre Julliard's avatar
Alexandre Julliard committed
1111

1112
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1113 1114
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1115

Alexandre Julliard's avatar
Alexandre Julliard committed
1116 1117 1118 1119 1120 1121 1122 1123 1124
/**********************************************************************
 *          DefineHandleTable16    (KERNEL.94)
 */
BOOL16 WINAPI DefineHandleTable16( WORD wOffset )
{
    return TRUE;  /* FIXME */
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1125 1126 1127
/***********************************************************************
 *           SetTaskQueue  (KERNEL.34)
 */
1128
HQUEUE16 WINAPI SetTaskQueue16( HTASK16 hTask, HQUEUE16 hQueue )
Alexandre Julliard's avatar
Alexandre Julliard committed
1129
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1130
    HQUEUE16 hPrev;
Alexandre Julliard's avatar
Alexandre Julliard committed
1131 1132
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1133
    if (!hTask) hTask = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
1134
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1135

Alexandre Julliard's avatar
Alexandre Julliard committed
1136 1137
    hPrev = pTask->hQueue;
    pTask->hQueue = hQueue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1138

Alexandre Julliard's avatar
Alexandre Julliard committed
1139
    return hPrev;
Alexandre Julliard's avatar
Alexandre Julliard committed
1140 1141
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1142 1143 1144 1145

/***********************************************************************
 *           GetTaskQueue  (KERNEL.35)
 */
1146
HQUEUE16 WINAPI GetTaskQueue16( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148 1149
{
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1150
    if (!hTask) hTask = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
1151
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1152 1153 1154
    return pTask->hQueue;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1155 1156 1157
/***********************************************************************
 *           SetThreadQueue  (KERNEL.463)
 */
1158
HQUEUE16 WINAPI SetThreadQueue16( DWORD thread, HQUEUE16 hQueue )
Alexandre Julliard's avatar
Alexandre Julliard committed
1159
{
1160 1161
    TEB *teb = thread? THREAD_IdToTEB( thread ) : NtCurrentTeb();
    HQUEUE16 oldQueue = teb? teb->queue : 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1162

1163
    if ( teb )
Alexandre Julliard's avatar
Alexandre Julliard committed
1164
    {
1165
        teb->queue = hQueue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1166

1167 1168
        if ( GetTaskQueue16( teb->htask16 ) == oldQueue )
            SetTaskQueue16( teb->htask16, hQueue );
Alexandre Julliard's avatar
Alexandre Julliard committed
1169 1170 1171 1172 1173 1174 1175 1176
    }

    return oldQueue;
}

/***********************************************************************
 *           GetThreadQueue  (KERNEL.464)
 */
1177
HQUEUE16 WINAPI GetThreadQueue16( DWORD thread )
Alexandre Julliard's avatar
Alexandre Julliard committed
1178
{
1179
    TEB *teb = NULL;
1180
    if ( !thread )
1181
        teb = NtCurrentTeb();
1182
    else if ( HIWORD(thread) )
1183
        teb = THREAD_IdToTEB( thread );
1184
    else if ( IsTask16( (HTASK16)thread ) )
1185
        teb = ((TDB *)GlobalLock16( (HANDLE16)thread ))->teb;
1186

1187
    return (HQUEUE16)(teb? teb->queue : 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1188 1189 1190 1191 1192
}

/***********************************************************************
 *           SetFastQueue  (KERNEL.624)
 */
1193
VOID WINAPI SetFastQueue16( DWORD thread, HANDLE hQueue )
Alexandre Julliard's avatar
Alexandre Julliard committed
1194
{
1195
    TEB *teb = NULL;
1196
    if ( !thread )
1197
        teb = NtCurrentTeb();
1198
    else if ( HIWORD(thread) )
1199
        teb = THREAD_IdToTEB( thread );
1200
    else if ( IsTask16( (HTASK16)thread ) )
1201
        teb = ((TDB *)GlobalLock16( (HANDLE16)thread ))->teb;
1202

1203
    if ( teb ) teb->queue = (HQUEUE16) hQueue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1204 1205 1206 1207 1208
}

/***********************************************************************
 *           GetFastQueue  (KERNEL.625)
 */
1209
HANDLE WINAPI GetFastQueue16( void )
Alexandre Julliard's avatar
Alexandre Julliard committed
1210
{
1211 1212
    TEB *teb = NtCurrentTeb();
    if (!teb) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1213

1214 1215
    if (!teb->queue)
        Callout.InitThreadInput16( 0, THREAD_IsWin16(teb)? 4 : 5 );
1216

1217
    if (!teb->queue)
1218
        FIXME("(): should initialize thread-local queue, expect failure!\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
1219

1220
    return (HANDLE)teb->queue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1221
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1222

Alexandre Julliard's avatar
Alexandre Julliard committed
1223 1224 1225
/***********************************************************************
 *           SwitchStackTo   (KERNEL.108)
 */
1226
void WINAPI SwitchStackTo16( WORD seg, WORD ptr, WORD top )
Alexandre Julliard's avatar
Alexandre Julliard committed
1227 1228 1229
{
    TDB *pTask;
    STACK16FRAME *oldFrame, *newFrame;
Alexandre Julliard's avatar
Alexandre Julliard committed
1230 1231
    INSTANCEDATA *pData;
    UINT16 copySize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1232

Alexandre Julliard's avatar
Alexandre Julliard committed
1233
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1234
    if (!(pData = (INSTANCEDATA *)GlobalLock16( seg ))) return;
1235 1236 1237
    TRACE("old=%04x:%04x new=%04x:%04x\n",
          SELECTOROF( pTask->teb->cur_stack ),
          OFFSETOF( pTask->teb->cur_stack ), seg, ptr );
Alexandre Julliard's avatar
Alexandre Julliard committed
1238

Alexandre Julliard's avatar
Alexandre Julliard committed
1239
    /* Save the old stack */
Alexandre Julliard's avatar
Alexandre Julliard committed
1240

1241
    oldFrame = THREAD_STACK16( pTask->teb );
Alexandre Julliard's avatar
Alexandre Julliard committed
1242
    /* pop frame + args and push bp */
1243
    pData->old_ss_sp   = pTask->teb->cur_stack + sizeof(STACK16FRAME)
1244
                           + 2 * sizeof(WORD);
Alexandre Julliard's avatar
Alexandre Julliard committed
1245
    *(WORD *)PTR_SEG_TO_LIN(pData->old_ss_sp) = oldFrame->bp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1246 1247 1248 1249
    pData->stacktop    = top;
    pData->stackmin    = ptr;
    pData->stackbottom = ptr;

Alexandre Julliard's avatar
Alexandre Julliard committed
1250
    /* Switch to the new stack */
Alexandre Julliard's avatar
Alexandre Julliard committed
1251

Alexandre Julliard's avatar
Alexandre Julliard committed
1252 1253 1254
    /* Note: we need to take the 3 arguments into account; otherwise,
     * the stack will underflow upon return from this function.
     */
Alexandre Julliard's avatar
Alexandre Julliard committed
1255 1256
    copySize = oldFrame->bp - OFFSETOF(pData->old_ss_sp);
    copySize += 3 * sizeof(WORD) + sizeof(STACK16FRAME);
1257 1258
    pTask->teb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( seg, ptr - copySize );
    newFrame = THREAD_STACK16( pTask->teb );
Alexandre Julliard's avatar
Alexandre Julliard committed
1259 1260 1261

    /* Copy the stack frame and the local variables to the new stack */

Alexandre Julliard's avatar
Alexandre Julliard committed
1262 1263 1264
    memmove( newFrame, oldFrame, copySize );
    newFrame->bp = ptr;
    *(WORD *)PTR_SEG_OFF_TO_LIN( seg, ptr ) = 0;  /* clear previous bp */
Alexandre Julliard's avatar
Alexandre Julliard committed
1265 1266 1267 1268 1269 1270
}


/***********************************************************************
 *           SwitchStackBack   (KERNEL.109)
 */
1271
void WINAPI SwitchStackBack16( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
1272 1273
{
    STACK16FRAME *oldFrame, *newFrame;
Alexandre Julliard's avatar
Alexandre Julliard committed
1274
    INSTANCEDATA *pData;
Alexandre Julliard's avatar
Alexandre Julliard committed
1275

1276
    if (!(pData = (INSTANCEDATA *)GlobalLock16(SELECTOROF(NtCurrentTeb()->cur_stack))))
Alexandre Julliard's avatar
Alexandre Julliard committed
1277 1278
        return;
    if (!pData->old_ss_sp)
Alexandre Julliard's avatar
Alexandre Julliard committed
1279
    {
1280
        WARN("No previous SwitchStackTo\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
1281 1282
        return;
    }
1283 1284
    TRACE("restoring stack %04x:%04x\n",
          SELECTOROF(pData->old_ss_sp), OFFSETOF(pData->old_ss_sp) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1285

1286
    oldFrame = CURRENT_STACK16;
Alexandre Julliard's avatar
Alexandre Julliard committed
1287 1288 1289 1290 1291

    /* Pop bp from the previous stack */

    BP_reg(context) = *(WORD *)PTR_SEG_TO_LIN(pData->old_ss_sp);
    pData->old_ss_sp += sizeof(WORD);
Alexandre Julliard's avatar
Alexandre Julliard committed
1292

Alexandre Julliard's avatar
Alexandre Julliard committed
1293
    /* Switch back to the old stack */
Alexandre Julliard's avatar
Alexandre Julliard committed
1294

1295
    NtCurrentTeb()->cur_stack = pData->old_ss_sp - sizeof(STACK16FRAME);
Alexandre Julliard's avatar
Alexandre Julliard committed
1296
    SS_reg(context)  = SELECTOROF(pData->old_ss_sp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1297
    ESP_reg(context) = OFFSETOF(pData->old_ss_sp) - sizeof(DWORD); /*ret addr*/
Alexandre Julliard's avatar
Alexandre Julliard committed
1298
    pData->old_ss_sp = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1299

Alexandre Julliard's avatar
Alexandre Julliard committed
1300
    /* Build a stack frame for the return */
Alexandre Julliard's avatar
Alexandre Julliard committed
1301

1302
    newFrame = CURRENT_STACK16;
1303 1304 1305 1306
    newFrame->frame32     = oldFrame->frame32;
    newFrame->module_cs   = oldFrame->module_cs;
    newFrame->callfrom_ip = oldFrame->callfrom_ip;
    newFrame->entry_ip    = oldFrame->entry_ip;
Alexandre Julliard's avatar
Alexandre Julliard committed
1307 1308 1309
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1310
/***********************************************************************
1311
 *           GetTaskQueueDS16  (KERNEL.118)
Alexandre Julliard's avatar
Alexandre Julliard committed
1312
 */
1313
void WINAPI GetTaskQueueDS16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1314
{
1315
    CURRENT_STACK16->ds = GlobalHandleToSel16( GetTaskQueue16(0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1316 1317 1318 1319
}


/***********************************************************************
1320
 *           GetTaskQueueES16  (KERNEL.119)
Alexandre Julliard's avatar
Alexandre Julliard committed
1321
 */
1322
void WINAPI GetTaskQueueES16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1323
{
1324
    CURRENT_STACK16->es = GlobalHandleToSel16( GetTaskQueue16(0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1325 1326 1327
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1328 1329 1330
/***********************************************************************
 *           GetCurrentTask   (KERNEL.36)
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1331
HTASK16 WINAPI GetCurrentTask(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1332
{
1333
    return NtCurrentTeb()->htask16;
Alexandre Julliard's avatar
Alexandre Julliard committed
1334 1335
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1336
DWORD WINAPI WIN16_GetCurrentTask(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1337 1338 1339
{
    /* This is the version used by relay code; the first task is */
    /* returned in the high word of the result */
Alexandre Julliard's avatar
Alexandre Julliard committed
1340
    return MAKELONG( GetCurrentTask(), hFirstTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
1341 1342 1343 1344 1345
}


/***********************************************************************
 *           GetCurrentPDB   (KERNEL.37)
1346 1347
 *
 * UNDOC: returns PSP of KERNEL in high word
Alexandre Julliard's avatar
Alexandre Julliard committed
1348
 */
1349
DWORD WINAPI GetCurrentPDB16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1350 1351 1352
{
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1353
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
1354
    return MAKELONG(pTask->hPDB, 0); /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1355 1356 1357
}


1358 1359 1360 1361 1362 1363 1364 1365 1366
/***********************************************************************
 *           GetCurPID16   (KERNEL.157)
 */
DWORD WINAPI GetCurPID16( DWORD unused )
{
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1367 1368 1369
/***********************************************************************
 *           GetInstanceData   (KERNEL.54)
 */
1370
INT16 WINAPI GetInstanceData16( HINSTANCE16 instance, WORD buffer, INT16 len )
Alexandre Julliard's avatar
Alexandre Julliard committed
1371
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1372
    char *ptr = (char *)GlobalLock16( instance );
Alexandre Julliard's avatar
Alexandre Julliard committed
1373 1374
    if (!ptr || !len) return 0;
    if ((int)buffer + len >= 0x10000) len = 0x10000 - buffer;
Alexandre Julliard's avatar
Alexandre Julliard committed
1375
    memcpy( (char *)GlobalLock16(CURRENT_DS) + buffer, ptr + buffer, len );
Alexandre Julliard's avatar
Alexandre Julliard committed
1376 1377 1378 1379
    return len;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1380 1381 1382
/***********************************************************************
 *           GetExeVersion   (KERNEL.105)
 */
1383
WORD WINAPI GetExeVersion16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1384 1385 1386
{
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1387
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1388 1389 1390 1391
    return pTask->version;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1392
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1393
 *           SetErrorMode16   (KERNEL.107)
Alexandre Julliard's avatar
Alexandre Julliard committed
1394
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1395
UINT16 WINAPI SetErrorMode16( UINT16 mode )
Alexandre Julliard's avatar
Alexandre Julliard committed
1396 1397
{
    TDB *pTask;
Alexandre Julliard's avatar
Alexandre Julliard committed
1398
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1399
    pTask->error_mode = mode;
1400
    return SetErrorMode( mode );
Alexandre Julliard's avatar
Alexandre Julliard committed
1401 1402 1403
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1404 1405 1406
/***********************************************************************
 *           GetDOSEnvironment   (KERNEL.131)
 */
1407
SEGPTR WINAPI GetDOSEnvironment16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1408 1409 1410
{
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1411
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1412
    return PTR_SEG_OFF_TO_SEGPTR( pTask->pdb.environment, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1413 1414 1415
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1416 1417 1418
/***********************************************************************
 *           GetNumTasks   (KERNEL.152)
 */
1419
UINT16 WINAPI GetNumTasks16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1420 1421 1422 1423 1424 1425 1426
{
    return nTaskCount;
}


/***********************************************************************
 *           GetTaskDS   (KERNEL.155)
Alexandre Julliard's avatar
Alexandre Julliard committed
1427 1428 1429
 *
 * Note: this function apparently returns a DWORD with LOWORD == HIWORD.
 * I don't think we need to bother with this.
Alexandre Julliard's avatar
Alexandre Julliard committed
1430
 */
1431
HINSTANCE16 WINAPI GetTaskDS16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1432 1433 1434
{
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1435
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
1436
    return GlobalHandleToSel16(pTask->hInstance);
Alexandre Julliard's avatar
Alexandre Julliard committed
1437 1438
}

1439 1440 1441
/***********************************************************************
 *           GetDummyModuleHandleDS   (KERNEL.602)
 */
1442
WORD WINAPI GetDummyModuleHandleDS16(void)
1443 1444 1445 1446
{
    TDB *pTask;
    WORD selector;

1447 1448
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
    if (!(pTask->flags & TDBF_WIN32)) return 0;
1449
    selector = GlobalHandleToSel16( pTask->hModule );
1450 1451
    CURRENT_DS = selector;
    return selector;
1452
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1453 1454 1455 1456

/***********************************************************************
 *           IsTask   (KERNEL.320)
 */
1457
BOOL16 WINAPI IsTask16( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
1458 1459 1460
{
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1461 1462
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return FALSE;
    if (GlobalSize16( hTask ) < sizeof(TDB)) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1463 1464 1465 1466
    return (pTask->magic == TDB_MAGIC);
}


1467 1468 1469 1470 1471 1472 1473 1474 1475
/***********************************************************************
 *           IsWinOldApTask16   (KERNEL.158)
 */
BOOL16 WINAPI IsWinOldApTask16( HTASK16 hTask )
{
    /* should return bit 0 of byte 0x48 in PSP */
    return FALSE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1476 1477 1478
/***********************************************************************
 *           SetTaskSignalProc   (KERNEL.38)
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1479
FARPROC16 WINAPI SetTaskSignalProc( HTASK16 hTask, FARPROC16 proc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1480 1481 1482 1483
{
    TDB *pTask;
    FARPROC16 oldProc;

Alexandre Julliard's avatar
Alexandre Julliard committed
1484
    if (!hTask) hTask = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
1485
    if (!(pTask = (TDB *)GlobalLock16( hTask ))) return NULL;
1486 1487
    oldProc = pTask->userhandler;
    pTask->userhandler = proc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1488 1489 1490
    return oldProc;
}

1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
/***********************************************************************
 *           TASK_CallTaskSignalProc
 */
/* ### start build ### */
extern WORD CALLBACK TASK_CallTo16_word_wwwww(FARPROC16,WORD,WORD,WORD,WORD,WORD);
/* ### stop build ### */
void TASK_CallTaskSignalProc( UINT16 uCode, HANDLE16 hTaskOrModule )
{
    TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
    if ( !pTask || !pTask->userhandler ) return;

    TASK_CallTo16_word_wwwww( pTask->userhandler, 
                              hTaskOrModule, uCode, 0, 
                              pTask->hInstance, pTask->hQueue );
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1506 1507 1508 1509

/***********************************************************************
 *           SetSigHandler   (KERNEL.140)
 */
1510
WORD WINAPI SetSigHandler16( FARPROC16 newhandler, FARPROC16* oldhandler,
Alexandre Julliard's avatar
Alexandre Julliard committed
1511
                           UINT16 *oldmode, UINT16 newmode, UINT16 flag )
Alexandre Julliard's avatar
Alexandre Julliard committed
1512
{
1513
    FIXME("(%p,%p,%p,%d,%d), unimplemented.\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1514
	  newhandler,oldhandler,oldmode,newmode,flag );
Alexandre Julliard's avatar
Alexandre Julliard committed
1515 1516 1517 1518 1519 1520 1521

    if (flag != 1) return 0;
    if (!newmode) newhandler = NULL;  /* Default handler */
    if (newmode != 4)
    {
        TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1522
        if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1523 1524 1525 1526 1527 1528 1529 1530 1531
        if (oldmode) *oldmode = pTask->signal_flags;
        pTask->signal_flags = newmode;
        if (oldhandler) *oldhandler = pTask->sighandler;
        pTask->sighandler = newhandler;
    }
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1532 1533
/***********************************************************************
 *           GlobalNotify   (KERNEL.154)
1534 1535 1536
 *
 * Note that GlobalNotify does _not_ return the old NotifyProc
 * -- contrary to LocalNotify !!
Alexandre Julliard's avatar
Alexandre Julliard committed
1537
 */
1538
VOID WINAPI GlobalNotify16( FARPROC16 proc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1539 1540 1541
{
    TDB *pTask;

Alexandre Julliard's avatar
Alexandre Julliard committed
1542
    if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1543 1544 1545 1546
    pTask->discardhandler = proc;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1547 1548 1549
/***********************************************************************
 *           GetExePtr   (KERNEL.133)
 */
1550
static inline HMODULE16 GetExePtrHelper( HANDLE16 handle, HTASK16 *hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
1551 1552
{
    char *ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1553
    HANDLE16 owner;
Alexandre Julliard's avatar
Alexandre Julliard committed
1554 1555 1556

      /* Check for module handle */

Alexandre Julliard's avatar
Alexandre Julliard committed
1557
    if (!(ptr = GlobalLock16( handle ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1558
    if (((NE_MODULE *)ptr)->magic == IMAGE_OS2_SIGNATURE) return handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1559

Alexandre Julliard's avatar
Alexandre Julliard committed
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
      /* Search for this handle inside all tasks */

    *hTask = hFirstTask;
    while (*hTask)
    {
        TDB *pTask = (TDB *)GlobalLock16( *hTask );
        if ((*hTask == handle) ||
            (pTask->hInstance == handle) ||
            (pTask->hQueue == handle) ||
            (pTask->hPDB == handle)) return pTask->hModule;
        *hTask = pTask->hNext;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1573 1574
      /* Check the owner for module handle */

1575
    owner = FarGetOwner16( handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
1576
    if (!(ptr = GlobalLock16( owner ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1577
    if (((NE_MODULE *)ptr)->magic == IMAGE_OS2_SIGNATURE) return owner;
Alexandre Julliard's avatar
Alexandre Julliard committed
1578

Alexandre Julliard's avatar
Alexandre Julliard committed
1579
      /* Search for the owner inside all tasks */
Alexandre Julliard's avatar
Alexandre Julliard committed
1580

Alexandre Julliard's avatar
Alexandre Julliard committed
1581 1582
    *hTask = hFirstTask;
    while (*hTask)
Alexandre Julliard's avatar
Alexandre Julliard committed
1583
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1584 1585
        TDB *pTask = (TDB *)GlobalLock16( *hTask );
        if ((*hTask == owner) ||
Alexandre Julliard's avatar
Alexandre Julliard committed
1586 1587 1588
            (pTask->hInstance == owner) ||
            (pTask->hQueue == owner) ||
            (pTask->hPDB == owner)) return pTask->hModule;
Alexandre Julliard's avatar
Alexandre Julliard committed
1589
        *hTask = pTask->hNext;
Alexandre Julliard's avatar
Alexandre Julliard committed
1590
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1591

Alexandre Julliard's avatar
Alexandre Julliard committed
1592 1593 1594
    return 0;
}

1595
HMODULE16 WINAPI WIN16_GetExePtr( HANDLE16 handle )
Alexandre Julliard's avatar
Alexandre Julliard committed
1596 1597
{
    HTASK16 hTask = 0;
1598
    HMODULE16 hModule = GetExePtrHelper( handle, &hTask );
1599 1600 1601
    STACK16FRAME *frame = CURRENT_STACK16;
    frame->ecx = hModule;
    if (hTask) frame->es = hTask;
1602
    return hModule;
Alexandre Julliard's avatar
Alexandre Julliard committed
1603 1604
}

1605 1606 1607 1608 1609 1610 1611
HMODULE16 WINAPI GetExePtr( HANDLE16 handle )
{
    HTASK16 hTask = 0;
    return GetExePtrHelper( handle, &hTask );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1612 1613 1614
/***********************************************************************
 *           TaskFirst   (TOOLHELP.63)
 */
1615
BOOL16 WINAPI TaskFirst16( TASKENTRY *lpte )
Alexandre Julliard's avatar
Alexandre Julliard committed
1616 1617
{
    lpte->hNext = hFirstTask;
1618
    return TaskNext16( lpte );
Alexandre Julliard's avatar
Alexandre Julliard committed
1619 1620 1621 1622 1623 1624
}


/***********************************************************************
 *           TaskNext   (TOOLHELP.64)
 */
1625
BOOL16 WINAPI TaskNext16( TASKENTRY *lpte )
Alexandre Julliard's avatar
Alexandre Julliard committed
1626
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1627 1628 1629
    TDB *pTask;
    INSTANCEDATA *pInstData;

1630
    TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext );
Alexandre Julliard's avatar
Alexandre Julliard committed
1631
    if (!lpte->hNext) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1632
    pTask = (TDB *)GlobalLock16( lpte->hNext );
Alexandre Julliard's avatar
Alexandre Julliard committed
1633
    if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
1634
    pInstData = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( GlobalHandleToSel16(pTask->hInstance), 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1635 1636 1637 1638
    lpte->hTask         = lpte->hNext;
    lpte->hTaskParent   = pTask->hParent;
    lpte->hInst         = pTask->hInstance;
    lpte->hModule       = pTask->hModule;
1639 1640
    lpte->wSS           = SELECTOROF( pTask->teb->cur_stack );
    lpte->wSP           = OFFSETOF( pTask->teb->cur_stack );
Alexandre Julliard's avatar
Alexandre Julliard committed
1641 1642 1643 1644 1645
    lpte->wStackTop     = pInstData->stacktop;
    lpte->wStackMinimum = pInstData->stackmin;
    lpte->wStackBottom  = pInstData->stackbottom;
    lpte->wcEvents      = pTask->nEvents;
    lpte->hQueue        = pTask->hQueue;
1646
    lstrcpynA( lpte->szModule, pTask->module_name, sizeof(lpte->szModule) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1647 1648 1649
    lpte->wPSPOffset    = 0x100;  /*??*/
    lpte->hNext         = pTask->hNext;
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1650 1651
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1652 1653 1654 1655

/***********************************************************************
 *           TaskFindHandle   (TOOLHELP.65)
 */
1656
BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
1657
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1658
    lpte->hNext = hTask;
1659
    return TaskNext16( lpte );
Alexandre Julliard's avatar
Alexandre Julliard committed
1660
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1661 1662 1663


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1664 1665
 *           GetAppCompatFlags16   (KERNEL.354)
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1666
DWORD WINAPI GetAppCompatFlags16( HTASK16 hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
1667
{
1668
    return GetAppCompatFlags( hTask );
Alexandre Julliard's avatar
Alexandre Julliard committed
1669 1670 1671 1672
}


/***********************************************************************
1673
 *           GetAppCompatFlags   (USER32.206)
Alexandre Julliard's avatar
Alexandre Julliard committed
1674
 */
1675
DWORD WINAPI GetAppCompatFlags( HTASK hTask )
Alexandre Julliard's avatar
Alexandre Julliard committed
1676 1677 1678 1679 1680 1681 1682 1683
{
    TDB *pTask;

    if (!hTask) hTask = GetCurrentTask();
    if (!(pTask=(TDB *)GlobalLock16( (HTASK16)hTask ))) return 0;
    if (GlobalSize16(hTask) < sizeof(TDB)) return 0;
    return pTask->compat_flags;
}