Exemple #1
0
int rt_tbx_delete(TBX *tbx)
{
	CHK_TBX_MAGIC;
	tbx->magic = 0;
	if (rt_sem_delete(&(tbx->sndsmx)) || rt_sem_delete(&(tbx->rcvsmx))|| rt_sem_delete(&(tbx->bcbsmx))) {
		return -EFAULT;
	}
	while (tbx->waiting_task) {
		tbx_signal(tbx);
	}
	sched_free(tbx->bufadr); 
	sched_free(tbx->bcbadr); 
	return 0;
}
Exemple #2
0
/**
 * @brief - purge scheduler from system
 *
 * @param[in]	psched	- The pointer to the delete to delete
 *
 * @return	error code
 * @retval	0	- scheduler purged
 * @retval	PBSE_OBJBUSY	- scheduler deletion not allowed
 */
int
sched_delete(pbs_sched *psched)
{
	pbs_db_obj_info_t obj;
	pbs_db_sched_info_t dbsched;
	pbs_db_conn_t *conn = (pbs_db_conn_t *) svr_db_conn;

	if (psched == NULL)
		return (0);

	/* TODO check for scheduler activity and return PBSE_OBJBUSY */
	/* delete scheduler from database */
	strcpy(dbsched.sched_name, psched->sc_name);
	obj.pbs_db_obj_type = PBS_DB_SCHED;
	obj.pbs_db_un.pbs_db_sched = &dbsched;
	if (pbs_db_delete_obj(conn, &obj) != 0) {
		snprintf(log_buffer, LOG_BUF_SIZE,
				"delete of scheduler %s from datastore failed",
				psched->sc_name);
		log_err(errno, __func__, log_buffer);
	}
	sched_free(psched);

	return (0);
}
void up_release_stack(_TCB *dtcb)
{
  if (dtcb->stack_alloc_ptr)
    {
      sched_free(dtcb->stack_alloc_ptr);
      dtcb->stack_alloc_ptr = NULL;
    }

  dtcb->adj_stack_size = 0;
}
Exemple #4
0
int up_create_stack(_TCB *tcb, size_t stack_size)
{
  if (tcb->stack_alloc_ptr &&
      tcb->adj_stack_size != stack_size)
    {
      sched_free(tcb->stack_alloc_ptr);
      tcb->stack_alloc_ptr = NULL;
    }

   if (!tcb->stack_alloc_ptr)
     {
#ifdef CONFIG_DEBUG
       tcb->stack_alloc_ptr = (uint32_t*)kzalloc(stack_size);
#else
       tcb->stack_alloc_ptr = (uint32_t*)kmalloc(stack_size);
#endif
     }

   if (tcb->stack_alloc_ptr)
     {
       size_t top_of_stack;
       size_t size_of_stack;

       /* MIPS uses a push-down stack:  the stack grows
        * toward loweraddresses in memory.  The stack pointer
        * register, points to the lowest, valid work address
        * (the "top" of the stack).  Items on the stack are
        * referenced as positive word offsets from sp.
        */

       top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4;

       /* The MIPS stack must be aligned at word (4 byte)
        * boundaries. If necessary top_of_stack must be rounded
        * down to the next boundary
        */

       top_of_stack &= ~3;
       size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4;

       /* Save the adjusted stack values in the _TCB */

       tcb->adj_stack_ptr  = (uint32_t*)top_of_stack;
       tcb->adj_stack_size = size_of_stack;

       up_ledon(LED_STACKCREATED);
       return OK;
     }

   return ERROR;
}
void pthread_destroyjoin(FAR join_t *pjoin)
{
  sdbg("pjoin=0x%p\n", pjoin);

  /* Remove the join info from the set of joins */

  (void)pthread_removejoininfo((pid_t)pjoin->thread);

  /* Destroy its semaphores */

  (void)sem_destroy(&pjoin->data_sem);
  (void)sem_destroy(&pjoin->exit_sem);

  /* And deallocate the pjoin structure */

  sched_free(pjoin);
}
Exemple #6
0
void uip_grpfree(FAR struct uip_driver_s *dev, FAR struct igmp_group_s *group)
{
  uip_lock_t flags;

  grplldbg("Free: %p flags: %02x\n", group, group->flags);

  /* Cancel the wdog */

  flags = uip_lock();
  wd_cancel(group->wdog);
  
  /* Remove the group structure from the group list in the device structure */

  sq_rem((FAR sq_entry_t*)group, &dev->grplist);
  
  /* Destroy the wait semapore */

  (void)sem_destroy(&group->sem);

  /* Destroy the wdog */

  wd_delete(group->wdog);
  
  /* Then release the group structure resources.  Check first if this is one
   * of the pre-allocated group structures that we will retain in a free list.
   */

#if CONFIG_PREALLOC_IGMPGROUPS > 0
  if (IS_PREALLOCATED(group->flags))
    {
      grplldbg("Put back on free list\n");
      sq_addlast((FAR sq_entry_t*)group, &g_freelist);
      uip_unlock(flags);
    }
  else
#endif
    {
      /* No.. deallocate the group structure.  Use sched_free() just in case
       * this function is executing within an interrupt handler.
       */

      uip_unlock(flags);
      grplldbg("Call sched_free()\n");
      sched_free(group);
    }
}
int rt_delete_tasklet(struct rt_tasklet_struct *tasklet)
{
	int pid, thread;

	rt_remove_tasklet(tasklet);
	tasklet->handler = 0;
	pid = ((tasklet->task)->lnxtsk)->pid;
	copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_tasklet_struct));
	rt_task_resume(tasklet->task);
	while (find_task_by_pid(pid)) {
		current->state = TASK_INTERRUPTIBLE;
		schedule_timeout(2);
	}
	thread = tasklet->thread;	
	sched_free(tasklet);
	return thread;	
}
Exemple #8
0
int up_use_stack(_TCB *tcb, void *stack, size_t stack_size)
{
  size_t top_of_stack;
  size_t size_of_stack;

  if (tcb->stack_alloc_ptr)
    {
      sched_free(tcb->stack_alloc_ptr);
    }

  /* Save the stack allocation */

  tcb->stack_alloc_ptr = stack;

  /* The ARM uses a push-down stack:  the stack grows toward lower addresses
   * in memory.  The stack pointer register, points to the lowest, valid
   * work address (the "top" of the stack).  Items on the stack are
   * referenced as positive word offsets from sp.
   */

  top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4;

  /* The ARM stack must be aligned; 4 byte alignment for OABI and 8-byte
   * alignment for EABI. If necessary top_of_stack must be rounded down
   * to the next boundary
   */

  top_of_stack = STACK_ALIGN_DOWN(top_of_stack);

  /* The size of the stack in bytes is then the difference between
   * the top and the bottom of the stack (+4 because if the top
   * is the same as the bottom, then the size is one 32-bit element).
   * The size need not be aligned.
   */

  size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4;

  /* Save the adjusted stack values in the _TCB */

  tcb->adj_stack_ptr  = (uint32_t*)top_of_stack;
  tcb->adj_stack_size = size_of_stack;

  return OK;
}
void sig_releasependingsigaction(FAR sigq_t *sigq)
{
  irqstate_t saved_state;

  /* If this is a generally available pre-allocated structyre,
   * then just put it back in the free list.
   */

  if (sigq->type == SIG_ALLOC_FIXED)
    {
      /* Make sure we avoid concurrent access to the free
       * list from interrupt handlers. */

      saved_state = irqsave();
      sq_addlast((FAR sq_entry_t*)sigq, &g_sigpendingaction);
      irqrestore(saved_state);
   }

  /* If this is a message pre-allocated for interrupts,
   * then put it back in the correct  free list.
   */

  else if (sigq->type == SIG_ALLOC_IRQ)
    {
      /* Make sure we avoid concurrent access to the free
       * list from interrupt handlers. */

      saved_state = irqsave();
      sq_addlast((FAR sq_entry_t*)sigq, &g_sigpendingirqaction);
      irqrestore(saved_state);
    }

  /* Otherwise, deallocate it.  Note:  interrupt handlers
   * will never deallocate signals because they will not
   * receive them.
   */

  else if (sigq->type == SIG_ALLOC_DYN)
    {
      sched_free(sigq);
    }
}
Exemple #10
0
void env_release(FAR struct task_group_s *group)
{
  DEBUGASSERT(group);

  /* Free any allocate environment strings */

  if (group->tg_envp)
    {
      /* Free the environment */

      sched_free(group->tg_envp);
    }

  /* In any event, make sure that all environment-related varialbles in the
   * task group structure are reset to initial values.
   */

  group->tg_envsize = 0;
  group->tg_envp = NULL;
}
Exemple #11
0
int sem_close(FAR sem_t *sem)
{
  FAR nsem_t *psem;
  int ret = ERROR;

  /* Verify the inputs */

  if (sem)
    {
      sched_lock();

      /* Search the list of named semaphores */

      for (psem = (FAR nsem_t*)g_nsems.head;
           ((psem) && (sem != &psem->sem));
           psem = psem->flink);

      /* Check if we found it */

      if (psem)
        {
          /* Decrement the count of sem_open connections to this semaphore */

          if (psem->nconnect) psem->nconnect--;

          /* If the semaphore is no long connected to any processes AND the
           * semaphore was previously unlinked, then deallocate it.
           */

          if (!psem->nconnect && psem->unlinked)
            {
              dq_rem((FAR dq_entry_t*)psem, &g_nsems);
              sched_free(psem);
            }
          ret = OK;
        }
      sched_unlock();
    }

  return ret;
}
Exemple #12
0
void mq_msgqfree(FAR msgq_t *msgq)
{
  FAR mqmsg_t *curr;
  FAR mqmsg_t *next;

  /* Deallocate any stranded messages in the message queue. */

  curr = (FAR mqmsg_t*)msgq->msglist.head;
  while (curr)
    {
      /* Deallocate the message structure. */

      next = curr->next;
      mq_msgfree(curr);
      curr = next;
    }

  /* Then deallocate the message queue itself */

  sched_free(msgq);
}
Exemple #13
0
int up_use_stack(_TCB *tcb, void *stack, size_t stack_size)
{
  size_t top_of_stack;
  size_t size_of_stack;

  if (tcb->stack_alloc_ptr)
    {
      sched_free(tcb->stack_alloc_ptr);
    }

  /* Save the stack allocation */

  tcb->stack_alloc_ptr = stack;

  /* The Arm7Tdmi uses a push-down stack:  the stack grows
   * toward loweraddresses in memory.  The stack pointer
   * register, points to the lowest, valid work address
   * (the "top" of the stack).  Items on the stack are
   * referenced as positive word offsets from sp.
   */

  top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4;

  /* The Arm7Tdmi stack must be aligned at word (4 byte)
   * boundaries. If necessary top_of_stack must be rounded
   * down to the next boundary
   */

  top_of_stack &= ~3;
  size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4;

  /* Save the adjusted stack values in the _TCB */

  tcb->adj_stack_size = top_of_stack;
  tcb->adj_stack_size = size_of_stack;

  return OK;
}
Exemple #14
0
int rt_tbx_init(TBX *tbx, int size, int flags)
{
	if (!(tbx->bufadr = sched_malloc(size))) { 
		return -ENOMEM;
	}
	if (!(tbx->bcbadr = sched_malloc(size))) { 
		sched_free(tbx->bufadr);
		return -ENOMEM;
	}
	*tbx->bcbadr = TYPE_NONE;
	memset(tbx->bufadr, 0, size);
	memset(tbx->bcbadr, 0, size);
	rt_typed_sem_init(&(tbx->sndsmx), 1, CNT_SEM | flags);
	rt_typed_sem_init(&(tbx->rcvsmx), 1, CNT_SEM | flags);
	rt_typed_sem_init(&(tbx->bcbsmx), 1, BIN_SEM | flags);
	tbx->magic = RT_TBX_MAGIC;
	tbx->size = tbx->frbs = size;
	tbx->waiting_task = 0;
	tbx->waiting_nr = 0;
	spin_lock_init(&(tbx->buflock));
	tbx->fbyte = tbx->avbs = 0;
	return 0;
}
int sched_releasetcb(FAR _TCB *tcb)
{
  int ret = OK;
  int i;

  if (tcb)
    {
      /* Relase any timers that the task might hold.  We do this
       * before release the PID because it may still be trying to
       * deliver signals (although interrupts are should be
       * disabled here).
       */

#ifndef CONFIG_DISABLE_POSIX_TIMERS
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
     if (timer_deleteall != NULL)
#endif
        {
          timer_deleteall(tcb->pid);
        }
#endif

      /* Release the task's process ID if one was assigned.  PID
       * zero is reserved for the IDLE task.  The TCB of the IDLE
       * task is never release so a value of zero simply means that
       * the process ID was never allocated to this TCB.
       */

      if (tcb->pid)
        {
          sched_releasepid(tcb->pid);
        }

      /* Delete the thread's stack if one has been allocated */

#ifndef CONFIG_CUSTOM_STACK
      if (tcb->stack_alloc_ptr)
        {
          up_release_stack(tcb);
        }
#endif

      /* Delete the tasks's allocated DSpace region (external modules only) */

#ifdef CONFIG_PIC
      if (tcb->dspace)
        {
          if (tcb->dspace->crefs <= 1)
            {
              sched_free(tcb->dspace);
            }
          else
            {
              tcb->dspace->crefs--;
            }
        }
#endif

      /* Release command line arguments that were allocated for task
       * start/re-start.
       */

      if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
        {
          for (i = 1; i < CONFIG_MAX_TASK_ARGS+1 && tcb->argv[i]; i++)
            {
              sched_free((FAR void*)tcb->argv[i]);
            }
        }

      /* Release any allocated file structures */

      ret = sched_releasefiles(tcb);

      /* Release environment variables */

      (void)env_release(tcb);

      /* And, finally, release the TCB itself */

      sched_free(tcb);
    }
  return ret;
}
Exemple #16
0
int up_create_stack(_TCB *tcb, size_t stack_size)
{
  if (tcb->stack_alloc_ptr &&
      tcb->adj_stack_size != stack_size)
    {
      sched_free(tcb->stack_alloc_ptr);
      tcb->stack_alloc_ptr = NULL;
    }

  if (!tcb->stack_alloc_ptr)
    {
#ifdef CONFIG_DEBUG
      tcb->stack_alloc_ptr = (uint32_t*)kzalloc(stack_size);
#else
      tcb->stack_alloc_ptr = (uint32_t*)kmalloc(stack_size);
#endif
    }

  if (tcb->stack_alloc_ptr)
    {
      size_t top_of_stack;
      size_t size_of_stack;

      /* The ARM uses a push-down stack:  the stack grows toward lower
       * addresses in memory.  The stack pointer register, points to
       * the lowest, valid work address (the "top" of the stack).  Items
       * on the stack are referenced as positive word offsets from sp.
       */

      top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4;

      /* The ARM stack must be aligned; 4 byte alignment for OABI and
       * 8-byte alignment for EABI. If necessary top_of_stack must be
       * rounded down to the next boundary
       */

      top_of_stack = STACK_ALIGN_DOWN(top_of_stack);

      /* The size of the stack in bytes is then the difference between
       * the top and the bottom of the stack (+4 because if the top
       * is the same as the bottom, then the size is one 32-bit element).
       * The size need not be aligned.
       */

      size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4;

      /* Save the adjusted stack values in the _TCB */

      tcb->adj_stack_ptr  = (uint32_t*)top_of_stack;
      tcb->adj_stack_size = size_of_stack;

      /* If stack debug is enabled, then fill the stack with a
       * recognizable value that we can use later to test for high
       * water marks.
       */

#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_STACK)
      memset32(tcb->stack_alloc_ptr, 0xDEADBEEF, tcb->adj_stack_size/4);
#endif

      up_ledon(LED_STACKCREATED);
      return OK;
    }

   return ERROR;
}
Exemple #17
0
int up_create_stack(_TCB *tcb, size_t stack_size)
{
  /* Is there already a stack allocated of a different size? */

  if (tcb->stack_alloc_ptr && tcb->adj_stack_size != stack_size)
    {
      /* Yes.. free it */

      sched_free(tcb->stack_alloc_ptr);
      tcb->stack_alloc_ptr = NULL;
    }

   /* Do we need to allocate a stack? */
 
   if (!tcb->stack_alloc_ptr)
     {
       /* Allocate the stack.  If DEBUG is enabled (but not stack debug),
        * then create a zeroed stack to make stack dumps easier to trace.
        */

#if defined(CONFIG_DEBUG) && !defined(CONFIG_DEBUG_STACK)
       tcb->stack_alloc_ptr = (FAR void *)zalloc(stack_size);
#else
       tcb->stack_alloc_ptr = (FAR void *)malloc(stack_size);
#endif
     }

   /* Did we successfully allocate a stack? */

   if (tcb->stack_alloc_ptr)
     {
       size_t top_of_stack;

       /* Yes.. If stack debug is enabled, then fill the stack with a
        * recognizable value that we can use later to test for high
        * water marks.
        */

#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_STACK)
       memset(tcb->stack_alloc_ptr, 0xaa, stack_size);
#endif

       /* The AVR uses a push-down stack:  the stack grows toward lower
        * addresses in memory.  The stack pointer register, points to the
        * lowest, valid work address (the "top" of the stack).  Items on the
        * stack are referenced as positive word offsets from sp.
        */

       top_of_stack = (size_t)tcb->stack_alloc_ptr + stack_size - 1;

       /* Save the adjusted stack values in the _TCB */

       tcb->adj_stack_ptr  = (FAR void *)top_of_stack;
       tcb->adj_stack_size = stack_size;

       up_ledon(LED_STACKCREATED);
       return OK;
     }

   return ERROR;
}
Exemple #18
0
/* sched_alloc(): allocate and populate a schedule data structure
 * from a file, specified with a filename string.
 *
 * arguments:
 *  @fname: filename of the input schedule to read.
 *
 * returns:
 *  pointer to a newly allocated and populated schedule structure,
 *  or NULL on failure.
 */
sched *sched_alloc (const char *fname) {
  /* declare required variables:
   *  @sch: pointer to the newly allocated schedule structure.
   *  @buf: character buffer to hold each line of schedule text.
   *  @i1, @i2, @i3: parsed grid indices.
   *  @dscan: number of parsed indices.
   *  @fh: input file handle.
   */
  int dscan, i1, i2, i3;
  char buf[N_BUF];
  sched *sch;
  FILE *fh;

  /* allocate a new structure pointer. */
  sch = (sched*) malloc(sizeof(sched));
  if (!sch) {
    /* if unsuccessful, output an error message and return. */
    failf("failed to allocate schedule pointer");
    return NULL;
  }

  /* initialize the contents of the structure. */
  sch->idx = NULL;
  sch->w = NULL;
  sch->n = 0;
  sch->d = 0;
  sch->n1 = 0;
  sch->n2 = 0;
  sch->n3 = 0;

  /* check that the input filename is defined. */
  if (!fname) {
    /* if not, output an error message and return. */
    failf("schedule filename not supplied");
    sched_free(sch);
    return NULL;
  }

  /* open the input file. */
  fh = fopen(fname, "r");
  if (!fh) {
    /* if unsuccessful, output an error message and return. */
    failf("failed to open schedule file '%s'", fname);
    sched_free(sch);
    return NULL;
  }

  /* attempt to read the first line of text from the schedule. */
  if (!fgets(buf, N_BUF, fh)) {
    /* if unsuccessful, output an error message and return. */
    failf("failed to read from '%s'", fname);
    sched_free(sch);
    fclose(fh);
    return NULL;
  }

  /* check for the line format of each dimensionality. */
  if (sscanf(buf, FMT_3D, &i1, &i2, &i3) == 3) {
    /* set three dimensions. */
    sch->d = 3;
  }
  else if (sscanf(buf, FMT_2D, &i1, &i2) == 2) {
    /* set two dimensions. */
    sch->d = 2;
  }
  else if (sscanf(buf, FMT_1D, &i1) == 1) {
    /* set one dimension. */
    sch->d = 1;
  }

  /* check for a sane dimensionality. */
  if (sch->d == 0) {
    /* if not sane, output an error message and return. */
    failf("failed to determine schedule dimensionality");
    sched_free(sch);
    fclose(fh);
    return NULL;
  }

  /* seek back to the beginning of the schedule file. */
  if (fseek(fh, SEEK_SET, 0)) {
    /* if unsuccessful, output an error message and return. */
    failf("failed to seek within the schedule file");
    sched_free(sch);
    fclose(fh);
    return NULL;
  }

  /* loop until the end of the schedule file is reached. */
  while (!feof(fh)) {
    /* read a new line of text from the schedule file. */
    if (fgets(buf, N_BUF, fh)) {
      /* initialize the indices. */
      i1 = i2 = i3 = 0;

      /* parse based on the dimensionality. */
      switch (sch->d) {
        /* one-dimensional. */
        case 1:
          dscan = sscanf(buf, FMT_1D, &i1);
          break;

        /* two-dimensional. */
        case 2:
          dscan = sscanf(buf, FMT_2D, &i1, &i2);
          break;

        /* three-dimensional. */
        case 3:
          dscan = sscanf(buf, FMT_3D, &i1, &i2, &i3);
          break;

        /* else. won't happen. */
        default:
          dscan = 0;
          break;
      }

      /* check for a successful parse. */
      if (dscan != sch->d) {
        /* if not, output an error message and return. */
        failf("failed to parse line %d of '%s'", sch->n + 1, fname);
        sched_free(sch);
        fclose(fh);
        return NULL;
      }

      /* reallocate the index array. */
      sch->n++;
      sch->idx = (int*) realloc(sch->idx, 3 * sch->n * sizeof(int));
      if (!sch->idx) {
        /* if unsuccessful, output an error message and return. */
        failf("failed to reallocate schedule array");
        sched_free(sch);
        fclose(fh);
        return NULL;
      }

      /* store the parsed indices. */
      sch->idx[3 * (sch->n - 1) + 0] = i1;
      sch->idx[3 * (sch->n - 1) + 1] = i2;
      sch->idx[3 * (sch->n - 1) + 2] = i3;

      /* update the maximum grid indices. */
      if (i1 > sch->n1) sch->n1 = i1;
      if (i2 > sch->n2) sch->n2 = i2;
      if (i3 > sch->n3) sch->n3 = i3;
    }
  }

  /* transform the maximum grid indices into sizes. */
  if (sch->d >= 1) sch->n1++;
  if (sch->d >= 2) sch->n2++;
  if (sch->d >= 3) sch->n3++;

  /* close the input file handle. */
  fclose(fh);

  /* return the allocated and prepared structure pointer. */
  return sch;
}
Exemple #19
0
int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
                   pthread_startroutine_t start_routine, pthread_addr_t arg)
{
  FAR _TCB *ptcb;
  FAR join_t *pjoin;
  int status;
  int priority;
#if CONFIG_RR_INTERVAL > 0
  int policy;
#endif
  pid_t pid;

  /* If attributes were not supplied, use the default attributes */

  if (!attr)
    {
      attr = &g_default_pthread_attr;
    }

  /* Allocate a TCB for the new task. */

  ptcb = (FAR _TCB*)kzalloc(sizeof(_TCB));
  if (!ptcb)
    {
      return ENOMEM;
    }

  /* Associate file descriptors with the new task */

  status = sched_setuppthreadfiles(ptcb);
  if (status != OK)
    {
      sched_releasetcb(ptcb);
      return status;
    }

  /* Share the parent's envionment */

  (void)env_share(ptcb);

  /* Allocate a detachable structure to support pthread_join logic */

  pjoin = (FAR join_t*)kzalloc(sizeof(join_t));
  if (!pjoin)
    {
      sched_releasetcb(ptcb);
      return ENOMEM;
    }

  /* Allocate the stack for the TCB */

  status = up_create_stack(ptcb, attr->stacksize);
  if (status != OK)
    {
      sched_releasetcb(ptcb);
      sched_free(pjoin);
      return ENOMEM;
    }

  /* Should we use the priority and scheduler specified in the
   * pthread attributes?  Or should we use the current thread's
   * priority and scheduler?
   */

  if (attr->inheritsched == PTHREAD_INHERIT_SCHED)
    {
      /* Get the priority for this thread. */

      struct sched_param param;
      status = sched_getparam(0, &param);
      if (status == OK)
        {
          priority = param.sched_priority;
        }
      else
        {
          priority = SCHED_FIFO;
        }

      /* Get the scheduler policy for this thread */

#if CONFIG_RR_INTERVAL > 0
      policy = sched_getscheduler(0);
      if (policy == ERROR)
        {
          policy = SCHED_FIFO;
        }
#endif
    }
  else
    {
      /* Use the priority and scheduler from the attributes */

      priority = attr->priority;
#if CONFIG_RR_INTERVAL > 0
      policy   = attr->policy;
#endif
    }

  /* Mark this task as a pthread (this setting will be needed in
   * task_schedsetup() when up_initial_state() is called.
   */

  ptcb->flags |= TCB_FLAG_TTYPE_PTHREAD;

  /* Initialize the task control block */

  status  = task_schedsetup(ptcb, priority, pthread_start,
                            (main_t)start_routine);
  if (status != OK)
    {

      sched_releasetcb(ptcb);
      sched_free(pjoin);
      return EBUSY;
    }

  /* Configure the TCB for a pthread receiving on parameter
   * passed by value
   */

  pthread_argsetup(ptcb, arg);

  /* Attach the join info to the TCB. */

  ptcb->joininfo = (void*)pjoin;

  /* If round robin scheduling is selected, set the appropriate flag
   * in the TCB.
   */

#if CONFIG_RR_INTERVAL > 0
  if (policy == SCHED_RR)
    {
      ptcb->flags    |= TCB_FLAG_ROUND_ROBIN;
      ptcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK;
    }
#endif

  /* Get the assigned pid before we start the task (who knows what
   * could happen to ptcb after this!).  Copy this ID into the join structure
   * as well.
   */

  pid = (int)ptcb->pid;
  pjoin->thread = (pthread_t)pid;

  /* Initialize the semaphores in the join structure to zero. */

  status = sem_init(&pjoin->data_sem, 0, 0);
  if (status == OK)
    {
      status = sem_init(&pjoin->exit_sem, 0, 0);
    }

  /* Activate the task */

  sched_lock();
  if (status == OK)
    {
      status = task_activate(ptcb);
    }

  if (status == OK)
    {
      /* Wait for the task to actually get running and to register
       * its join_t
       */

      (void)pthread_takesemaphore(&pjoin->data_sem);

      /* Return the thread information to the caller */

      if (thread) *thread = (pthread_t)pid;
      if (!pjoin->started) status = ERROR;

      sched_unlock();
      (void)sem_destroy(&pjoin->data_sem);
    }
  else
    {
      sched_unlock();
      dq_rem((FAR dq_entry_t*)ptcb, (dq_queue_t*)&g_inactivetasks);
      (void)sem_destroy(&pjoin->data_sem);
      (void)sem_destroy(&pjoin->exit_sem);
      sched_releasetcb(ptcb);
      sched_free(pjoin);
      return EIO;
    }

  return OK;
}