예제 #1
0
파일: a2_vm.c 프로젝트: eagles125/A2
static inline void callinfo_new(struct a2_vm* vm_p, struct a2_closure* cls, int retbegin, int retnumber){
	assert(vm_p);
	struct vm_callinfo* ci = (struct vm_callinfo*)malloc(sizeof(*ci));
	ci->cls = cls;
	// set closure stack frame
	ci->reg_stack.len = (cls)?(a2_closure_regscount(cls)):(0);
	ci->reg_stack.sf_idx = up_stack_frame(vm_p, ci->reg_stack.len);
	ci->pc=0;
	ci->front = NULL;
	ci->retbegin = retbegin;
	ci->retnumber = retnumber;
	ci->next = vm_p->call_chain;
	if(vm_p->call_chain)
		vm_p->call_chain->front = ci;
	vm_p->call_chain = ci;
}
예제 #2
0
static inline int task_stackargsetup(FAR struct task_tcb_s *tcb,
                                     FAR char * const argv[])
{
  FAR char **stackargv;
  FAR const char *name;
  FAR char *str;
  size_t strtablen;
  size_t argvlen;
  int nbytes;
  int argc;
  int i;

  /* Get the name string that we will use as the first argument */

#if CONFIG_TASK_NAME_SIZE > 0
  name = tcb->cmn.name;
#else
  name = (FAR const char *)g_noname;
#endif /* CONFIG_TASK_NAME_SIZE */

  /* Get the size of the task name (including the NUL terminator) */

  strtablen = (strlen(name) + 1);

  /* Count the number of arguments and get the accumulated size of the
   * argument strings (including the null terminators).  The argument count
   * does not include the task name in that will be in argv[0].
   */

  argc = 0;
  if (argv)
    {
      /* A NULL argument terminates the list */

      while (argv[argc])
        {
          /* Add the size of this argument (with NUL terminator).
           * Check each time if the accumulated size exceeds the
           * size of the allocated stack.
           */

          strtablen += (strlen(argv[argc]) + 1);
          if (strtablen >= tcb->cmn.adj_stack_size)
            {
               return -ENAMETOOLONG;
            }

          /* Increment the number of args.  Here is a sanity check to
           * prevent running away with an unterminated argv[] list.
           * MAX_STACK_ARGS should be sufficiently large that this never
           * happens in normal usage.
           */

          if (++argc > MAX_STACK_ARGS)
            {
              return -E2BIG;
            }
        }
    }

  /* Allocate a stack frame to hold argv[] array and the strings.  NOTE
   * that argc + 2 entries are needed:  The number of arguments plus the
   * task name plus a NULL argv[] entry to terminate the list.
   */

  argvlen   = (argc + 2)*sizeof(FAR char*);
  stackargv = (FAR char **)up_stack_frame(&tcb->cmn, argvlen + strtablen);

  DEBUGASSERT(stackargv != NULL);
  if (stackargv == NULL)
    {
      return -ENOMEM;
    }

  /* Get the address of the string table that will lie immediately after
   * the argv[] array and mark it as a null string.
   */

  str = (FAR char *)stackargv + argvlen;

  /* Copy the task name.  Increment str to skip over the task name and its
   * NUL terminator in the string buffer.
   */

  stackargv[0] = str;
  nbytes       = strlen(name) + 1;
  strcpy(str, name);
  str         += nbytes;

  /* Copy each argument */

  for (i = 0; i < argc; i++)
    {
      /* Save the pointer to the location in the string buffer and copy
       * the argument into the buffer.  Increment str to skip over the
       * argument and its NUL terminator in the string buffer.
       */

      stackargv[i+1] = str;
      nbytes         = strlen(argv[i]) + 1;
      strcpy(str, argv[i]);
      str           += nbytes;
    }

  /* Put a terminator entry at the end of the argv[] array.  Then save the
   * argv[] arry pointer in the TCB where it will be recovered later by
   * task_start().
   */

  stackargv[argc + 1] = NULL;
  tcb->argv = stackargv;

  return OK;
}
예제 #3
0
파일: up_vfork.c 프로젝트: dagar/NuttX
pid_t up_vfork(const struct vfork_s *context)
{
  struct tcb_s *parent = this_task();
  struct task_tcb_s *child;
  size_t stacksize;
  uint32_t newsp;
#ifdef CONFIG_MIPS32_FRAMEPOINTER
  uint32_t newfp;
#endif
  uint32_t stackutil;
  size_t argsize;
  void *argv;
  int ret;

  sinfo("s0:%08x s1:%08x s2:%08x s3:%08x s4:%08x\n",
        context->s0, context->s1, context->s2, context->s3, context->s4);
#ifdef CONFIG_MIPS32_FRAMEPOINTER
  sinfo("s5:%08x s6:%08x s7:%08x\n",
        context->s5, context->s6, context->s7);
#ifdef MIPS32_SAVE_GP
  sinfo("fp:%08x sp:%08x ra:%08x gp:%08x\n",
        context->fp, context->sp, context->ra, context->gp);
#else
  sinfo("fp:%08x sp:%08x ra:%08x\n",
        context->fp context->sp, context->ra);
#endif
#else
  sinfo("s5:%08x s6:%08x s7:%08x s8:%08x\n",
        context->s5, context->s6, context->s7, context->s8);
#ifdef MIPS32_SAVE_GP
  sinfo("sp:%08x ra:%08x gp:%08x\n",
        context->sp, context->ra, context->gp);
#else
  sinfo("sp:%08x ra:%08x\n",
        context->sp, context->ra);
#endif
#endif

  /* Allocate and initialize a TCB for the child task. */

  child = task_vforksetup((start_t)context->ra, &argsize);
  if (!child)
    {
      sinfo("task_vforksetup failed\n");
      return (pid_t)ERROR;
    }

  sinfo("Parent=%p Child=%p\n", parent, child);

  /* Get the size of the parent task's stack.  Due to alignment operations,
   * the adjusted stack size may be smaller than the stack size originally
   * requrested.
   */

  stacksize = parent->adj_stack_size + CONFIG_STACK_ALIGNMENT - 1;

  /* Allocate the stack for the TCB */

  ret = up_create_stack((FAR struct tcb_s *)child, stacksize + argsize,
                        parent->flags & TCB_FLAG_TTYPE_MASK);
  if (ret != OK)
    {
      serr("ERROR: up_create_stack failed: %d\n", ret);
      task_vforkabort(child, -ret);
      return (pid_t)ERROR;
    }

  /* Allocate the memory and copy argument from parent task */

  argv = up_stack_frame((FAR struct tcb_s *)child, argsize);
  memcpy(argv, parent->adj_stack_ptr, argsize);

  /* How much of the parent's stack was utilized?  The MIPS uses
   * a push-down stack so that the current stack pointer should
   * be lower than the initial, adjusted stack pointer.  The
   * stack usage should be the difference between those two.
   */

  DEBUGASSERT((uint32_t)parent->adj_stack_ptr > context->sp);
  stackutil = (uint32_t)parent->adj_stack_ptr - context->sp;

  sinfo("stacksize:%d stackutil:%d\n", stacksize, stackutil);

  /* Make some feeble effort to perserve the stack contents.  This is
   * feeble because the stack surely contains invalid pointers and other
   * content that will not work in the child context.  However, if the
   * user follows all of the caveats of vfork() usage, even this feeble
   * effort is overkill.
   */

  newsp = (uint32_t)child->cmn.adj_stack_ptr - stackutil;
  memcpy((void *)newsp, (const void *)context->sp, stackutil);

  /* Was there a frame pointer in place before? */

#ifdef CONFIG_MIPS32_FRAMEPOINTER
  if (context->fp <= (uint32_t)parent->adj_stack_ptr &&
      context->fp >= (uint32_t)parent->adj_stack_ptr - stacksize)
    {
      uint32_t frameutil = (uint32_t)parent->adj_stack_ptr - context->fp;
      newfp = (uint32_t)child->cmn.adj_stack_ptr - frameutil;
    }
  else
    {
      newfp = context->fp;
    }

  sinfo("Old stack base:%08x SP:%08x FP:%08x\n",
        parent->adj_stack_ptr, context->sp, context->fp);
  sinfo("New stack base:%08x SP:%08x FP:%08x\n",
        child->cmn.adj_stack_ptr, newsp, newfp);
#else
  sinfo("Old stack base:%08x SP:%08x\n",
        parent->adj_stack_ptr, context->sp);
  sinfo("New stack base:%08x SP:%08x\n",
        child->cmn.adj_stack_ptr, newsp);
#endif

  /* Update the stack pointer, frame pointer, global pointer and saved
   * registers.  When the child TCB was initialized, all of the values
   * were set to zero. up_initial_state() altered a few values, but the
   * return value in v0 should be cleared to zero, providing the
   * indication to the newly started child thread.
   */

  child->cmn.xcp.regs[REG_S0]  = context->s0;  /* Saved register s0 */
  child->cmn.xcp.regs[REG_S1]  = context->s1;  /* Saved register s1 */
  child->cmn.xcp.regs[REG_S2]  = context->s2;  /* Saved register s2 */
  child->cmn.xcp.regs[REG_S3]  = context->s3;  /* Volatile register s3 */
  child->cmn.xcp.regs[REG_S4]  = context->s4;  /* Volatile register s4 */
  child->cmn.xcp.regs[REG_S5]  = context->s5;  /* Volatile register s5 */
  child->cmn.xcp.regs[REG_S6]  = context->s6;  /* Volatile register s6 */
  child->cmn.xcp.regs[REG_S7]  = context->s7;  /* Volatile register s7 */
#ifdef CONFIG_MIPS32_FRAMEPOINTER
  child->cmn.xcp.regs[REG_FP]  = newfp;        /* Frame pointer */
#else
  child->cmn.xcp.regs[REG_S8]  = context->s8;  /* Volatile register s8 */
#endif
  child->cmn.xcp.regs[REG_SP]  = newsp;        /* Stack pointer */
#ifdef MIPS32_SAVE_GP
  child->cmn.xcp.regs[REG_GP]  = newsp;        /* Global pointer */
#endif

  /* And, finally, start the child task.  On a failure, task_vforkstart()
   * will discard the TCB by calling task_vforkabort().
   */

  return task_vforkstart(child);
}