Example #1
0
void core_Switch(CONTEXT *regs)
{
    struct ExecBase *SysBase = *SysBasePtr;
    struct Task *task;
    struct AROSCPUContext *ctx;
    
    Ints_Enabled = 0;
    D(bug("[KRN] core_Switch()\n"));
    
    task = SysBase->ThisTask;
        
    DS(bug("[KRN] Old task = %p (%s)\n", task, task->tc_Node.ln_Name));
        
    /* Copy current task's context into the ETask structure */
    ctx = (struct AROSCPUContext *)GetIntETask(task)->iet_Context;
    CopyMemory(ctx, regs, sizeof(CONTEXT));
    ctx->LastError = *LastErrorPtr;
        
    /* store IDNestCnt into tasks's structure */  
    task->tc_IDNestCnt = SysBase->IDNestCnt;
    task->tc_SPReg = (APTR)regs->Esp;
        
    /* And enable interrupts */
    SysBase->IDNestCnt = -1;
        
    /* TF_SWITCH flag set? Call the switch routine */
    if (task->tc_Flags & TF_SWITCH)
    {
        task->tc_Switch(SysBase);
    }
    
    core_Dispatch(regs);
}
Example #2
0
/*
 * Task dispatcher. Basically it may be the same one no matter what scheduling algorithm is used
 */
void core_Dispatch(CONTEXT *regs)
{
    struct ExecBase *SysBase = *SysBasePtr;
    struct Task *task;
    struct AROSCPUContext *ctx;

    Ints_Enabled = 0;
    D(bug("[KRN] core_Dispatch()\n"));

    /* 
     * Is the list of ready tasks empty? Well, increment the idle switch cound and stop the main thread.
     */
    if (IsListEmpty(&SysBase->TaskReady))
    {
        if (!Sleep_Mode) {
            SysBase->IdleCount++;
            SysBase->AttnResched |= ARF_AttnSwitch;
            DSLEEP(bug("[KRN] TaskReady list empty. Sleeping for a while...\n"));
            /* We are entering sleep mode */
	    Sleep_Mode = SLEEP_MODE_PENDING;
        }

        core_LeaveInterrupt();
        return;
    }

    Sleep_Mode = SLEEP_MODE_OFF;
    SysBase->DispCount++;
        
    /* Get the first task from the TaskReady list, and populate it's settings through Sysbase */
    task = (struct Task *)REMHEAD(&SysBase->TaskReady);
    SysBase->ThisTask = task;  
    SysBase->Elapsed = SysBase->Quantum;
    SysBase->SysFlags &= ~0x2000;
    task->tc_State = TS_RUN;
    SysBase->IDNestCnt = task->tc_IDNestCnt;

    DS(bug("[KRN] New task = %p (%s)\n", task, task->tc_Node.ln_Name));

    /* Handle tasks's flags */
    if (task->tc_Flags & TF_EXCEPT)
        Exception();
        
    if (task->tc_Flags & TF_LAUNCH)
    {
        task->tc_Launch(SysBase);       
    }
        
    /* Restore the task's state */
    ctx = (struct AROSCPUContext *)GetIntETask(task)->iet_Context;
    CopyMemory(regs, ctx, sizeof(CONTEXT));
    *LastErrorPtr = ctx->LastError;
        
    /* Leave interrupt and jump to the new task */
    core_LeaveInterrupt();
}
Example #3
0
/*
 * Task dispatcher. Basically it may be the same one no matter what scheduling algorithm is used
 */
void core_Dispatch(regs_t *regs)
{
    volatile struct ExecBase *SysBase = getSysBase();
    struct Task *task;

    if (SysBase)
    {
    	wrmsr(rdmsr() & ~MSR_EE);

        /*
         * Is the list of ready tasks empty? Well, increment the idle switch cound and halt CPU.
         * It should be extended by some plugin mechanism which would put CPU and whole machine
         * into some more sophisticated sleep states (ACPI?)
         */
        while (IsListEmpty(&SysBase->TaskReady))
        {
//            SysBase->IdleCount++;
            SysBase->AttnResched |= ARF_AttnSwitch;

            //D(bug("[KRN] TaskReady list empty. Sleeping for a while...\n"));
            /* Sleep almost forever ;) */

            wrmsr(rdmsr() | MSR_EE);
            asm volatile("sync");
//            wrmsr(rdmsr() | MSR_POW);
//            asm volatile("isync");

            if (SysBase->SysFlags & SFF_SoftInt)
            {
                core_Cause(SysBase);
            }
        }

        SysBase->DispCount++;

        /* Get the first task from the TaskReady list, and populate it's settings through Sysbase */
        task = (struct Task *)REMHEAD(&SysBase->TaskReady);
        SysBase->ThisTask = task;
        SysBase->Elapsed = SysBase->Quantum;
        SysBase->SysFlags &= ~0x2000;
        task->tc_State = TS_RUN;
        SysBase->IDNestCnt = task->tc_IDNestCnt;

        //D(bug("[KRN] New task = %p (%s)\n", task, task->tc_Node.ln_Name));

        /* Handle tasks's flags */
        if (task->tc_Flags & TF_EXCEPT)
            Exception();

        /* Store the launch time */
        GetIntETask(task)->iet_private1 = mftbu();

        if (task->tc_Flags & TF_LAUNCH)
        {
            AROS_UFC1(void, task->tc_Launch,
                      AROS_UFCA(struct ExecBase *, SysBase, A6));
        }

        /* Restore the task's state */
        regs = task->tc_UnionETask.tc_ETask->et_RegFrame;

        if (SysBase->IDNestCnt < 0)
        	regs->srr1 |= MSR_EE;

        /* Copy the fpu, mmx, xmm state */
#warning FIXME: Change to the lazy saving of the FPU state!!!!
#warning TODO: No FPU support yet!!!!!!! Yay, it sucks! :-D

    }
Example #4
0
LONG launcher()
{
    D(bug("launcher: Entered child launcher\n"));

    struct Task *this = FindTask(NULL);
    struct vfork_data *udata = this->tc_UserData;
    BYTE child_signal;
    struct Library *aroscbase = NULL;

    GetIntETask(this)->iet_startup = GetETask(this)->et_Result2 = AllocVec(sizeof(struct aros_startup), MEMF_ANY | MEMF_CLEAR);

    /* Allocate signal for parent->child communication */
    child_signal = udata->child_signal = AllocSignal(-1);
    D(bug("launcher: Allocated child signal: %d\n", udata->child_signal));
    if(udata->child_signal == -1)
    {
	/* Lie */
	udata->child_errno = ENOMEM;
	Signal(udata->parent, 1 << udata->parent_signal);
	return -1;
    }

    if(__register_init_fdarray(udata->ppriv->acpd_fd_array, udata->ppriv->acpd_numslots))
        aroscbase = OpenLibrary((STRPTR) "arosc.library", 0);
    if(!aroscbase)
    {
	FreeSignal(child_signal);
	udata->child_errno = ENOMEM;
	Signal(udata->parent, 1 << udata->parent_signal);
	return -1;	
    }
    
    udata->cpriv = __get_arosc_privdata();
    udata->cpriv->acpd_parent_does_upath = udata->ppriv->acpd_doupath;
    udata->cpriv->acpd_flags |= DO_NOT_CLONE_ENV_VARS;

    if(setjmp(__aros_startup_jmp_buf) == 0)
    {
        /* Setup complete, signal parent */
        D(bug("launcher: Signaling parent that we finished setup\n"));
        Signal(udata->parent, 1 << udata->parent_signal);

        D(bug("launcher: Child waiting for exec or exit\n"));
        Wait(1 << udata->child_signal);

        if(udata->child_executed)
        {
            APTR exec_id;
            BPTR dir;
            
            D(bug("launcher: child executed\n"));
            
            /* Set current dir to parent's current dir */
            dir = DupLock(((struct Process *)udata->parent)->pr_CurrentDir);
            UnLock(CurrentDir(dir));
            /* Don't mind updating aroscbase->acb_startup_cd_changed as we will
               exit from process after __exec_do has finished */

            /* Filenames passed from parent obey parent's __doupath */
            __doupath = udata->cpriv->acpd_parent_does_upath;
            D(bug("launcher: __doupath == %d for __exec_prepare()\n", __doupath));
            
            exec_id = udata->exec_id = __exec_prepare(
                udata->exec_filename,
                udata->exec_searchpath,
                udata->exec_argv,
                udata->exec_envp
            );
            
            udata->child_errno = errno;

            /* Clear __doupath again, command will set it if wanted */
            __doupath = 0;
            
            D(bug("launcher: informing parent that we have run __exec_prepare\n"));
            /* Inform parent that we have run __exec_prepare */
            Signal(udata->parent, 1 << udata->parent_signal);
            
            /* Wait 'till __exec_do() is called on parent process */
            D(bug("launcher: Waiting parent to get the result\n"));
            Wait(1 << udata->child_signal);

            D(bug("launcher: informing parent that we won't use udata anymore\n"));
            /* Inform parent that we won't use udata anymore */
            Signal(udata->parent, 1 << udata->parent_signal);

            if (exec_id)
            {
                D(bug("launcher: executing command\n"));
                __exec_do(exec_id);
                
                assert(0); /* Should not be reached */
            }
            else
            {
                D(bug("launcher: exit because execve returned with an error\n"));
                _exit(0);
            }
        }
        else
        {
            D(bug("launcher: informing parent that we won't use udata anymore\n"));
            /* Inform parent that we won't use udata anymore */
            Signal(udata->parent, 1 << udata->parent_signal);
        }
    }
    else
    {
        D(bug("launcher: freeing child_signal\n"));
        FreeSignal(child_signal);
        CloseLibrary(aroscbase);
    }
    
    return 0;
}
Example #5
0
pid_t __vfork(jmp_buf env)
{
    struct Task *this = FindTask(NULL);
    struct vfork_data *udata = AllocMem(sizeof(struct vfork_data), MEMF_ANY | MEMF_CLEAR);
    if(udata == NULL)
    {
	errno = ENOMEM;
	longjmp(env, -1);	
    }
    D(bug("__vfork: allocated udata %p\n", udata));
    bcopy(env, &udata->vfork_jump, sizeof(jmp_buf));

    struct TagItem tags[] =
    {
	{ NP_Entry,         (IPTR) launcher  },
	{ NP_CloseInput,    (IPTR) FALSE     },
	{ NP_CloseOutput,   (IPTR) FALSE     },
	{ NP_CloseError,    (IPTR) FALSE     },
        { NP_Cli,           (IPTR) TRUE      },
        { NP_Name,          (IPTR) "vfork()" },
        { NP_UserData,      (IPTR) udata     },
        { NP_NotifyOnDeath, (IPTR) TRUE      },
        { TAG_DONE,         0                }
    };

    udata->parent = this;
    
    struct arosc_privdata *ppriv = __get_arosc_privdata();
    udata->ppriv = ppriv;
    
    /* Store parent's vfork_data to restore it later */
    udata->prev = __get_arosc_privdata()->acpd_vfork_data;
    D(bug("__vfork: Saved old parent's vfork_data: %p\n", udata->prev));
                                        
    D(bug("__vfork: backuping startup buffer\n"));
    /* Backup startup buffer */
    CopyMem(&__aros_startup_jmp_buf, &udata->startup_jmp_buf, sizeof(jmp_buf));

    D(bug("__vfork: Allocating parent signal\n"));
    /* Allocate signal for child->parent communication */
    udata->parent_signal = AllocSignal(-1);
    if(udata->parent_signal == -1)
    {
	/* Couldn't allocate the signal, return -1 */
	FreeMem(udata, sizeof(struct vfork_data));
	errno = ENOMEM;
	longjmp(udata->vfork_jump, -1);    
    }
    
    D(bug("__vfork: Creating child\n"));
    udata->child = (struct Task*) CreateNewProc(tags);

    if(udata->child == NULL)
    {
	/* Something went wrong, return -1 */
	FreeMem(udata, sizeof(struct vfork_data));
	errno = ENOMEM; /* Most likely */
	longjmp(env, -1);
    }
    D(bug("__vfork: Child created %p, waiting to finish setup\n", udata->child));
    udata->child_id = GetETaskID(udata->child);
    D(bug("__vfork: Got unique child id: %d\n", udata->child_id));

    /* Wait for child to finish setup */
    Wait(1 << udata->parent_signal);
    
    if(udata->child_errno)
    {
	/* An error occured during child setup */
	errno = udata->child_errno;
	longjmp(env, -1);
    }
    
    D(bug("__vfork: Setting jmp_buf at %p in %p\n", __aros_startup, &__aros_startup_jmp_buf));
    if(setjmp(__aros_startup_jmp_buf))
    {
	D(bug("__vfork: child exited\n or executed\n"));

	if(!GETUDATA->child_executed)
	{
	    D(bug("__vfork: not executed\n"));
	    ((struct aros_startup*) GetIntETask(GETUDATA->child)->iet_startup)->as_startup_error = __aros_startup_error;
	    D(bug("__vfork: Signaling child\n"));
	    Signal(GETUDATA->child, 1 << GETUDATA->child_signal);
	}

	D(bug("__vfork: Waiting for child to finish using udata\n"));
	/* Wait for child to finish using GETUDATA */
	Wait(1 << GETUDATA->parent_signal);

	D(bug("__vfork: fflushing\n"));
	fflush(NULL);

	D(bug("__vfork: restoring old fd_array\n"));
	/* Restore parent's old fd_array */
	((struct arosc_privdata *) GetIntETask(GETUDATA->parent)->iet_acpd)->acpd_fd_mempool = GETUDATA->parent_acpd_fd_mempool;
	((struct arosc_privdata *) GetIntETask(GETUDATA->parent)->iet_acpd)->acpd_numslots = GETUDATA->parent_acpd_numslots;
	((struct arosc_privdata *) GetIntETask(GETUDATA->parent)->iet_acpd)->acpd_fd_array =  GETUDATA->parent_acpd_fd_array;

	D(bug("__vfork: restoring startup buffer\n"));
	/* Restore parent startup buffer */
	CopyMem(&GETUDATA->startup_jmp_buf, &__aros_startup_jmp_buf, sizeof(jmp_buf));

	D(bug("__vfork: freeing parent signal\n"));
	FreeSignal(GETUDATA->parent_signal);

        errno = GETUDATA->child_errno;
        
	FreeAndJump(GETUDATA);
	assert(0); /* not reached */
        return (pid_t) 1;
    }

    /* Remember parent fd descriptor table */
    udata->parent_acpd_fd_mempool = ppriv->acpd_fd_mempool;
    udata->parent_acpd_numslots = ppriv->acpd_numslots;
    udata->parent_acpd_fd_array = ppriv->acpd_fd_array;
    
    /* Pretend to be running as the child created by vfork */
    ppriv->acpd_vfork_data = udata;
    ppriv->acpd_flags |= PRETEND_CHILD;
    ppriv->acpd_fd_mempool = udata->cpriv->acpd_fd_mempool;
    ppriv->acpd_numslots = udata->cpriv->acpd_numslots;
    ppriv->acpd_fd_array = udata->cpriv->acpd_fd_array;
    
    D(bug("__vfork: Jumping to jmp_buf %p\n", &udata->vfork_jump));
    D(bug("__vfork: ip: %p, stack: %p\n", udata->vfork_jump[0].retaddr, udata->vfork_jump[0].regs[_JMPLEN - 1]));
    vfork_longjmp(udata->vfork_jump, 0);
    assert(0); /* not reached */
    return (pid_t) 0;
}