示例#1
0
文件: main.c 项目: navaro/atomthreads
/**
 * \b main
 *
 * Initialize atomthreads and start a test_thread to run the Atomthreads test suite. 
 *
 */
int
main (void)
{
    uint32_t failures ;

    printf ("atomthreads starting %s... ", ATOMTHREADS_TEST) ;

    atomOSInit(&idle_stack[0], IDLE_STACK_BYTE_SIZE, TRUE) ;
    atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[0], TEST_STACK_BYTE_SIZE, TRUE);
    atomOSStart() ;

    return 0 ;
}
示例#2
0
/**
 * \b main
 *
 * Program entry point.
 *
 * Sets up the MicroBlaze hardware resources (system tick timer interrupt) necessary
 * for the OS to be started. Creates an application thread and starts the OS.
 */
int main ( void )
{
    int8_t status;

    ATOMLOG("\n\nAtomThreads MicroBlaze Starting\n\n");

    /**
     * Initialise the OS before creating our threads.
     */
    status = atomOSInit(&idle_thread_stack[0], IDLE_STACK_SIZE_BYTES, TRUE);
    if (status == ATOM_OK)
    {
        /* Enable the system tick timer */
        microblazeInitSystemTickTimer();

        /* Create an application thread */
        status = atomThreadCreate(&main_tcb,
                     TEST_THREAD_PRIO, main_thread_func, 0,
                     &main_thread_stack[0],
                     MAIN_STACK_SIZE_BYTES,
                     TRUE);

        if (status == ATOM_OK)
        {
            /**
             * First application thread successfully created. It is
             * now possible to start the OS. Execution will not return
             * from atomOSStart(), which will restore the context of
             * our application thread and start executing it.
             *
             * Note that interrupts are still disabled at this point.
             * They will be enabled as we restore and execute our first
             * thread in archFirstThreadRestore().
             */
            atomOSStart();
        }
    }

    while (1)
        ;

    /* There was an error starting the OS if we reach here */
    return (0);
}
示例#3
0
/**
 * \b atomOSInit
 *
 * Initialise the atomthreads OS.
 *
 * Must be called before any application code uses the atomthreads APIs. No
 * threads are actually started until the application calls atomOSStart().
 *
 * Callers must provide a pointer to some storage for the idle thread stack.
 * The caller is responsible for calculating the appropriate space required
 * for their particular architecture.
 *
 * Applications should use the following initialisation sequence:
 *
 * \li Call atomOSInit() before calling any atomthreads APIs
 * \li Arrange for a timer to call atomTimerTick() periodically
 * \li Create one or more application threads using atomThreadCreate()
 * \li Start the OS using atomOSStart(). At this point the highest
 *     priority application thread created will be started.
 *
 * Interrupts should be disabled until the first thread restore is complete,
 * to avoid any complications due to interrupts occurring while crucial
 * operating system facilities are being initialised. They are normally
 * enabled by the archFirstThreadRestore() routine in the architecture port.
 *
 * @param[in] idle_thread_stack_top Ptr to top of stack area for idle thread
 * @param[in] idle_thread_stack_size Size of idle thread stack in bytes
 *
 * @retval ATOM_OK Success
 * @retval ATOM_ERROR Initialisation error
 */
uint8_t atomOSInit (void *idle_thread_stack_top, uint32_t idle_thread_stack_size)
{
    uint8_t status;

    /* Initialise data */
    curr_tcb = NULL;
    tcbReadyQ = NULL;
    atomOSStarted = FALSE;

    /* Create the idle thread */
    status = atomThreadCreate(&idle_tcb,
                 IDLE_THREAD_PRIORITY,
                 atomIdleThread,
                 0,
                 idle_thread_stack_top,
                 idle_thread_stack_size);

    /* Return status */
    return (status);

}
int Sensordrv::start_thread()
{
  uint8_t status;

  if(is_running)
    {
      return -EBUSY;
    }

  status = atomThreadCreate(&(this -> tcb), DEFAULT_THREAD_PRIO,
                            this -> thread_func, 0,
                            thread_stack,
                            SENSORDRV_STACK_SIZE_BYTES, TRUE);

  if(ATOM_OK == status)
    {
      is_running = true;
      return 0;
    }
  else
    {
      return atom_err_to_errno(status);
    }
}
示例#5
0
/**
 * \b test_start
 *
 * Start mutex test.
 *
 * Stress-tests mutex Get and Put operations. Four threads are created which are
 * continually Getting and Putting the same mutex, with no time delays between
 * each Get/Put.
 *
 * @retval Number of g_failures
 */
uint32_t test_start (void)
{
    CRITICAL_STORE;
    int finish_cnt;

    /* Default to zero g_failures */
    g_failures = 0;

    /* Create mutex to stress */
    if (atomMutexCreate (&mutex1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating mutex\n"));
        g_failures++;
    }
    /* Create sem to receive thread-finished notification */
    else if (atomSemCreate (&sem1, 0) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating sem\n"));
        g_failures++;
    }
    else
    {
        /* Take ownership of the mutex to ensure all threads wait for now */
        if (atomMutexGet (&mutex1, 0) != ATOM_OK)
        {
            ATOMLOG (_STR("Error taking mutex\n"));
            g_failures++;
        }

        /* Create Thread 1 */
        if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1,
              &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
              TEST_THREAD_STACK_SIZE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            CRITICAL_START ();
            g_failures++;
            CRITICAL_END ();
        }

        /* Create Thread 2 */
        if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 2,
              &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1],
              TEST_THREAD_STACK_SIZE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            CRITICAL_START ();
            g_failures++;
            CRITICAL_END ();
        }

        /* Create Thread 3 */
        if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3,
              &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1],
              TEST_THREAD_STACK_SIZE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            CRITICAL_START ();
            g_failures++;
            CRITICAL_END ();
        }

        /* Create Thread 4 */
        if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4,
              &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1],
              TEST_THREAD_STACK_SIZE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            CRITICAL_START ();
            g_failures++;
            CRITICAL_END ();
        }

        /* Release ownership of the mutex to kick the threads off */
        if (atomMutexPut (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Error putting mutex\n"));
            g_failures++;
        }

        /*
         * All four threads will now be performing Gets/Puts on mutex1.
         * When they have finished they will post sem1, so we wait
         * until sem1 is posted four times.
         */
        finish_cnt = 0;
        while (1)
        {
            /*
             * Attempt to Get sem1. When we have managed to get
             * the semaphore four times, it must have been posted
             * by all four threads.
             */
            if (atomSemGet (&sem1, 0) == ATOM_OK)
            {
                /* Increment our count of finished threads */
                finish_cnt++;

                /* Check if all four threads have now posted sem1 */
                if (finish_cnt == 4)
                {
                    break;
                }
            }
        }

        /* Delete OS objects, test finished */
        if (atomMutexDelete (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Delete failed\n"));
            CRITICAL_START ();
            g_failures++;
            CRITICAL_END ();
        }
        if (atomSemDelete (&sem1) != ATOM_OK)
        {
            ATOMLOG (_STR("Delete failed\n"));
            CRITICAL_START ();
            g_failures++;
            CRITICAL_END ();
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                g_failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    g_failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return g_failures;

}
示例#6
0
/**
 * \b test_start
 *
 * Start queue test.
 *
 * With multiple threads blocking on a single queue, this test confirms that
 * they are woken in order when the queue is posted. The correct order for
 * waking is that the higher priority threads are woken first, followed by the
 * lower priority threads. Where multiple threads of the same priority are
 * waiting, the threads are woken in FIFO order (the order in which they started
 * waiting on the queue).
 *
 * To test this we create four threads which all wait on a single queue.
 * One pair of threads are running at high priority, with the other pair at a
 * lower priority:
 *
 * Thread 1: low prio thread A
 * Thread 2: low prio thread B
 * Thread 3: high prio thread A
 * Thread 4: high prio thread B
 *
 * The threads are forced to start blocking on the same queue in the
 * above order.
 *
 * We expect to see them woken up in the following order:
 *  3, 4, 1, 2
 *
 * This proves the multiple blocking thread ordering in terms of both
 * the priority-queueing and same-priority-FIFO-queueing.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures, count;
    uint8_t msg;

    /* Default to zero failures */
    failures = 0;

    /* Create empty queue */
    if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test q1\n"));
        failures++;
    }

    /* Start the threads */
    else
    {
        /*
         * The test threads all start by calling atomQueueGet() to receive
         * a message from the queue. Because the queue is empty, all test
         * threads should immediately block on the queue (until a message
         * is posted to it).
         */

        /* Create Thread 1 (lower priority thread A) */
        if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO+1, test_thread_func, 1,
              &test_thread_stack[0][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the queue */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 2 (lower priority thread B) */
        if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO+1, test_thread_func, 2,
              &test_thread_stack[1][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the queue */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 3 (higher priority thread A) */
        if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3,
              &test_thread_stack[2][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the queue */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 4 (higher priority thread B) */
        if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4,
              &test_thread_stack[3][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the queue */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* All four threads will now be blocking on queue1 */

        /*
         * Initialise wake count, used by threads to determine
         * what order they were woken in.
         */
        wake_cnt = 0;

        /* Loop waking all four threads */
        for (count = 0; count < 4; count++)
        {
            /*
             * Post a message to the queue. This will wake up one of the threads
             * blocking on it (because it is currently empty). That thread will
             * wake up, note the order at which it was woken, then go to sleep
             * forever leaving the queue empty again. This is done four times so
             * that all four threads are woken, noting their wake order.
             */
            msg = 0x66;
            if (atomQueuePut (&queue1, 0, &msg) != ATOM_OK)
            {
                ATOMLOG (_STR("Post fail\n"));
                failures++;
            }

            /*
             * Sleep to give the thread time to wake up and modify the shared
             * global data wake_cnt and wake_order[]. We deliberately do not
             * use a mutex for protecting access to this shared data, as we
             * are testing the queue module in isolation here.
             */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC / 4);

        }

        /* All four threads now woken up, check they woke in correct order */
        if ((wake_order[0] != 3) && (wake_order[1] != 4)
            && (wake_order[2] != 1) && (wake_order[3] != 2))
        {
            ATOMLOG (_STR("Bad order %d,%d,%d,%d\n"),
                wake_order[0], wake_order[1], wake_order[2], wake_order[3]);
            failures++;
        }

        /* Delete queue, test finished */
        if (atomQueueDelete (&queue1) != ATOM_OK)
        {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#7
0
int main ( void )
{
    int8_t status;

    /**
     * Reuse part of the idle thread's stack for the stack required
     * during this startup function.
     */
    SP = (int)&idle_thread_stack[(IDLE_STACK_SIZE_BYTES/2) - 1];

    /**
     * Note: to protect OS structures and data during initialisation,
     * interrupts must remain disabled until the first thread
     * has been restored. They are reenabled at the very end of
     * the first thread restore, at which point it is safe for a
     * reschedule to take place.
     */

    /**
     * Initialise the OS before creating our threads.
     *
     * Note that we tell the OS that the idle stack is half its actual
     * size. This prevents it prefilling the bottom half with known
     * values for stack-checkig purposes, which we cannot allow because
     * we are temporarily using it for our own stack. The remainder will
     * still be available once the OS is started, this only prevents the
     * OS from prefilling it.
     *
     * If you are not reusing the idle thread's stack during startup then
     * you should pass in the correct size here.
     */
    status = atomOSInit(&idle_thread_stack[IDLE_STACK_SIZE_BYTES - 1], (IDLE_STACK_SIZE_BYTES/2));
    if (status == ATOM_OK)
    {
        /* Enable the system tick timer */
        avrInitSystemTickTimer();

        /* Create an application thread */
        status = atomThreadCreate(&main_tcb,
                     16, main_thread_func, 0,
                     &main_thread_stack[MAIN_STACK_SIZE_BYTES - 1],
                     MAIN_STACK_SIZE_BYTES);
        if (status == ATOM_OK)
        {
            /**
             * First application thread successfully created. It is
             * now possible to start the OS. Execution will not return
             * from atomOSStart(), which will restore the context of
             * our application thread and start executing it.
             *
             * Note that interrupts are still disabled at this point.
             * They will be enabled as we restore and execute our first
             * thread in archFirstThreadRestore().
             */
            atomOSStart();
        }
    }

    while (1)
        ;

    /* There was an error starting the OS if we reach here */
    return (0);
}
示例#8
0
/**
 * \b test_start
 *
 * Start queue test.
 *
 * This test exercises queue deletion, waking threads blocking on a queue
 * in atomQueuePut() if the queue is deleted.
 *
 * Deletion wakeups are tested twice: once for a thread which is blocking
 * in atomQueuePut() with a timeout and once for a thread which is
 * blocking in atomQueuePut() with no timeout.
 *
 * Deletion of threads blocking in atomQueueGet() are tested in queue2.c.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures, i;
    uint8_t msg;

    /* Default to zero failures */
    failures = 0;

    /* Set a test value for posting to the queue */
    msg = 0x66;

    /* Test wakeup of threads on queue deletion (thread blocking with no timeout) */
    g_result = 0;
    if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test queue\n"));
        failures++;
    }

    /* Successful queue creation */
    else
    {
        /* Fill up all entries */
        for (i = 0; i < QUEUE_ENTRIES; i++)
        {
            if (atomQueuePut (&queue1, 0, &msg) != ATOM_OK)
            {
                ATOMLOG (_STR("Error filling queue\n"));
                failures++;
            }
        }

        /* Create a test thread that will block because the queue is full */
        if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0,
                  &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
                  TEST_THREAD_STACK_SIZE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread 1\n"));
            failures++;
        }
        else
        {

            /*
             * We have created and filled a queue. We want to see that the other
             * thread is woken up if its queue is deleted. This is indicated
             * through g_result being set.
             */

            /* Wait for the other thread to start blocking on queue1 */
            if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
            {
                ATOMLOG (_STR("Failed timer delay\n"));
                failures++;
            }
            else
            {
                /* The other thread will be blocking on queue1 now, delete queue1 */
                if (atomQueueDelete(&queue1) != ATOM_OK)
                {
                    ATOMLOG (_STR("Failed queue1 delete\n"));
                    failures++;
                }
                else
                {
                    /* Queue1 deleted. The thread should now wake up and set g_result. */
                    atomTimerDelay (SYSTEM_TICKS_PER_SEC);
                    if (g_result == 0)
                    {
                        ATOMLOG (_STR("Notify fail\n"));
                        failures++;
                    }
                    else
                    {
                        /* Success */
                    }
                }
            }
        }
    }

    /* Test wakeup of threads on semaphore deletion (thread blocking with timeout) */
    g_result = 0;
    if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test queue\n"));
        failures++;
    }

    /* Successful queue creation */
    else
    {
        /* Fill up all entries */
        for (i = 0; i < QUEUE_ENTRIES; i++)
        {
            if (atomQueuePut (&queue1, 0, &msg) != ATOM_OK)
            {
                ATOMLOG (_STR("Error filling queue\n"));
                failures++;
            }
        }

        /* Create a test thread that will block because the queue is full */
        if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0,
                  &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1],
                  TEST_THREAD_STACK_SIZE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread 2\n"));
            failures++;
        }
        else
        {

            /*
             * We have created and filled a queue. We want to see that the other
             * thread is woken up if its queue is deleted. This is indicated
             * through g_result being set.
             */

            /* Wait for the other thread to start blocking on queue1 */
            if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
            {
                ATOMLOG (_STR("Failed timer delay\n"));
                failures++;
            }
            else
            {
                /* The other thread will be blocking on queue1 now, delete queue1 */
                if (atomQueueDelete(&queue1) != ATOM_OK)
                {
                    ATOMLOG (_STR("Failed queue1 delete\n"));
                    failures++;
                }
                else
                {
                    /* Queue1 deleted. The thread should now wake up and set g_result. */
                    atomTimerDelay (SYSTEM_TICKS_PER_SEC);
                    if (g_result == 0)
                    {
                        ATOMLOG (_STR("Notify fail\n"));
                        failures++;
                    }
                    else
                    {
                        /* Success */
                    }
                }
            }
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;
}
示例#9
0
/**
 * \b test_start
 *
 * Start mutex test.
 *
 * This tests the lock count of a mutex. The mutex object should
 * count the number of times a thread has locked the mutex and
 * not fully release it for use by another thread until it has
 * been released the same number of times it was locked.
*
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    int i;

    /* Default to zero failures */
    failures = 0;

    /* Create mutex */
    if (atomMutexCreate (&mutex1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating mutex\n"));
        failures++;
    }
    else
    {
        /* Initialise the shared_data to zero */
        shared_data = 0;

        /* Take the mutex several times */
        for (i = 0; i < TEST_LOCK_CNT; i++)
        {
            if (atomMutexGet (&mutex1, 0) != ATOM_OK)
            {
                ATOMLOG (_STR("Error taking mutex\n"));
                failures++;
                break;
            }

        }

        /* Create second thread */
        if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1,
              &test_thread_stack[0][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /*
         * The second thread has now been created and should block on
         * the mutex until we release it. We wait a while and check that
         * shared_data has not been modified.
         */
        for (i = 0; i < 4; i++)
        {
            /*
             * Sleep for a while to give the second thread a chance to
             * modify shared_data, thought it shouldn't until we
             * release the mutex enough times.
             */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

            /* Check shared data. The second thread always sets it to one. */
            if (shared_data != 0)
            {
                ATOMLOG (_STR("Shared data modified\n"));
                failures++;
                break;
            }
        }

        /* Check successful so far */
        if (failures == 0)
        {
            /*
             * Release the mutex TEST_LOCK_CNT-1 times, after which we
             * should still own the mutex (until we release one more time).
             */
            for (i = 0; i < TEST_LOCK_CNT-1; i++)
            {
                if (atomMutexPut (&mutex1) != ATOM_OK)
                {
                    ATOMLOG (_STR("Failed release\n"));
                    failures++;
                }

            }

            /*
             * Wait a little while then check that shared_data has
             * not been modified (we should still own the mutex).
             */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
            if (shared_data != 0)
            {
                ATOMLOG (_STR("Expected unmodified\n"));
                failures++;
            }

            /*
             * Release the mutex one more time, after which we should no
             * longer own the mutex (and wake up the second thread).
             */
            if (atomMutexPut (&mutex1) != ATOM_OK)
            {
                ATOMLOG (_STR("Failed release\n"));
                failures++;
            }

            /*
             * Wait a little while then check that shared_data has
             * been modified by the second thread.
             */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
            if (shared_data != 1)
            {
                ATOMLOG (_STR("Expected modified\n"));
                failures++;
            }
        }

        /*
         * Finally attempt to release the mutex one more time, while
         * we no longer own the mutex. Either the second thread will
         * have ownership of it, or no thread will have ownership.
         * In both cases we expect to get an ownership error when we
         * attempt to release it.
         */
        if (atomMutexPut (&mutex1) != ATOM_ERR_OWNERSHIP)
        {
            ATOMLOG (_STR("Failed locked+1 release\n"));
            failures++;
        }

        /* Delete mutex, test finished */
        if (atomMutexDelete (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#10
0
/**
 * \b test_start
 *
 * Start timer test.
 *
 * Tests that atomTimerDelay() delays for the correct time
 * period when used by three threads simultanously.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;

    /* Default to zero failures */
    failures = 0;
    g_failure_cnt[0] = g_failure_cnt[1] = g_failure_cnt[2] = 0;

    /* Create Thread 1 */
    if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1,
          &test_thread_stack[0][0],
          TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
    {
        /* Fail */
        ATOMLOG (_STR("Thread1\n"));
        failures++;
    }

    /* Create Thread 2 */
    if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 2,
          &test_thread_stack[1][0],
          TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
    {
        /* Fail */
        ATOMLOG (_STR("Thread2\n"));
        failures++;
    }

    /* Create Thread 3 */
    if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3,
          &test_thread_stack[2][0],
          TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
    {
        /* Fail */
        ATOMLOG (_STR("Thread3\n"));
        failures++;
    }

    /* Sleep for 10 seconds allowing the three threads to run tests */
    if (atomTimerDelay(TEST_PERIOD_SECS * SYSTEM_TICKS_PER_SEC) != ATOM_OK)
    {
        ATOMLOG (_STR("Period\n"));
        failures++;
    }

    /* Add the per-thread failure count to the main count */
    failures += g_failure_cnt[0] + g_failure_cnt[1] + g_failure_cnt[2];

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#11
0
/**
 * \b test_start
 *
 * Start kernel test.
 *
 * This tests the scheduling of threads at different priorities, and
 * preemption of lower priority threads by higher priority threads.
 *
 * Much of this functionality is already tested implicitly by the
 * semaphore, mutex tests etc but we repeat it here within the kernel
 * tests for completeness.
 *
 * Two threads are created at different priorities, with each thread
 * setting a running flag whenever it runs. We check that when the
 * higher priority thread is ready to run, only the higher priority
 * thread's running flag is set (even though the lower priority
 * thread should also be setting it at this time). This checks that
 * the scheduler is correctly prioritising thread execution.
 *
 * The test also exercises preemption, by disabling setting of the
 * running flag in the higher priority thread for a period. During
 * this time the higher priority thread repeatedly sleeps for one
 * system tick then wakes up to check the sleep-request flag again.
 * Every time the higher priority thread wakes up, it has preempted
 * the lower priority thread (which is always running). By ensuring
 * that the higher priority thread is able to start running again
 * after one of these periods (through checking the running flag)
 * we prove that the preemption has worked.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    int i;

    /* Default to zero failures */
    failures = 0;

    /* Initialise global data */
    running_flag[0] = running_flag[1] = FALSE;
    sleep_request[0] = sleep_request[1] = FALSE;

    /* Create low priority thread */
    if (atomThreadCreate (&tcb[0], 253, test_thread_func, 0,
            &test_thread_stack[0][0],
            TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
    {
        ATOMLOG (_STR("Bad thread create\n"));
        failures++;
    }

    /* Create high priority thread */
    else if (atomThreadCreate (&tcb[1], 252, test_thread_func, 1,
            &test_thread_stack[1][0],
            TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
    {
        ATOMLOG (_STR("Bad thread create\n"));
        failures++;
    }

    /* Repeat test a few times */
    for (i = 0; i < 8; i++)
    {
        /* Make the higher priority thread sleep */
        sleep_request[1] = TRUE;

        /* Sleep a little to make sure the thread sees the sleep request */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Reset the running flag for both threads */
        running_flag[0] = running_flag[1] = FALSE;

        /* Sleep a little to give any running threads time to set their flag */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Check only the low priority thread has run since we reset the flags */
        if ((running_flag[0] != TRUE) || (running_flag[1] != FALSE))
        {
            ATOMLOG (_STR("Lo%d %d/%d\n"), i, running_flag[0], running_flag[1]);
            failures++;
            break;
        }
        else
        {
            /*
             * We have confirmed that only the ready thread has been running.
             * Now check that if we wake up the high priority thread, the
             * low priority one stops running and only the high priority one
             * does.
             */

            /* Tell the higher priority thread to stop sleeping */
            sleep_request[1] = FALSE;

            /* Reset the running flag for both threads */
            running_flag[0] = running_flag[1] = FALSE;

            /* Sleep a little to give any running threads time to set their flag */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

            /* Check only the high priority thread has run since we reset the flags */
            if ((running_flag[1] != TRUE) || (running_flag[0] != FALSE))
            {
                ATOMLOG (_STR("Hi%d/%d\n"), running_flag[0], running_flag[1]);
                failures++;
                break;
            }
            else
            {
                /*
                 * We have confirmed that the high priority thread has preempted the
                 * low priority thread, and remain running while never scheduling
                 * the lower one back in.
                 */
            }
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#12
0
/**
 * \b test_start
 *
 * Start kernel test.
 *
 * This tests the round-robin timeslicing of same priority threads.
 *
 * Four threads are created (over and above the main test thread).
 * The main test thread sleeps for the duration of the entire test.
 * While the test is ongoing, all four threads are running
 * continuously at the same priority. They each check that whenever
 * the system tick (atomTimeGet()) changes, it has moved on 1 tick
 * since the last time the tick was checked, and that the previous
 * thread is the one created before itself. In the case of the first
 * thread created, the previous thread should be the last thread
 * created. This proves that on every tick the four threads get a
 * schedule timeslice equally, and in the same order throughout the
 * duration of the test.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;

    /* Default to zero failures */
    failures = 0;

    /* Initialise global data */
    last_time = 0;
    last_thread_id = -1;
    failure_cnt[0] = failure_cnt[1] = failure_cnt[2] = failure_cnt[3] = 0;

    /* Set test as not started until all threads are ready to go */
    test_started = FALSE;

    /*
     * Create all four threads at the same priority as each other.
     * They are given a lower priority than this thread, however,
     * to ensure that once this thread wakes up to stop the test it
     * can do so without confusing the scheduling tests by having
     * a spell in which this thread was run.
     */
    if (atomThreadCreate (&tcb[0], TEST_THREAD_PRIO + 1, test_thread_func, 0,
                          &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
                          TEST_THREAD_STACK_SIZE) != ATOM_OK) {
        ATOMLOG (_STR("Bad thread create\n"));
        failures++;
    } else if (atomThreadCreate (&tcb[1], TEST_THREAD_PRIO + 1, test_thread_func, 1,
                                 &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1],
                                 TEST_THREAD_STACK_SIZE) != ATOM_OK) {
        ATOMLOG (_STR("Bad thread create\n"));
        failures++;
    } else if (atomThreadCreate (&tcb[2], TEST_THREAD_PRIO + 1, test_thread_func, 2,
                                 &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1],
                                 TEST_THREAD_STACK_SIZE) != ATOM_OK) {
        ATOMLOG (_STR("Bad thread create\n"));
        failures++;
    } else if (atomThreadCreate (&tcb[3], TEST_THREAD_PRIO + 1, test_thread_func, 3,
                                 &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1],
                                 TEST_THREAD_STACK_SIZE) != ATOM_OK) {
        ATOMLOG (_STR("Bad thread create\n"));
        failures++;
    }

    /* Start the test */
    test_started = TRUE;

    /* Sleep for 5 seconds during test */
    atomTimerDelay (5 * SYSTEM_TICKS_PER_SEC);

    /* Stop the test */
    test_started = FALSE;

    /* Sleep for tests to complete */
    atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

    /* Count any failures from test threads */
    failures += failure_cnt[0] + failure_cnt[1] + failure_cnt[2] + failure_cnt[3];

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++) {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK) {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            } else {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0) {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#13
0
int main ( void )
{
    int8_t status;
    uint32_t loop;

    /**
     * Brief delay to give the debugger a chance to stop the core before we
     * muck around with the chip's configuration.
     */
    for(loop = 0; loop < 1000000; ++loop){
        __asm__("nop");
    }

    /**
     * Note: to protect OS structures and data during initialisation,
     * interrupts must remain disabled until the first thread
     * has been restored. They are reenabled at the very end of
     * the first thread restore, at which point it is safe for a
     * reschedule to take place.
     */
    board_setup();

    /**
     * Initialise the OS before creating our threads.
     *
     * Note that we cannot enable stack-checking on the idle thread on
     * this platform because we are already using part of the idle
     * thread's stack now as our startup stack. Prefilling for stack
     * checking would overwrite our current stack.
     *
     * If you are not reusing the idle thread's stack during startup then
     * you are free to enable stack-checking here.
     */
    status = atomOSInit(&idle_thread_stack[0], IDLE_STACK_SIZE_BYTES, FALSE);
    if (status == ATOM_OK)
    {

        /* Create an application thread */
        status = atomThreadCreate(&main_tcb,
                     TEST_THREAD_PRIO, main_thread_func, 0,
                     &main_thread_stack[0],
                     MAIN_STACK_SIZE_BYTES,
                     TRUE);
        if (status == ATOM_OK)
        {
            /**
             * First application thread successfully created. It is
             * now possible to start the OS. Execution will not return
             * from atomOSStart(), which will restore the context of
             * our application thread and start executing it.
             *
             * Note that interrupts are still disabled at this point.
             * They will be enabled as we restore and execute our first
             * thread in archFirstThreadRestore().
             */
            atomOSStart();
        }
    }

    while (1)
        ;

    /* There was an error starting the OS if we reach here */
    return (0);
}
示例#14
0
/**
 * \b test_start
 *
 * Start mutex test.
 *
 * This tests the ownership checks of the mutex library. Only threads
 * which own a mutex can release it. It should not be possible to
 * release a mutex if it is not owned by any thread, is owned by a
 * different thread, or at interrupt context. We test here that all
 * three cases are trapped.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    ATOM_TIMER timer_cb;

    /* Default to zero failures */
    failures = 0;

    /* Create mutex */
    if (atomMutexCreate (&mutex1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating mutex\n"));
        failures++;
    }
    else
    {
        /* Initialise the shared_data to zero */
        shared_data = 0;

        /* Attempt to release the mutex when not owned by any thread */
        if (atomMutexPut (&mutex1) != ATOM_ERR_OWNERSHIP)
        {
            ATOMLOG (_STR("Release error\n"));
            failures++;
        }

        /* Create second thread */
        else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1,
              &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
              TEST_THREAD_STACK_SIZE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /*
         * The second thread has now been created and should take ownership
         * of the mutex. We wait a while and check that shared_data has been
         * modified, which proves to us that the thread has taken the mutex.
         */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
        if (shared_data != 1)
        {
            ATOMLOG (_STR("Shared data unmodified\n"));
            failures++;
        }

        /* Check successful so far */
        if (failures == 0)
        {
            /*
             * Attempt to release the mutex again now that it is owned
             * by another thread.
             */
            if (atomMutexPut (&mutex1) != ATOM_ERR_OWNERSHIP)
            {
                ATOMLOG (_STR("Release error 2\n"));
                failures++;
            }

            /* Finally check that the mutex cannot be released from an ISR */

            /* Fill out the timer callback request structure */
            timer_cb.cb_func = testCallback;
            timer_cb.cb_data = NULL;
            timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;

            /* Request the timer callback to run in one second */
            if (atomTimerRegister (&timer_cb) != ATOM_OK)
            {
                ATOMLOG (_STR("Error registering timer\n"));
                failures++;
            }

            /*
             * Wait two seconds for shared_date to be set to 2
             * indicating success. This happens if the timer
             * callback received the expected ownership error
             * when attempting to release the mutex.
             */
            else
            {
                atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC);
                if (shared_data != 2)
                {
                    ATOMLOG (_STR("Context check failed\n"));
                    failures++;
                }
            }
        }

        /* Delete mutex, test finished */
        if (atomMutexDelete (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#15
0
/**
 * \b test_start
 *
 * Start mutex test.
 *
 * This tests timeouts on a mutex. We make a thread block with timeout
 * on a mutex, and test that sufficient time has actually passed as
 * was requested by the timeout parameter.
 *
 * The main thread creates a second thread which will immediately take
 * ownership of the mutex. The test checks that the correct timeout
 * occurs when the first thread blocks on the mutex which is already
 * owned (by the second thread).
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    uint32_t start_time, end_time;

    /* Default to zero failures */
    failures = 0;

    /* Create mutex */
    if (atomMutexCreate (&mutex1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating mutex\n"));
        failures++;
    }
    else
    {
        /* Initialise the shared_data to zero */
        shared_data = 0;

        /* Create second thread */
        if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1,
              &test_thread_stack[0][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /*
         * The second thread has now been created and should take ownership
         * of the mutex. We wait a while and check that shared_data has been
         * modified, which proves to us that the thread has taken the mutex.
         */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
        if (shared_data != 1)
        {
            ATOMLOG (_STR("Shared data unmodified\n"));
            failures++;
        }

        /* Check successful so far */
        if (failures == 0)
        {
            /* Take note of the start time */
            start_time = atomTimeGet();

            /* Block on the mutex with two second timeout */
            if (atomMutexGet (&mutex1, 2 * SYSTEM_TICKS_PER_SEC) != ATOM_TIMEOUT)
            {
                ATOMLOG (_STR("Failed get\n"));
                failures++;
            }

            /* Take note of the end time */
            end_time = atomTimeGet();

            /* Now check that two seconds have passed */
            if ((end_time < (start_time + (2 * SYSTEM_TICKS_PER_SEC)))
                || (end_time > (start_time + (2 * SYSTEM_TICKS_PER_SEC) + 1)))
            {
                ATOMLOG (_STR("Bad time\n"));
                failures++;
            }
        }

        /* Delete mutex, test finished */
        if (atomMutexDelete (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#16
0
/**
 * \b test_start
 *
 * Start queue test.
 *
 * This tests basic operation of queues.
 *
 * The main test thread creates a second thread and posts
 * a series of messages to the second thread. The message
 * values are checked against the expected values.
 *
 * We test using 4-byte messages.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures, count;
    int num_entries;
    uint32_t msg;

    /* Default to zero failures */
    failures = 0;
    g_result = 0;

    /* Create test queue */
    if (atomQueueCreate (&queue1, (uint8_t *)&queue1_storage[0], sizeof(queue1_storage[0]), QUEUE_ENTRIES) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test queue\n"));
        failures++;
    }

    /* Create a test thread that will block because the queue is empty */
    else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO + 1, test1_thread_func, 0,
              &test_thread_stack[0][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
    {
        /* Fail */
        ATOMLOG (_STR("Error creating test thread 1\n"));
        failures++;
    }
    else
    {

        /*
         * We have created an empty queue and a thread which should now
         * be blocking on the queue. The test thread is lower priority
         * than us.
         */

        /* Wait for the other thread to start blocking on queue1 */
        if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
        {
            ATOMLOG (_STR("Failed timer delay\n"));
            failures++;
        }
        else
        {
            /*
             * Post all entries in the test array to the queue.
             * Because the second thread is lower priority than
             * us, we will post 8 messages until the queue is
             * full without waking up the second thread at all.
             * At that point, we will block and the second
             * thread will remove one message from the queue.
             * With a spare entry in the queue, this thread
             * will wake up again and post another message.
             * This will continue until this thread has posted
             * all messages, at which point the second thread
             * will drain all remaining messages from the
             * queue.
             *
             * Through this scheme we are able to test posting
             * to the queue at all possible fill levels.
             */
            num_entries = sizeof(test_values) / sizeof(test_values[0]);
            for (count = 0; count < num_entries; count++)
            {
                /* Increment through and post all test values to the queue */
                msg = test_values[count];
                if (atomQueuePut (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
                {
                    ATOMLOG (_STR("Failed post\n"));
                    failures++;
                }
            }

            /* Sleep a while for the second thread to finish */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC);

            /* Check that the second thread has found all test values */
            if (g_result != 1)
            {
                ATOMLOG (_STR("Bad test vals\n"));
                failures++;
            }
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;
}
示例#17
0
/**
 * \b test_start
 *
 * Start semaphore test.
 *
 * This tests usage of a semaphore for basic mutual exclusion type
 * operation. Note that Atomthreads has a more fully-featured real
 * mutex implementation in the mutex module.
 *
 * The semaphore sem1 is initialised with a count of 1. Whichever
 * thread holds this semaphore can then modify the global variable
 * "shared_data".
 *
 * The main thread first takes the "mutex" sem1, then creates a
 * second thread. The second thread should block on the sem1 mutex
 * until the main thread releases it. The test checks that the
 * global "shared_data" is not modified by the second thread
 * until the main thread releases the mutex.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    int i;

    /* Default to zero failures */
    failures = 0;

    /* Create sem with count one for mutex purposes */
    if (atomSemCreate (&sem1, 1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test semaphore 1\n"));
        failures++;
    }
    else
    {
        /* Initialise the shared_data to zero */
        shared_data = 0;

        /* Take the mutex to ensure only this thread can modify shared_data */
        if (atomSemGet (&sem1, 0) != ATOM_OK)
        {
            ATOMLOG (_STR("Error taking mutex\n"));
            failures++;
        }

        /* Create second thread */
        else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1,
              &test_thread_stack[0][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /*
         * The second thread has now been created and should block on
         * the "mutex" sem1 (which now has count zero) until we release
         * it. We wait a while and check that shared_data has not been
         * modified.
         */
        for (i = 0; i < 4; i++)
        {
            /*
             * Sleep for a while to give the second thread a chance to
             * modify shared_data, thought it shouldn't until we
             * release the mutex.
             */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

            /* Check shared data. The second thread always sets it to one. */
            if (shared_data != 0)
            {
                ATOMLOG (_STR("Shared data modified\n"));
                failures++;
                break;
            }
        }

        /* Check successful so far */
        if (failures == 0)
        {
            /*
             * Release the mutex, which will allow the second thread to
             * wake and start modifying shared_data.
             */
            if (atomSemPut (&sem1) != ATOM_OK)
            {
                ATOMLOG (_STR("Failed release\n"));
                failures++;
            }

            /*
             * Wait a little while then check that shared_data has
             * been modified.
             */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
            if (shared_data != 1)
            {
                ATOMLOG (_STR("Expected modify\n"));
                failures++;
            }

            /*
             * Release and take the mutex again a few times to ensure
             * that the mutex continues to protect shared_data.
             */
            for (i = 0; i < 4; i++)
            {
                /*
                 * Take the mutex again, to prevent second thread accessing
                 * shared_data.
                 */
                if (atomSemGet (&sem1, SYSTEM_TICKS_PER_SEC) != ATOM_OK)
                {
                    ATOMLOG (_STR("Retake %d\n"), i);
                    failures++;
                    break;
                }
                else
                {
                    /*
                     * Set shared_data to 0 and wait to ensure that the
                     * second thread doesn't modify it while we have the
                     * mutex again.
                     */
                    shared_data = 0;

                    /* Wait a while to give second thread potential to run */
                    atomTimerDelay(SYSTEM_TICKS_PER_SEC/4);

                    /*
                     * Check that shared_data has not been modified while we
                     * own the mutex.
                     */
                    if (shared_data != 0)
                    {
                        /* Thread is still modifying the data */
                        ATOMLOG (_STR("Still modifying\n"));
                        failures++;
                        break;
                    }

                    /*
                     * Release the mutex, which will allow the second thread to
                     * wake and start modifying shared_data again.
                     */
                    if (atomSemPut (&sem1) != ATOM_OK)
                    {
                        ATOMLOG (_STR("Failed release\n"));
                        failures++;
                    }

                }
            }
        }

        /* Delete semaphore, test finished */
        if (atomSemDelete (&sem1) != ATOM_OK)
        {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#18
0
/**
 * \b test_start
 *
 * Start queue test.
 *
 * This test verifies the queue deletion API, by deleting a queue
 * on which multiple threads are blocking, and checking that all three
 * are woken up with an appropriate error code.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    int i;

    /* Default to zero failures */
    failures = 0;

    /* Initialise pass status for all three threads to FALSE */
    for (i = 0; i < 3; i++) {
        pass_flag[i] = FALSE;
    }

    /* Test wakeup of three threads on queue deletion */
    if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(queue1_storage[0]), QUEUE_ENTRIES) != ATOM_OK) {
        ATOMLOG (_STR("Error creating Q\n"));
        failures++;
    }

    else {
        /* The queue is empty so all three test threads will block */

        /* Create test thread 1 */
        if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0,
                             &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
                             TEST_THREAD_STACK_SIZE) != ATOM_OK) {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread 1\n"));
            failures++;
        }

        /* Create test thread 2 */
        else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 1,
                                  &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1],
                                  TEST_THREAD_STACK_SIZE) != ATOM_OK) {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread 2\n"));
            failures++;
        }

        /* Create test thread 3 */
        else if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 2,
                                  &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1],
                                  TEST_THREAD_STACK_SIZE) != ATOM_OK) {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread 3\n"));
            failures++;
        }

        /* Test threads now created */
        else {
            /* Wait a while for threads to start blocking on queue1 */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

            /* Delete queue1 now that all three threads should be blocking */
            if (atomQueueDelete (&queue1) != ATOM_OK) {
                ATOMLOG (_STR("Delete fail\n"));
                failures++;
            } else {
                /* Wait a while for all three threads to wake up */
                atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

                /* Check that all three threads have passed */
                if ((pass_flag[0] != TRUE) || (pass_flag[1] != TRUE) || (pass_flag[2] != TRUE)) {
                    ATOMLOG (_STR("Thread fail\n"));
                    failures++;
                }
            }
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++) {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK) {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            } else {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0) {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;
}
示例#19
0
int main ( void )
{
    int8_t status;
	sei();



	SerialInit(MYUBRR);
	InitWatch();
    /**
     * Reuse part of the idle thread's stack for the stack required
     * during this startup function.
     */
    SP = (int)&idle_thread_stack[(IDLE_STACK_SIZE_BYTES/2) - 1];

    /**
     * Note: to protect OS structures and data during initialisation,
     * interrupts must remain disabled until the first thread
     * has been restored. They are reenabled at the very end of
     * the first thread restore, at which point it is safe for a
     * reschedule to take place.
     */

    /**
     * Initialise the OS before creating our threads.
     *
     * Note that we cannot enable stack-checking on the idle thread on
     * this platform because we are already using part of the idle
     * thread's stack now as our startup stack. Prefilling for stack
     * checking would overwrite our current stack.
     *
     * If you are not reusing the idle thread's stack during startup then
     * you are free to enable stack-checking here.
     */
    status = atomOSInit(&idle_thread_stack[0], IDLE_STACK_SIZE_BYTES, FALSE);
    if (status == ATOM_OK)
    {

        /* Enable the system tick timer */
        avrInitSystemTickTimer();

        /* Create the main thread */
        status = atomThreadCreate(&main_tcb,
                     MAIN_THREAD_PRIO, main_thread_func, 0,
                     &main_thread_stack[0],
                     MAIN_STACK_SIZE_BYTES,
                     FALSE);
        if (status == ATOM_OK)
        {
            /**
             * Application threads successfully created. It is
             * now possible to start the OS. Execution will not return
             * from atomOSStart(), which will restore the context of
             * our application thread and start executing it.
             *
             * Note that interrupts are still disabled at this point.
             * They will be enabled as we restore and execute our first
             * thread in archFirstThreadRestore().
             */
            atomOSStart();

        }
    }
    while (1)
	{
		atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC); // wait 2 sec

	}
    /* There was an error starting the OS if we reach here */
    return (0);
}
示例#20
0
/**
 * \b test_start
 *
 * Start semaphore test.
 *
 * With multiple threads blocking on a single semaphore, this test confirms that
 * they are woken in order when the semaphore is posted. The correct order for
 * waking is that the higher priority threads are woken first, followed by the
 * lower priority threads. Where multiple threads of the same priority are
 * waiting, the threads are woken in FIFO order (the order in which they started
 * waiting on the semaphore).
 *
 * To test this we create four threads which all wait on a single semaphore.
 * One pair of threads are running at high priority, with the other pair at a
 * lower priority:
 *
 * Thread 1: low prio thread A
 * Thread 2: low prio thread B
 * Thread 3: high prio thread A
 * Thread 4: high prio thread B
 *
 * The threads are forced to start blocking on the same semaphore in the
 * above order (the semaphore is initialised with count 0 to ensure any
 * threads calling atomSemGet() will block).
 *
 * We expect to see them woken up in the following order:
 *  3, 4, 1, 2
 *
 * This proves the multiple blocking thread ordering in terms of both
 * the priority-queueing and same-priority-FIFO-queueing.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    int i;

    /* Default to zero failures */
    failures = 0;

    /* Create sem with count zero (so that all threads will block) */
    if (atomSemCreate (&sem1, 0) != ATOM_OK) {
        ATOMLOG (_STR("Error creating test semaphore 1\n"));
        failures++;
    } else {
        /* Create Thread 1 (lower priority thread A) */
        if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO+1, test_thread_func, 1,
                             &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
                             TEST_THREAD_STACK_SIZE) != ATOM_OK) {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the semaphore */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 2 (lower priority thread B) */
        if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO+1, test_thread_func, 2,
                             &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1],
                             TEST_THREAD_STACK_SIZE) != ATOM_OK) {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the semaphore */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 3 (higher priority thread A) */
        if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3,
                             &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1],
                             TEST_THREAD_STACK_SIZE) != ATOM_OK) {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the semaphore */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 4 (higher priority thread B) */
        if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4,
                             &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1],
                             TEST_THREAD_STACK_SIZE) != ATOM_OK) {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the semaphore */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* All four threads will now be blocking on sem1 */

        /*
         * Initialise wake count, used by threads to determine
         * what order they were woken in.
         */
        wake_cnt = 0;

        /*
         * Wake the four threads up in order, leaving some time between
         * each wake up for them to deal with global data in a
         * thread-safe fashion.
         */
        for (i = 0; i < 4; i++) {
            /* Post semaphore to wake one of the threads up */
            if (atomSemPut (&sem1) != ATOM_OK) {
                ATOMLOG (_STR("Post fail\n"));
                failures++;
            }

            /* Sleep to give the thread time to manipulate global data */
            atomTimerDelay (SYSTEM_TICKS_PER_SEC / 4);
        }

        /* All four threads now woken up, check they woke in correct order */
        if ((wake_order[0] != 3) || (wake_order[1] != 4)
            || (wake_order[2] != 1) || (wake_order[3] != 2)) {
            ATOMLOG (_STR("Bad order %d,%d,%d,%d\n"),
                     wake_order[0], wake_order[1], wake_order[2], wake_order[3]);
            failures++;
        }

        /* Delete semaphore, test finished */
        if (atomSemDelete (&sem1) != ATOM_OK) {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++) {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK) {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            } else {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0) {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#21
0
/**
 * \b test_start
 *
 * Start semaphore test.
 *
 * This test exercises the semaphore creation and deletion APIs, including
 * waking threads blocking on a semaphore if the semaphore is deleted.
 * Deletion wakeups are tested twice: once for a thread which is blocking
 * with a timeout and once for a thread which is blocking with no timeout.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    uint32_t i;
    uint8_t status;

    /* Default to zero failures */
    failures = 0;

    /* Test creation and deletion of semaphores: good values */
    for (i = 0; i < 1000; i++)
    {
        if (atomSemCreate (&sem1, 0) == ATOM_OK)
        {
            if (atomSemDelete (&sem1) == ATOM_OK)
            {
                /* Success */
            }
            else
            {
                /* Fail */
                ATOMLOG (_STR("Error deleting semaphore\n"));
                failures++;
                break;
            }
        }
        else
        {
            /* Fail */
            ATOMLOG (_STR("Error creating semaphore\n"));
            failures++;
            break;
        }
    }

    /* Test creation and deletion of semaphores: creation checks */
    if (atomSemCreate (NULL, 0) != ATOM_OK)
    {
        /* Success */
    }
    else
    {
        /* Fail */
        ATOMLOG (_STR("Bad semaphore creation checks\n"));
        failures++;
    }

    /* Test creation and deletion of semaphores: deletion checks */
    if (atomSemDelete (NULL) != ATOM_OK)
    {
        /* Success */
    }
    else
    {
        /* Fail */
        ATOMLOG (_STR("Bad semaphore deletion checks\n"));
        failures++;
    }

    /* Test wakeup of threads on semaphore deletion (thread blocking with no timeout) */
    if (atomSemCreate (&sem1, 0) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test semaphore 1\n"));
        failures++;
    }

    else if (atomSemCreate (&sem2, 0) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test semaphore 2\n"));
        failures++;
    }

    else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0,
                              &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
                              TEST_THREAD_STACK_SIZE) != ATOM_OK)
    {
        /* Fail */
        ATOMLOG (_STR("Error creating test thread 1\n"));
        failures++;
    }
    else
    {

        /*
         * We have created two semaphores. sem1 is for the other thread
         * to wait on, which we will delete from this thread. We want
         * to see that the other thread is woken up if its semaphore
         * is deleted. This is indicated through sem2 being posted
         * back to us.
         */

        /* Wait for the other thread to start blocking on sem1 */
        if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
        {
            ATOMLOG (_STR("Failed timer delay\n"));
            failures++;
        }
        else
        {
            /* The other thread will be blocking on sem1 now, delete sem1 */
            if (atomSemDelete(&sem1) != ATOM_OK)
            {
                ATOMLOG (_STR("Failed sem1 delete\n"));
                failures++;
            }
            else
            {
                /* Sem1 deleted. The thread should now wake up and post sem2. */
                if ((status = atomSemGet (&sem2, (5*SYSTEM_TICKS_PER_SEC))) != ATOM_OK)
                {
                    ATOMLOG (_STR("Notify fail (%d)\n"), status);
                    failures++;
                }
                else
                {
                    /* Success */

                    /* Clean up the last remaining semaphore */
                    if (atomSemDelete (&sem2) != ATOM_OK)
                    {
                        ATOMLOG (_STR("Failed sem2 delete\n"));
                        failures++;
                    }
                }
            }
        }
    }

    /* Test wakeup of threads on semaphore deletion (thread blocking with timeout) */
    if (atomSemCreate (&sem1, 0) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test semaphore 1\n"));
        failures++;
    }
    else if (atomSemCreate (&sem2, 0) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test semaphore 2\n"));
        failures++;
    }
    else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0,
                              &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1],
                              TEST_THREAD_STACK_SIZE) != ATOM_OK)
    {
        /* Fail */
        ATOMLOG (_STR("Error creating test thread 2\n"));
        failures++;
    }
    else
    {
        /*
         * We have created two semaphores. sem1 is for the other thread
         * to wait on, which we will delete from this thread. We want
         * to see that the other thread is woken up if its semaphore
         * is deleted. This is indicated through sem2 being posted
         * back to us.
         */

        /* Wait for the other thread to start blocking on sem1 */
        if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
        {
            ATOMLOG (_STR("Failed timer delay\n"));
            failures++;
        }
        else
        {
            /* The other thread will be blocking on sem1 now, delete sem1 */
            if (atomSemDelete(&sem1) != ATOM_OK)
            {
                ATOMLOG (_STR("Failed sem1 delete\n"));
                failures++;
            }
            else
            {
                /* Sem1 deleted. The thread should now wake up and post sem2. */
                if ((status = atomSemGet (&sem2, (5*SYSTEM_TICKS_PER_SEC))) != ATOM_OK)
                {
                    ATOMLOG (_STR("Notify fail (%d)\n"), status);
                    failures++;
                }
                else
                {
                    /* Success */

                    /* Clean up the last remaining semaphore */
                    if (atomSemDelete (&sem2) != ATOM_OK)
                    {
                        ATOMLOG (_STR("Failed sem2 delete\n"));
                        failures++;
                    }
                }
            }
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;
}
示例#22
0
/**
 * \b test_start
 *
 * Start mutex test.
 *
 * This test exercises the atomMutexGet() and atomMutexPut() APIs including
 * forcing the various error indications which can be returned from the
 * APIs to ensure that handling for these corner cases have been correctly
 * implemented.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;
    uint8_t status;
    ATOM_TIMER timer_cb;
    int count;

    /* Default to zero failures */
    failures = 0;

    /* Test parameter checks */
    if (atomMutexGet (NULL, 0) != ATOM_ERR_PARAM)
    {
        ATOMLOG (_STR("Get param failed\n"));
        failures++;
    }
    if (atomMutexPut (NULL) != ATOM_ERR_PARAM)
    {
        ATOMLOG (_STR("Put param failed\n"));
        failures++;
    }

    /* Test atomMutexGet() can not be called from interrupt context */
    g_result = 0;
    if (atomMutexCreate (&mutex1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test mutex1\n"));
        failures++;
    }
    else
    {
        /* Fill out the timer callback request structure */
        timer_cb.cb_func = testCallback;
        timer_cb.cb_data = NULL;
        timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;

        /* Request the timer callback to run in one second */
        if (atomTimerRegister (&timer_cb) != ATOM_OK)
        {
            ATOMLOG (_STR("Error registering timer\n"));
            failures++;
        }

        /* Wait two seconds for g_result to be set indicating success */
        else
        {
            atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC);
            if (g_result != 1)
            {
                ATOMLOG (_STR("Context check failed\n"));
                failures++;
            }
        }

        /* Delete the test mutex */
        if (atomMutexDelete (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Mutex1 delete failed\n"));
            failures++;
        }
    }

    /* Create mutex1 which will be owned by us */
    if (atomMutexCreate (&mutex1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test mutex 1\n"));
        failures++;
    }

    /* Create mutex2 which will be owned by another thread */
    else if (atomMutexCreate (&mutex2) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test mutex 2\n"));
        failures++;
    }

    /* Create a test thread, the sole purpose of which is to own mutex2 */
    g_owned = 0;
    if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0,
              &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
              TEST_THREAD_STACK_SIZE) != ATOM_OK)
    {
        /* Fail */
        ATOMLOG (_STR("Error creating test thread 1\n"));
        failures++;
    }

    /* Sleep until the test thread owns mutex2 */
    atomTimerDelay (SYSTEM_TICKS_PER_SEC);
    if (g_owned == 0)
    {
        ATOMLOG (_STR("Thread own fail\n"));
        failures++;
    }

    /* Test wait on mutex with timeout - should timeout while owned by another thread */
    if ((status = atomMutexGet (&mutex2, SYSTEM_TICKS_PER_SEC)) != ATOM_TIMEOUT)
    {
        ATOMLOG (_STR("Get %d\n"), status);
        failures++;
    }
    else
    {
        /* Success */
    }

    /* Test wait on mutex with no blocking - should return that owned by another thread */
    if ((status = atomMutexGet (&mutex2, -1)) != ATOM_WOULDBLOCK)
    {
        ATOMLOG (_STR("Wouldblock err %d\n"), status);
        failures++;
    }

    /* Test wait on mutex with no blocking when mutex is available */
    if (atomMutexGet (&mutex1, -1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error taking mutex1\n"));
        failures++;
    }
    else
    {
        /* Relinquish ownership of mutex1 */
        if (atomMutexPut (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Error posting mutex\n"));
            failures++;
        }
    }

    /* Test for lock count overflows with too many gets */
    count = 255;
    while (count--)
    {
        if (atomMutexGet (&mutex1, 0) != ATOM_OK)
        {
            ATOMLOG (_STR("Error getting mutex1\n"));
            failures++;
            break;
        }
    }

    /* The lock count should overflow this time */
    if (atomMutexGet (&mutex1, 0) != ATOM_ERR_OVF)
    {
        ATOMLOG (_STR("Error tracking overflow\n"));
        failures++;
    }
    else
    {
        /* Success */
    }

    /* Delete the test mutexes */
    if (atomMutexDelete (&mutex1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error deleting mutex1\n"));
        failures++;
    }
    if (atomMutexDelete (&mutex2) != ATOM_OK)
    {
        ATOMLOG (_STR("Error deleting mutex2\n"));
        failures++;
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;
}
示例#23
0
/**
 * \b test_start
 *
 * Start semaphore test.
 *
 * This tests basic counting semaphore operation between two threads.
 *
 * A semaphore is created with a count of 10. A second thread then
 * ensures that it can decrement the semaphore 10 times before
 * it can no longer be decremented.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;

    /* Default to zero failures */
    failures = 0;

    /* Create sem with count ten for second thread to decrement */
    if (atomSemCreate (&sem1, INITIAL_SEM_COUNT) != ATOM_OK) {
        ATOMLOG (_STR("Error creating test semaphore 1\n"));
        failures++;
    }
    /* Create sem to receive test-passed notification */
    else if (atomSemCreate (&sem2, 0) != ATOM_OK) {
        ATOMLOG (_STR("Error creating test semaphore 1\n"));
        failures++;
    } else {
        /* Check that sem2 doesn't already have a positive count */
        if (atomSemGet (&sem2, -1) != ATOM_WOULDBLOCK) {
            ATOMLOG (_STR("Sem2 already put\n"));
            failures++;
        }

        /* Create second thread */
        else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1,
                                  &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1],
                                  TEST_THREAD_STACK_SIZE) != ATOM_OK) {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /*
         * The second thread has now been created and will attempt to
         * decrement sem1 ten times, then finally check that it cannot
         * decrement it any further. If this passes then the second
         * thread will post sem2 to notify us that the test has passed.
         */
        else {
            /* Give the second thread one second to post sem2 */
            if (atomSemGet (&sem2, SYSTEM_TICKS_PER_SEC) != ATOM_OK) {
                ATOMLOG (_STR("Sem2 not posted\n"));
                failures++;
            }

        }

        /* Delete semaphores, test finished */
        if (atomSemDelete (&sem1) != ATOM_OK) {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
        if (atomSemDelete (&sem2) != ATOM_OK) {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++) {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK) {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            } else {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0) {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}
示例#24
0
/**
 * \b test_start
 *
 * Start mutex test.
 *
 * With multiple threads blocking on a single mutex, this test confirms that
 * they are woken in order when the mutex is released. The correct order for
 * waking is that the higher priority threads are woken first, followed by the
 * lower priority threads. Where multiple threads of the same priority are
 * waiting, the threads are woken in FIFO order (the order in which they started
 * waiting on the mutex).
 *
 * To test this we create four threads which all wait on a single mutex.
 * One pair of threads are running at high priority, with the other pair at a
 * lower priority:
 *
 * Thread 1: low prio thread A
 * Thread 2: low prio thread B
 * Thread 3: high prio thread A
 * Thread 4: high prio thread B
 *
 * The threads are forced to start blocking on the same mutex in the
 * above order.
 *
 * We expect to see them woken up in the following order:
 *  3, 4, 1, 2
 *
 * This proves the multiple blocking thread ordering in terms of both
 * the priority-queueing and same-priority-FIFO-queueing.
 *
 * @retval Number of failures
 */
uint32_t test_start (void)
{
    int failures;

    /* Default to zero failures */
    failures = 0;

    /* Create mutex */
    if (atomMutexCreate (&mutex1) != ATOM_OK)
    {
        ATOMLOG (_STR("Error creating test mutex 1\n"));
        failures++;
    }

    /* Take ownership of the mutex so all threads will block to begin with */
    else if (atomMutexGet (&mutex1, 0) != ATOM_OK)
    {
        ATOMLOG (_STR("Get error\n"));
        failures++;
    }

    /* Start the threads */
    else
    {
        /* Create Thread 1 (lower priority thread A) */
        if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO+1, test_thread_func, 1,
              &test_thread_stack[0][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the mutex */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 2 (lower priority thread B) */
        if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO+1, test_thread_func, 2,
              &test_thread_stack[1][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the mutex */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 3 (higher priority thread A) */
        if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3,
              &test_thread_stack[2][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the mutex */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* Create Thread 4 (higher priority thread B) */
        if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4,
              &test_thread_stack[3][0],
              TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
        {
            /* Fail */
            ATOMLOG (_STR("Error creating test thread\n"));
            failures++;
        }

        /* Delay to ensure the thread will start blocking on the mutex */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);

        /* All four threads will now be blocking on mutex1 */

        /*
         * Initialise wake count, used by threads to determine
         * what order they were woken in.
         */
        wake_cnt = 0;

        /*
         * Release the mutex. This will wake up one of the threads blocking
         * on it. That thread will take ownership of the mutex, and note the
         * order at which it was woken, before releasing the mutex. This in
         * turn will wake up the next thread blocking on the mutex until all
         * four test threads have taken and released the mutex, noting their
         * wake order.
         */
        if (atomMutexPut (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Post fail\n"));
            failures++;
        }

        /* Sleep to give all four threads time to complete */
        atomTimerDelay (SYSTEM_TICKS_PER_SEC / 4);

        /* All four threads now woken up, check they woke in correct order */
        if ((wake_order[0] != 3) && (wake_order[1] != 4)
            && (wake_order[2] != 1) && (wake_order[3] != 2))
        {
            ATOMLOG (_STR("Bad order %d,%d,%d,%d\n"),
                wake_order[0], wake_order[1], wake_order[2], wake_order[3]);
            failures++;
        }

        /* Delete mutex, test finished */
        if (atomMutexDelete (&mutex1) != ATOM_OK)
        {
            ATOMLOG (_STR("Delete failed\n"));
            failures++;
        }
    }

    /* Check thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
    {
        uint32_t used_bytes, free_bytes;
        int thread;

        /* Check all threads */
        for (thread = 0; thread < NUM_TEST_THREADS; thread++)
        {
            /* Check thread stack usage */
            if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
            {
                ATOMLOG (_STR("StackCheck\n"));
                failures++;
            }
            else
            {
                /* Check the thread did not use up to the end of stack */
                if (free_bytes == 0)
                {
                    ATOMLOG (_STR("StackOverflow %d\n"), thread);
                    failures++;
                }

                /* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
                ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
#endif
            }
        }
    }
#endif

    /* Quit */
    return failures;

}