Esempio n. 1
0
static void test_readwrite_start(int n)
{
	rw_task_finished = 0;
	
	sem_initialize(&sem_rw, 1);
	
	mtx_initialize(&mtx_rw);

	taskrw[0] = task_create("tRA", task_reader, &n, NULL, 0x1000, 220, 10, 0);
	task_resume_noschedule(taskrw[0]);

	taskrw[1] = task_create("tRB", task_reader, &n, NULL, 0x1000, 220, 10, 0);
	task_resume_noschedule(taskrw[1]);

	taskrw[2] = task_create("tRC", task_reader, &n, NULL, 0x1000, 220, 10, 0);
	task_resume_noschedule(taskrw[2]);

	taskrw[3] = task_create("tWA", task_writer, &n, NULL, 0x1000, 220, 10, 0);
	task_resume_noschedule(taskrw[3]);

	/* wait test task to exit */
	printf("Reader/Writer started\n");
	while(rw_task_finished < 4) task_delay(50);
	printf("Reader/Writer finished\n");
}
Esempio n. 2
0
File: server.c Progetto: ertesh/SO
int main()
{
  if ( (shmid = shmget(SHMKEY, sizeof(Mesg), PERMS | IPC_CREAT)) < 0)
    syserr("server: can't get shared memory");
  if ( (mesgptr = (Mesg *) shmat(shmid, (char *) 0, 0)) == (Mesg *) -1)
    syserr("server: can't attach shared memory");
  if ( (clisem = sem_initialize(SEMKEY1, IPC_CREAT)) < 0)
    syserr("server: can't create client semaphore");
  if ( (servsem = sem_initialize(SEMKEY2, IPC_CREAT)) < 0)
    syserr("server: can't create server semaphore");

  V(clisem);
  server();
  if (shmdt(mesgptr) < 0)
    syserr("server: can't detach shared memory");
  exit(0);
}
Esempio n. 3
0
/// Create and Initialize a Semaphore object used for managing resources.
/// \param[in]     semaphore_def semaphore definition referenced with \ref osSemaphore.
/// \param[in]     count         number of available resources.
/// \return semaphore ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osSemaphoreCreate shall be consistent in every CMSIS-RTOS.
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count)
{
    sem_t *sem;

    sem = (sem_t *)malloc(sizeof(sem_t));
    sem_initialize(sem, count);

    return sem;
}
Esempio n. 4
0
/** Create a new semaphore
 * @param sem pointer to the semaphore to create
 * @param count initial count of the semaphore
 * @return ERR_OK if successful, another err_t otherwise 
 *
 * Creates a new semaphore returns it through the sem pointer provided as argument to the function, in addition 
 * the function returns ERR_MEM if a new semaphore could not be created and ERR_OK if the semaphore was created. 
 * The count argument specifies the initial state of the semaphore. 
 */
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
{
	int ret;
	
	ret = sem_initialize(sem, count);
	if(ret == ROK)
		return ERR_OK;
	else
		return ERR_MEM;
}
Esempio n. 5
0
void initialize_standby()
{
    //creates the semaphore
    //sets pointers in list to NULL;
    standby_list = NULL;
    standby_tail = NULL;
    standby_size = 0;
    sem_initialize(&standby_sem,1);
    return;
} 
Esempio n. 6
0
File: client.c Progetto: ertesh/SO
int main()
{
  if ( (shmid = shmget(SHMKEY, sizeof(Mesg), 0)) < 0)
    syserr("client: can't get shared memory segment");
  if ( (mesgptr = (Mesg *) shmat(shmid, 0, 0)) == (Mesg *) -1)
    syserr("client: can't attach shared memory segment");

  if ( (clisem = sem_initialize(SEMKEY1, IPC_CREAT)) < 0)
    syserr("client: can't open client semaphore");
  if ( (servsem = sem_initialize(SEMKEY2, IPC_CREAT)) < 0)
    syserr("client: can't open server semaphore");

  client();

  if (shmdt(mesgptr) < 0)
    syserr("client: can't detach shared memory");
  if (shmctl(shmid, IPC_RMID, 0) < 0)
    syserr("client: can't remove shared memory");

  sem_done(clisem);		/* will remove the semaphore */
  sem_done(servsem);  		/* will remove the semaphore */

  return 0;
}
Esempio n. 7
0
static void test_ipctimeout0_start()
{
	task_t tt;
	
	sem_initialize(&sem_timeout0, 1);
	
	tt = task_create("taskA", task_ipctimeout0_taskA, NULL, NULL, 0x1000, 220, 0, 0);
	assert(tt != RERROR);
	task_resume_noschedule(tt);

	tt = task_create("taskB", task_ipctimeout0_taskB, NULL, NULL, 0x1000, 220, 0, 0);
	assert(tt != RERROR);
	task_resume_noschedule(tt);

	task_delay(500);
}
Esempio n. 8
0
static void test_destroyipc_start()
{
	task_t taskA, taskB;

	sem_initialize(&sem_destroyipc, 1);

	taskA = task_create("ttaskA", task_destroyipc_taskA, NULL, NULL, 0x1000, 150, 0, 0);
	task_resume_noschedule(taskA);
	taskB = task_create("ttaskB", task_destroyipc_taskB, NULL, NULL, 0x1000, 150, 0, 0);
	task_resume_noschedule(taskB);

	task_delay(200);
	sem_destroy(&sem_destroyipc);

	task_delay(300);
	task_destroy(taskA);
	task_destroy(taskB);
}
Esempio n. 9
0
void os_start(void)
{
  int i;

  slldbg("Entry\n");

  /* Initialize all task lists */

  dq_init(&g_readytorun);
  dq_init(&g_pendingtasks);
  dq_init(&g_waitingforsemaphore);
#ifndef CONFIG_DISABLE_SIGNALS
  dq_init(&g_waitingforsignal);
#endif
#ifndef CONFIG_DISABLE_MQUEUE
  dq_init(&g_waitingformqnotfull);
  dq_init(&g_waitingformqnotempty);
#endif
#ifdef CONFIG_PAGING
  dq_init(&g_waitingforfill);
#endif
  dq_init(&g_inactivetasks);
  sq_init(&g_delayeddeallocations);

  /* Initialize the logic that determine unique process IDs. */

  g_lastpid = 0;
  for (i = 0; i < CONFIG_MAX_TASKS; i++)
    {
      g_pidhash[i].tcb = NULL;
      g_pidhash[i].pid = INVALID_PROCESS_ID;
    }

  /* Assign the process ID of ZERO to the idle task */

  g_pidhash[ PIDHASH(0)].tcb = &g_idletcb;
  g_pidhash[ PIDHASH(0)].pid = 0;

  /* Initialize a TCB for this thread of execution.  NOTE:  The default
   * value for most components of the g_idletcb are zero.  The entire
   * structure is set to zero.  Then only the (potentially) non-zero
   * elements are initialized. NOTE:  The idle task is the only task in
   * that has pid == 0 and sched_priority == 0.
   */

  bzero((void*)&g_idletcb, sizeof(_TCB));
  g_idletcb.task_state = TSTATE_TASK_RUNNING;
  g_idletcb.entry.main = (main_t)os_start;

#if CONFIG_TASK_NAME_SIZE > 0
  strncpy(g_idletcb.name, g_idlename, CONFIG_TASK_NAME_SIZE-1);
  g_idletcb.argv[0] = g_idletcb.name;
#else
  g_idletcb.argv[0] = (char*)g_idlename;
#endif /* CONFIG_TASK_NAME_SIZE */

  /* Then add the idle task's TCB to the head of the ready to run list */

  dq_addfirst((FAR dq_entry_t*)&g_idletcb, (FAR dq_queue_t*)&g_readytorun);

  /* Initialize the processor-specific portion of the TCB */

  g_idletcb.flags = TCB_FLAG_TTYPE_KERNEL;
  up_initial_state(&g_idletcb);

  /* Initialize the semaphore facility(if in link).  This has to be done
   * very early because many subsystems depend upon fully functional
   * semaphores.
   */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (sem_initialize != NULL)
#endif
    {
      sem_initialize();
    }

  /* Initialize the memory manager */

#ifndef CONFIG_HEAP_BASE
  {
    FAR void *heap_start;
    size_t heap_size;
    up_allocate_heap(&heap_start, &heap_size);
    kmm_initialize(heap_start, heap_size);
  }
#else
  kmm_initialize((void*)CONFIG_HEAP_BASE, CONFIG_HEAP_SIZE);
#endif

  /* Initialize the interrupt handling subsystem (if included) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (irq_initialize != NULL)
#endif
    {
      irq_initialize();
    }

  /* Initialize the watchdog facility (if included in the link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (wd_initialize != NULL)
#endif
    {
      wd_initialize();
    }

  /* Initialize the POSIX timer facility (if included in the link) */

#ifndef CONFIG_DISABLE_CLOCK
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (clock_initialize != NULL)
#endif
    {
      clock_initialize();
    }
#endif

#ifndef CONFIG_DISABLE_POSIX_TIMERS
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (timer_initialize != NULL)
#endif
    {
      timer_initialize();
    }
#endif

  /* Initialize the signal facility (if in link) */

#ifndef CONFIG_DISABLE_SIGNALS
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (sig_initialize != NULL)
#endif
    {
      sig_initialize();
    }
#endif

  /* Initialize the named message queue facility (if in link) */

#ifndef CONFIG_DISABLE_MQUEUE
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (mq_initialize != NULL)
#endif
    {
      mq_initialize();
    }
#endif

  /* Initialize the thread-specific data facility (if in link) */

#ifndef CONFIG_DISABLE_PTHREAD
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (pthread_initialize != NULL)
#endif
    {
      pthread_initialize();
    }
#endif

  /* Initialize the file system (needed to support device drivers) */

#if CONFIG_NFILE_DESCRIPTORS > 0
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (fs_initialize != NULL)
#endif
    {
      fs_initialize();
    }
#endif

  /* Initialize the network system */

#ifdef CONFIG_NET
#if 0
  if (net_initialize != NULL)
#endif
    {
      net_initialize();
    }
#endif

  /* The processor specific details of running the operating system
   * will be handled here.  Such things as setting up interrupt
   * service routines and starting the clock are some of the things
   * that are different for each  processor and hardware platform.
   */

  up_initialize();

  /* Initialize the C libraries (if included in the link).  This
   * is done last because the libraries may depend on the above.
   */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (lib_initialize != NULL)
#endif
    {
      lib_initialize();
    }

  /* Create stdout, stderr, stdin on the IDLE task.  These will be
   * inherited by all of the threads created by the IDLE task.
   */

  (void)sched_setupidlefiles(&g_idletcb);

  /* Create initial tasks and bring-up the system */

  (void)os_bringup();

  /* When control is return to this point, the system is idle. */

  sdbg("Beginning Idle Loop\n");
  for (;;)
    {
      /* Perform garbage collection (if it is not being done by the worker
       * thread).  This cleans-up memory de-allocations that were queued
       * because they could not be freed in that execution context (for
       * example, if the memory was freed from an interrupt handler).
       */

#ifndef CONFIG_SCHED_WORKQUEUE
      /* We must have exclusive access to the memory manager to do this
       * BUT the idle task cannot wait on a semaphore.  So we only do
       * the cleanup now if we can get the semaphore -- this should be
       * possible because if the IDLE thread is running, no other task is!
       */

      if (kmm_trysemaphore() == 0)
        {
          sched_garbagecollection();
          kmm_givesemaphore();
        }
#endif

      /* Perform any processor-specific idle state operations */

      up_idle();
    }
}
Esempio n. 10
0
void os_start(void)
{
  int i;

  slldbg("Entry\n");

  /* Initialize RTOS Data ***************************************************/
  /* Initialize all task lists */

  dq_init(&g_readytorun);
  dq_init(&g_pendingtasks);
  dq_init(&g_waitingforsemaphore);
#ifndef CONFIG_DISABLE_SIGNALS
  dq_init(&g_waitingforsignal);
#endif
#ifndef CONFIG_DISABLE_MQUEUE
  dq_init(&g_waitingformqnotfull);
  dq_init(&g_waitingformqnotempty);
#endif
#ifdef CONFIG_PAGING
  dq_init(&g_waitingforfill);
#endif
  dq_init(&g_inactivetasks);
  sq_init(&g_delayed_kufree);
#if (defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)) && \
     defined(CONFIG_MM_KERNEL_HEAP)
  sq_init(&g_delayed_kfree);
#endif

  /* Initialize the logic that determine unique process IDs. */

  g_lastpid = 0;
  for (i = 0; i < CONFIG_MAX_TASKS; i++)
    {
      g_pidhash[i].tcb = NULL;
      g_pidhash[i].pid = INVALID_PROCESS_ID;
    }

  /* Assign the process ID of ZERO to the idle task */

  g_pidhash[PIDHASH(0)].tcb = &g_idletcb.cmn;
  g_pidhash[PIDHASH(0)].pid = 0;

  /* Initialize the IDLE task TCB *******************************************/
  /* Initialize a TCB for this thread of execution.  NOTE:  The default
   * value for most components of the g_idletcb are zero.  The entire
   * structure is set to zero.  Then only the (potentially) non-zero
   * elements are initialized. NOTE:  The idle task is the only task in
   * that has pid == 0 and sched_priority == 0.
   */

  bzero((void*)&g_idletcb, sizeof(struct task_tcb_s));
  g_idletcb.cmn.task_state = TSTATE_TASK_RUNNING;
  g_idletcb.cmn.entry.main = (main_t)os_start;
  g_idletcb.cmn.flags      = TCB_FLAG_TTYPE_KERNEL;

  /* Set the IDLE task name */

#if CONFIG_TASK_NAME_SIZE > 0
  strncpy(g_idletcb.cmn.name, g_idlename, CONFIG_TASK_NAME_SIZE);
  g_idletcb.cmn.name[CONFIG_TASK_NAME_SIZE] = '\0';
#endif /* CONFIG_TASK_NAME_SIZE */

  /* Configure the task name in the argument list.  The IDLE task does
   * not really have an argument list, but this name is still useful
   * for things like the NSH PS command.
   *
   * In the kernel mode build, the arguments are saved on the task's stack
   * and there is no support that yet.
   */

#if CONFIG_TASK_NAME_SIZE > 0
  g_idleargv[0]  = g_idletcb.cmn.name;
#else
  g_idleargv[0]  = (FAR char *)g_idlename;
#endif /* CONFIG_TASK_NAME_SIZE */
  g_idleargv[1]  = NULL;
  g_idletcb.argv = g_idleargv;

  /* Then add the idle task's TCB to the head of the ready to run list */

  dq_addfirst((FAR dq_entry_t*)&g_idletcb, (FAR dq_queue_t*)&g_readytorun);

  /* Initialize the processor-specific portion of the TCB */

  up_initial_state(&g_idletcb.cmn);

  /* Initialize RTOS facilities *********************************************/
  /* Initialize the semaphore facility.  This has to be done very early
   * because many subsystems depend upon fully functional semaphores.
   */

  sem_initialize();

#if defined(MM_KERNEL_USRHEAP_INIT) || defined(CONFIG_MM_KERNEL_HEAP) || defined(CONFIG_MM_PGALLOC)
  /* Initialize the memory manager */

  {
    FAR void *heap_start;
    size_t heap_size;

#ifdef MM_KERNEL_USRHEAP_INIT
    /* Get the user-mode heap from the platform specific code and configure
     * the user-mode memory allocator.
     */

    up_allocate_heap(&heap_start, &heap_size);
    kumm_initialize(heap_start, heap_size);
#endif

#ifdef CONFIG_MM_KERNEL_HEAP
    /* Get the kernel-mode heap from the platform specific code and configure
     * the kernel-mode memory allocator.
     */

    up_allocate_kheap(&heap_start, &heap_size);
    kmm_initialize(heap_start, heap_size);
#endif

#ifdef CONFIG_MM_PGALLOC
    /* If there is a page allocator in the configuration, then get the page
     * heap information from the platform-specific code and configure the
     * page allocator.
     */

    up_allocate_pgheap(&heap_start, &heap_size);
    mm_pginitialize(heap_start, heap_size);
#endif
  }
#endif

#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
  /* Initialize tasking data structures */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (task_initialize != NULL)
#endif
    {
      task_initialize();
    }
#endif

  /* Initialize the interrupt handling subsystem (if included) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (irq_initialize != NULL)
#endif
    {
      irq_initialize();
    }

  /* Initialize the watchdog facility (if included in the link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (wd_initialize != NULL)
#endif
    {
      wd_initialize();
    }

  /* Initialize the POSIX timer facility (if included in the link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (clock_initialize != NULL)
#endif
    {
      clock_initialize();
    }

#ifndef CONFIG_DISABLE_POSIX_TIMERS
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (timer_initialize != NULL)
#endif
    {
      timer_initialize();
    }
#endif

#ifndef CONFIG_DISABLE_SIGNALS
  /* Initialize the signal facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (sig_initialize != NULL)
#endif
    {
      sig_initialize();
    }
#endif

#ifndef CONFIG_DISABLE_MQUEUE
  /* Initialize the named message queue facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (mq_initialize != NULL)
#endif
    {
      mq_initialize();
    }
#endif

#ifndef CONFIG_DISABLE_PTHREAD
  /* Initialize the thread-specific data facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (pthread_initialize != NULL)
#endif
    {
      pthread_initialize();
    }
#endif

#if CONFIG_NFILE_DESCRIPTORS > 0
  /* Initialize the file system (needed to support device drivers) */

  fs_initialize();
#endif

#ifdef CONFIG_NET
  /* Initialize the networking system.  Network initialization is
   * performed in two steps:  (1) net_setup() initializes static
   * configuration of the network support.  This must be done prior
   * to registering network drivers by up_initialize().  This step
   * cannot require upon any hardware-depending features such as
   * timers or interrupts.
   */

  net_setup();
#endif

  /* The processor specific details of running the operating system
   * will be handled here.  Such things as setting up interrupt
   * service routines and starting the clock are some of the things
   * that are different for each  processor and hardware platform.
   */

  up_initialize();

#ifdef CONFIG_NET
  /* Complete initialization the networking system now that interrupts
   * and timers have been configured by up_initialize().
   */

  net_initialize();
#endif

#ifdef CONFIG_MM_SHM
  /* Initialize shared memory support */

  shm_initialize();
#endif

  /* Initialize the C libraries.  This is done last because the libraries
   * may depend on the above.
   */

  lib_initialize();

  /* IDLE Group Initialization **********************************************/
#ifdef HAVE_TASK_GROUP
  /* Allocate the IDLE group */

  DEBUGVERIFY(group_allocate(&g_idletcb, g_idletcb.cmn.flags));
#endif

#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
  /* Create stdout, stderr, stdin on the IDLE task.  These will be
   * inherited by all of the threads created by the IDLE task.
   */

  DEBUGVERIFY(group_setupidlefiles(&g_idletcb));
#endif

#ifdef HAVE_TASK_GROUP
  /* Complete initialization of the IDLE group.  Suppress retention
   * of child status in the IDLE group.
   */

  DEBUGVERIFY(group_initialize(&g_idletcb));
  g_idletcb.cmn.group->tg_flags = GROUP_FLAG_NOCLDWAIT;
#endif

  /* Bring Up the System ****************************************************/
  /* Create initial tasks and bring-up the system */

  DEBUGVERIFY(os_bringup());

  /* The IDLE Loop **********************************************************/
  /* When control is return to this point, the system is idle. */

  sdbg("Beginning Idle Loop\n");
  for (;;)
    {
      /* Perform garbage collection (if it is not being done by the worker
       * thread).  This cleans-up memory de-allocations that were queued
       * because they could not be freed in that execution context (for
       * example, if the memory was freed from an interrupt handler).
       */

#ifndef CONFIG_SCHED_WORKQUEUE
      /* We must have exclusive access to the memory manager to do this
       * BUT the idle task cannot wait on a semaphore.  So we only do
       * the cleanup now if we can get the semaphore -- this should be
       * possible because if the IDLE thread is running, no other task is!
       *
       * WARNING: This logic could have undesirable side-effects if priority
       * inheritance is enabled.  Imaginee the possible issues if the
       * priority of the IDLE thread were to get boosted!  Moral: If you
       * use priority inheritance, then you should also enable the work
       * queue so that is done in a safer context.
       */

      if (kmm_trysemaphore() == 0)
        {
          sched_garbagecollection();
          kmm_givesemaphore();
        }
#endif

      /* Perform any processor-specific idle state operations */

      up_idle();
    }
}
Esempio n. 11
0
main(int argc,char **argv)
{
	int ret;
	char *chartoop;
	int chances = 10;
	int delay;

	if(argv[1])
		chartoop = "firstprocess ";
	else
		chartoop = "secondprocess ";

	sem_id = semget((key_t)1001,1,0700|IPC_CREAT);

	if(sem_id == -1)
	{
		perror("System call semget(for semget) failed");
		exit(EXIT_FAILURE);
	}

   printf( "got sem_id.. :%d:\n", sem_id) ;

	if(argv[1])
	{
      printf( "initialized..\n" ) ;
		ret = sem_initialize(1);

		if(ret == -1)
		{
			perror("System call semctl(for initialize) failed");
			exit(EXIT_FAILURE);
		}
	}

   system( "stty -icanon" ) ; // non-block mode
	while(chances--)
	{
      //printf( "b4 sem_getacess semval is :%d:\n" , semctl(sem_id,0,GETVAL)  ) ;

		if( sem_getacess() == -1 )
		{
			perror("System call sem_op(for getting the access) failed");
         handle_delete() ;
		}

      printf( "%s LOCKED semaphore..\n" , chartoop ) ;
      //printf( "semval is :%d:\n" , semctl(sem_id,0,GETVAL)  ) ; fflush(0) ;
      while( getchar() != EXIT_WHILE_CHAR ) ;

		ret = sem_giveupaccess();
      printf( "%s UNLOCKED semaphore..\n" , chartoop ) ;
      //printf( "after sem_giveupaccess semval is :%d:\n" , semctl(sem_id,0,GETVAL)  ) ;

		if(ret == -1)
		{
			perror("System call semop(for giveupaccess) failed");
         handle_delete() ;
		}
	}

   system( "stty icanon" ) ;
	if(argv[1])
	{
		sleep(1);
      handle_delete() ;
	}

	exit(EXIT_SUCCESS);
}
Esempio n. 12
0
static void test_prodcons_start(int n)
{
	task_t tt;
	int i;
	struct pctest_list *node;

	pc_finished_tasks = 0;

	/* initialize list */
	pclist1 = NULL;
	pclist2 = NULL;
	for(i=PC_LISTNODE_NUMBER-1; i>=0; i--)
	{
		SINGLE_LIST_INSERT(&pclist1, &pcarray[i]);
	}

	/* create ipc */
	sem_initialize(&sem_empty, PC_LISTNODE_NUMBER);

	sem_initialize(&sem_full, 0);

	sem_initialize(&mtx_pc, 1);

	/* create tasks */
	tt = task_create("tPA", task_product, &n, NULL, 0x1000, 220, 1, 0);
	assert(tt != RERROR);
	task_resume_noschedule(tt);

	tt = task_create("tPB", task_product, &n, NULL, 0x1000, 220, 1, 0);
	assert(tt != RERROR);
	task_resume_noschedule(tt);

	tt = task_create("tPC", task_product, &n, NULL, 0x1000, 220, 1, 0);
	assert(tt != RERROR);
	task_resume_noschedule(tt);

	tt = task_create("tCA", task_consume, &n, NULL, 0x1000, 220, 1, 0);
	assert(tt != RERROR);
	task_resume_noschedule(tt);

	tt = task_create("tCB", task_consume, &n, NULL, 0x1000, 220, 1, 0);
	assert(tt != RERROR);
	task_resume_noschedule(tt);

	tt = task_create("tCC", task_consume, &n, NULL, 0x1000, 220, 1, 0);
	assert(tt != RERROR);
	task_resume_noschedule(tt);

	printf("Producter/Consumer test started\n");

	/* wait test task to exit */
	while(pc_finished_tasks < 6) task_delay(50);
	
	printf("Producter/Consumer test finished\n");

	/* dump list */
	printf("elements in list1: ");
	node = pclist1;
	while(node)
	{
		printf("%d ", node->value);
		node = node ->next;
	}
	printf("\n");
	printf("elements in list2: ");
	node = pclist2;
	while(node)
	{
		printf("%d ", node->value);
		node = node ->next;
	}
	printf("\n");
}