Search:

PmWiki

pmwiki.org

edit SideBar

Main / ThreadxExample
/* 12_sample_system.c

   Create two threads, one byte pool, two message queues, three timers, and 
   one counting semaphore. This is an example of multiple object suspension 
   using event-chaining, i.e., speedy_thread and slow_thread wait for a
   message to appear on either of two queues  */


/****************************************************/
/*    Declarations, Definitions, and Prototypes     */
/****************************************************/

#include   "tx_api.h"
#include   <stdio.h>

#define     STACK_SIZE         1024
#define     BYTE_POOL_SIZE     9120
#define     NUMBER_OF_MESSAGES 100
#define     MESSAGE_SIZE       TX_1_ULONG
#define     QUEUE_SIZE         MESSAGE_SIZE*sizeof(ULONG)*NUMBER_OF_MESSAGES


/* Define the ThreadX object control blocks...  */

TX_THREAD      speedy_thread;  /* higher priority thread */
TX_THREAD      slow_thread;    /* lower priority thread */

TX_BYTE_POOL   my_byte_pool;   /* byte pool for stacks and queues */
TX_SEMAPHORE   gatekeeper;     /* indicate how many objects available */

TX_QUEUE       queue_1;        /* queue for multiple object suspension */
TX_QUEUE       queue_2;        /* queue for multiple object suspension */

TX_TIMER       stats_timer;    /* generate statistics at intervals */
TX_TIMER       queue_timer_1;  /* send message to queue_1 at intervals */
TX_TIMER       queue_timer_2;  /* send message to queue_2 at intervals */

/* Variables needed to get info about the message queue */
CHAR      *info_queue_name;
TX_THREAD *first_suspended;
TX_QUEUE  *next_queue;
ULONG     enqueued_1=0, enqueued_2=0, suspended_count=0, available_storage=0;

/* Define the variables used in the sample application...  */
ULONG  speedy_thread_counter=0, total_speedy_time=0;
ULONG  slow_thread_counter=0, total_slow_time=0;
ULONG  send_message_1[TX_1_ULONG]={0X0}, send_message_2[TX_1_ULONG]={0X0};
ULONG  receive_message_1[TX_1_ULONG], receive_message_2[TX_1_ULONG];

/* speedy_thread and slow_thread entry function prototypes */
void    speedy_thread_entry(ULONG thread_input);
void    slow_thread_entry(ULONG thread_input);

/* timer entry function prototypes */
void    queue_timer_1_entry(ULONG thread_input);
void    queue_timer_2_entry(ULONG thread_input);
void    print_stats(ULONG);

/* event notification function prototypes */
void    queue_1_send_notify(TX_QUEUE *queue_1_ptr);
void    queue_2_send_notify(TX_QUEUE *queue_2_ptr);


/****************************************************/
/*               Main Entry Point                   */
/****************************************************/

/* Define main entry point.  */

int main()
{
    /* Enter the ThreadX kernel.  */
    tx_kernel_enter();
}


/****************************************************/
/*             Application Definitions              */
/****************************************************/


/* Define what the initial system looks like.  */

void    tx_application_define(void *first_unused_memory)
{

CHAR *speedy_stack_ptr;
CHAR *slow_stack_ptr;
CHAR *queue_1_ptr;
CHAR *queue_2_ptr;

   /* Create a byte memory pool from which to allocate the thread stacks. */
   tx_byte_pool_create(&my_byte_pool, "my_byte_pool",
                       first_unused_memory, BYTE_POOL_SIZE);

   /* Create threads, queues, the semaphore, timers, and register functions
      for event-chaining */

   /* Allocate the stack for speedy_thread.  */
   tx_byte_allocate(&my_byte_pool, (VOID **) &speedy_stack_ptr, STACK_SIZE, 
                    TX_NO_WAIT);

   /* Create speedy_thread.  */
   tx_thread_create(&speedy_thread, "speedy_thread", speedy_thread_entry, 0,  
                    speedy_stack_ptr, STACK_SIZE, 5, 5, TX_NO_TIME_SLICE, 
                    TX_AUTO_START);

   /* Allocate the stack for slow_thread.  */
   tx_byte_allocate(&my_byte_pool, (VOID **) &slow_stack_ptr, STACK_SIZE, 
                    TX_NO_WAIT);

   /* Create slow_thread */
   tx_thread_create(&slow_thread, "slow_thread", slow_thread_entry, 1,
                    slow_stack_ptr, STACK_SIZE, 15, 15, TX_NO_TIME_SLICE, 
                    TX_AUTO_START);

   /* Create the message queues used by both threads.  */
   tx_byte_allocate(&my_byte_pool, (VOID **) &queue_1_ptr,
                    QUEUE_SIZE, TX_NO_WAIT);

   tx_queue_create (&queue_1, "queue_1", MESSAGE_SIZE,
                    queue_1_ptr, QUEUE_SIZE);

   tx_byte_allocate(&my_byte_pool, (VOID **) &queue_2_ptr,
                    QUEUE_SIZE, TX_NO_WAIT);

   tx_queue_create (&queue_2, "queue_2", MESSAGE_SIZE,
                    queue_2_ptr, QUEUE_SIZE);

   /* Create the gatekeeper semaphore that counts the available objects */
   tx_semaphore_create (&gatekeeper, "gatekeeper", 0); 

   /* Create and activate the stats timer */
   tx_timer_create (&stats_timer, "stats_timer", print_stats,
                    0x1234, 500, 500, TX_AUTO_ACTIVATE);

   /* Create and activate the timer to send messages to queue_1 */
   tx_timer_create (&queue_timer_1, "queue_timer", queue_timer_1_entry,
                    0x1234, 12, 12, TX_AUTO_ACTIVATE);

   /* Create and activate the timer to send messages to queue_2 */
   tx_timer_create (&queue_timer_2, "queue_timer", queue_timer_2_entry,
                    0x1234, 9, 9, TX_AUTO_ACTIVATE);

   /* Register the function to increment the gatekeeper semaphore when a
      message is sent to queue_1 */
   tx_queue_send_notify(&queue_1, queue_1_send_notify);

   /* Register the function to increment the gatekeeper semaphore when a
      message is sent to queue_2 */
   tx_queue_send_notify(&queue_2, queue_1_send_notify);
}


/****************************************************/
/*              Function Definitions                */
/****************************************************/


/* Entry function definition of speedy_thread
   it has a higher priority than slow_thread */

void    speedy_thread_entry(ULONG thread_input)
{

ULONG   start_time, cycle_time=0, current_time=0;
UINT    status;

   /* This is the higher priority speedy_thread */

   while(1)
   {
      /* Get the starting time for this cycle */
      start_time = tx_time_get();

      /* Activity 1:  2 ticks.  */
      tx_thread_sleep(2);

      /* Activity 2:  5 ticks.  */
      /* wait for a message to appear on either one of the two queues */
      tx_semaphore_get (&gatekeeper, TX_WAIT_FOREVER); 

      /* Determine whether a message queue_1 or queue_2 is available */
      status = tx_queue_receive (&queue_1, receive_message_1, TX_NO_WAIT);

      if (status == TX_SUCCESS)
         ; /* A message on queue_1 has been found - process */
      else
         /* Receive a message from queue_2 */
         tx_queue_receive (&queue_2, receive_message_2, TX_WAIT_FOREVER);

       tx_thread_sleep(5);

      /* Increment the thread counter and get timing info  */
      speedy_thread_counter++;
      current_time = tx_time_get();
      cycle_time = current_time - start_time;
      total_speedy_time = total_speedy_time + cycle_time;
   }
}

/************************************************************/

/* Entry function definition of slow_thread
   it has a lower priority than speedy_thread */

void    slow_thread_entry(ULONG thread_input)
{

ULONG   start_time, current_time=0, cycle_time=0;
UINT    status;


   while(1)
   {
      /* Get the starting time for this cycle */
         start_time = tx_time_get();

      /* Activity 3 - sleep 12 ticks.  */
      /* wait for a message to appear on either one of the two queues */
      tx_semaphore_get (&gatekeeper, TX_WAIT_FOREVER);

      /* Determine whether a message queue_1 or queue_2 is available */
      status = tx_queue_receive (&queue_1, receive_message_1, TX_NO_WAIT);

      if (status == TX_SUCCESS)
         ; /* A message on queue_1 has been found - process */
      else
         /* Receive a message from queue_2 */
         tx_queue_receive (&queue_2, receive_message_2, TX_WAIT_FOREVER);

      tx_thread_sleep(12);


      /* Activity 4:  8 ticks.  */
      tx_thread_sleep(8);

      /* Increment the thread counter and get timing info  */
      slow_thread_counter++;

      current_time = tx_time_get();
      cycle_time = current_time - start_time;
      total_slow_time = total_slow_time + cycle_time;
    }
}

/*****************************************************/
/* print statistics at specified times */
void print_stats (ULONG invalue)
{
ULONG   current_time, avg_slow_time, avg_speedy_time;

   if ((speedy_thread_counter>0) && (slow_thread_counter>0))
   {
      current_time = tx_time_get();
      avg_slow_time = total_slow_time / slow_thread_counter;
      avg_speedy_time = total_speedy_time / speedy_thread_counter;
      tx_queue_info_get (&queue_1, &info_queue_name, &enqueued_1, 
                         &available_storage, &first_suspended, 
                         &suspended_count, &next_queue);
      tx_queue_info_get (&queue_2, &info_queue_name, &enqueued_2, 
                         &available_storage, &first_suspended, 
                         &suspended_count, &next_queue);
      printf("\nEvent-Chaining: 2 threads waiting for 2 queues\n\n");
      printf("     Current Time:                    %lu\n", current_time);
      printf("         speedy_thread counter:       %lu\n", speedy_thread_counter);
      printf("        speedy_thread avg time:       %lu\n", avg_speedy_time);
      printf("           slow_thread counter:       %lu\n", slow_thread_counter);
      printf("          slow_thread avg time:       %lu\n", avg_slow_time);
      printf(" total # queue_1 messages sent:       %lu\n", send_message_1[TX_1_ULONG-1]);
      printf(" total # queue_2 messages sent:       %lu\n", send_message_2[TX_1_ULONG-1]);
      printf(" current # messages in queue_1:       %lu\n", enqueued_1);
      printf(" current # messages in queue_2:       %lu\n\n", enqueued_2);

   }
   else printf("Bypassing print_stats function, Current Time: %lu\n", tx_time_get());
}



/*****************************************************/
/* Send a message to queue_1 at specified times */
void queue_timer_1_entry (ULONG invalue)
{

   /* Send a message to queue_1 using the multiple object suspension approach  */
   /* The gatekeeper semaphore keeps track of how many objects are available
      via the notification function */
   send_message_1[TX_1_ULONG-1]++;
   tx_queue_send (&queue_1, send_message_1, TX_NO_WAIT);

}

/*****************************************************/
/* Send a message to the queue at specified times */
void queue_timer_2_entry (ULONG invalue)
{

   /* Send a message to queue_2 using the multiple object suspension approach  */
   /* The gatekeeper semaphore keeps track of how many objects are available
      via the notification function */
   send_message_2[TX_1_ULONG-1]++;
   tx_queue_send (&queue_2, send_message_2, TX_NO_WAIT);

}

/*****************************************************/
/* Notification function to increment gatekeeper semaphore
   whenever a message has been sent to queue_1 */
void queue_1_send_notify(TX_QUEUE *queue_ptr_1)
{
   tx_semaphore_put (&gatekeeper);
}

/*****************************************************/
/* Notification function to increment gatekeeper semaphore
   whenever a message has been sent to queue_2 */
void queue_2_send_notify(TX_QUEUE *queue_ptr_2)
{
   tx_semaphore_put (&gatekeeper);
}

Page last modified on July 09, 2019, at 02:35 PM