⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stress_threads.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//        stress_threads.cxx
//
//        Basic thread stress test
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):     rosalia
// Contributors:  rosalia, jskov
// Date:          1999-04-13
// Description:   Very simple thread stress test, with some memory
//                allocation and alarm handling.
//
// Notes:
//  If client_makes_request is big, it means that there are made many more
//  client requests than can be serviced. Consequently, clients are wasting
//  CPU time and should be sleeping more.
//
//  The list of handler invocations show how many threads are running
//  at the same time. The more powerful the CPU, the more the numbers
//  should spread out.
//####DESCRIPTIONEND####

#include <pkgconf/system.h>
#include <cyg/infra/testcase.h>

#include <cyg/hal/hal_arch.h>

#if defined(CYGPKG_KERNEL) && defined(CYGPKG_IO) && defined(CYGPKG_ISOINFRA)

#include <pkgconf/kernel.h>
#include <pkgconf/isoinfra.h>
#include CYGHWR_MEMORY_LAYOUT_H

#if defined(CYGFUN_KERNEL_API_C)

#include <cyg/kernel/kapi.h>

#ifdef CYGINT_ISO_STDIO_FORMATTED_IO

#include <stdio.h>
#include <stdlib.h>

#if defined(CYGPKG_LIBM)

#include <math.h>
#include <assert.h>

#include <cyg/kernel/test/stackmon.h>

#if defined(CYGFUN_KERNEL_THREADS_TIMER)
#if CYGINT_ISO_MALLOC

/* if TIME_LIMIT is defined, it represents the number of seconds this
   test should last; if it is undefined the test will go forever */
#define DEATH_TIME_LIMIT 20
/* #undef DEATH_TIME_LIMIT */

// STACK_SIZE is typical +2kB for printf family calls which use big
// auto variables. Add more for handler which calls perform_stressful_tasks()
#define STACK_SIZE (2*1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL)
#define STACK_SIZE_HANDLER (STACK_SIZE + 30*CYGNUM_HAL_STACK_FRAME_SIZE)

#define N_MAIN 1

// If we have instrumentation enabled, make the execution time in the
// simulator even shorter that we were going to anyway.
#ifdef CYGPKG_KERNEL_INSTRUMENT
#define SIM_DELAY_DIVISOR 100
#else
#define SIM_DELAY_DIVISOR 10
#endif

//-----------------------------------------------------------------------
// Some targets need to define a smaller number of handlers due to
// memory restrictions.
#if defined(CYGMEM_REGION_ram_SIZE) && (CYGMEM_REGION_ram_SIZE < 0x80000)
#define MAX_HANDLERS 4
#define N_LISTENERS 1
#define N_CLIENTS 1

#undef STACK_SIZE
#undef STACK_SIZE_HANDLER
#define STACK_SIZE (1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL)
#define STACK_SIZE_HANDLER (STACK_SIZE + 10*CYGNUM_HAL_STACK_FRAME_SIZE)
#endif

//-----------------------------------------------------------------------
// If no target specific definitions, use defaults
#ifndef MAX_HANDLERS
#define MAX_HANDLERS 19
#define N_LISTENERS 4
#define N_CLIENTS 4
#endif

/* Allocate priorities in this order. This ensures that handlers
   (which are the ones using the CPU) get enough CPU time to actually
   complete their tasks. 

   The empty space ensures that if libc main() thread should happen to
   be in the priority range of the handlers, no handlers are
   accidently reduced so much in priority to get below
   listeners/clients. */

#define P_MAIN_PROGRAM    1
#define P_MAIN_PROGRAM_E  (P_MAIN_PROGRAM+N_MAIN)

#define P_BASE_HANDLER    (P_MAIN_PROGRAM_E)
#define P_BASE_HANDLER_E  (P_BASE_HANDLER+MAX_HANDLERS)

#define P_BASE_EMPTY      (P_BASE_HANDLER_E)
#define P_BASE_EMPTY_E    (P_BASE_EMPTY+2)

#define P_BASE_LISTENER   (P_BASE_EMPTY_E)
#define P_BASE_LISTENER_E (P_BASE_LISTENER+N_LISTENERS)

#define P_BASE_CLIENT     (P_BASE_LISTENER_E)
#define P_BASE_CLIENT_E   (P_BASE_CLIENT+N_CLIENTS)

#define P_MAX             (P_BASE_CLIENT_E)

/* Ensure there's room for what we request */
#if (CYGNUM_KERNEL_SCHED_PRIORITIES >= P_MAX)

/* if we use the bitmap scheduler we must make sure we don't use the
   same priority more than once, so we must store those already in use */
static volatile char priority_in_use[P_MAX];

/* We may not get the priority we ask for (scheduler may decide to ignore
   schedule hint). So keep a table of priorities actually assigned to
   the threads. This information may come in handy for debugging - it's
   not actively used by the code. */
static volatile int  priority_translation[P_MAX];

/* now declare (and allocate space for) some kernel objects, like the
   threads we will use */
cyg_thread main_thread_s;
cyg_thread handler_thread_s[MAX_HANDLERS];
cyg_thread listener_thread_s[N_LISTENERS];
cyg_thread client_thread_s[N_CLIENTS];

/* space for stacks for all threads */
char main_stack[STACK_SIZE];
char handler_stack[MAX_HANDLERS][STACK_SIZE_HANDLER];
char listener_stack[N_LISTENERS][STACK_SIZE];
char client_stack[N_CLIENTS][STACK_SIZE];

/* now the handles for the threads */
cyg_handle_t mainH;
cyg_handle_t handlerH[MAX_HANDLERS];
cyg_handle_t listenerH[N_LISTENERS];
cyg_handle_t clientH[N_CLIENTS];

/* space for thread names */
char thread_name[P_MAX][20];

/* and now variables for the procedure which is the thread */
cyg_thread_entry_t main_program, client_program, listener_program, 
    handler_program;

/* a few mutexes used in the code */
cyg_mutex_t client_request_lock, handler_slot_lock, statistics_print_lock, 
    free_handler_lock;

/* global variables with which the handler IDs and thread priorities
   to free are communicated from handlers to main_program. Access to
   these are protected by free_handler_lock. An id of -1 means the
   that the variables are empty. */
volatile int free_handler_pri = 0;
volatile int free_handler_id = -1;

/* a global variable with which the client and server coordinate */
volatile int client_makes_request = 0;

/* if this is true, clients will not make requests */
volatile int clients_paused = 0;


/* indicates that it's time to print out a report */
volatile int time_to_report = 0;
/* print status after a delay of this many secs. */
int time_report_delay;

/*** now application-specific variables ***/
/* an array that stores whether the handler threads are in use */
volatile int handler_thread_in_use[MAX_HANDLERS];
/* total count of active handlers */
volatile int handler_thread_in_use_count;


/***** statistics-gathering variables *****/
struct s_statistics {
    /* store the number of times each handler has been invoked */
    unsigned long handler_invocation_histogram[MAX_HANDLERS];

    /* store how many times malloc has been attempted and how many times
       it has failed */
    unsigned long malloc_tries, malloc_failures;

    /* how many threads have been created */
    unsigned long thread_creations, thread_exits;
};

struct s_statistics statistics;

/* some function prototypes; those with the sc_ prefix are
   "statistics-collecting" versions of the cyg_ primitives */
cyg_addrword_t sc_thread_create(
    cyg_addrword_t      sched_info,             /* scheduling info (eg pri)  */
    cyg_thread_entry_t  *entry,                 /* entry point function      */
    cyg_addrword_t      entry_data,             /* entry data                */
    char                *name,                  /* optional thread name      */
    void                *stack_base,            /* stack base, NULL = alloc  */
    cyg_ucount32        stack_size,             /* stack size, 0 = default   */
    cyg_handle_t        *handle,                /* returned thread handle    */
    cyg_thread          *thread                 /* put thread here           */
    );

void start_handler(void);
void stop_handler(int handler_id, int handler_pri);
void perform_stressful_tasks(void);
void permute_array(char a[], int size, int seed);
void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp,
                       cyg_alarm *death_alarm_p, int *killed_p);
void print_statistics(int print_full);

/* we need to declare the alarm handling function (which is defined
   below), so that we can pass it to cyg_alarm_initialize() */
cyg_alarm_t report_alarm_func, death_alarm_func;

/* handle and alarm for the report alarm */
cyg_handle_t report_alarmH, counterH, system_clockH;
cyg_alarm report_alarm;

/* main launches all the threads of the test */
int
main(void)
{
    int i;

    CYG_TEST_INIT();
    CYG_TEST_INFO("Stress threads test compiled on " __DATE__);

    cyg_mutex_init(&client_request_lock);
    cyg_mutex_init(&statistics_print_lock);
    cyg_mutex_init(&free_handler_lock);

    /* initialize statistics */
    memset(&statistics, 0, sizeof(statistics));

    /* clear priority table */
    for (i = 0; i < sizeof(priority_in_use); i++)
        priority_in_use[i] = 0;

    /* initialize main thread */
    {
        priority_translation[P_MAIN_PROGRAM] =
            sc_thread_create(P_MAIN_PROGRAM, main_program, (cyg_addrword_t) 0,
                             "main_program", (void *) main_stack, STACK_SIZE,
                             &mainH, &main_thread_s);
        priority_in_use[P_MAIN_PROGRAM]++;
    }

    /* initialize all handler threads to not be in use */
    for (i = 0; i < MAX_HANDLERS; ++i) {
        handler_thread_in_use[i] = 0;
    }
    handler_thread_in_use_count = 0;
    for (i = 0; i < N_LISTENERS; ++i) {
        int prio = P_BASE_LISTENER + i;
        char* name = &thread_name[prio][0];
        sprintf(name, "listener-%02d", i);
        priority_translation[prio] =
            sc_thread_create(prio, listener_program, (cyg_addrword_t) i,
                             name, (void *) listener_stack[i], STACK_SIZE,
                             &listenerH[i], &listener_thread_s[i]);
        CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
        priority_in_use[prio]++;
    }
    for (i = 0; i < N_CLIENTS; ++i) {
        int prio = P_BASE_CLIENT + i;
        char* name = &thread_name[prio][0];
        sprintf(name, "client-%02d", i);
        priority_translation[prio] =
            sc_thread_create(prio, client_program, (cyg_addrword_t) i,
                             name, (void *) client_stack[i], STACK_SIZE,
                             &(clientH[i]), &client_thread_s[i]);
        CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
        priority_in_use[prio]++;
    }

    cyg_thread_resume(mainH);
    for (i = 0; i < N_CLIENTS; ++i) {
        cyg_thread_resume(clientH[i]);
    }
    for (i = 0; i < N_LISTENERS; ++i) {
        cyg_thread_resume(listenerH[i]);
    }

    /* set up the alarm which gives periodic wakeups to say "time to
       print a report */
    system_clockH = cyg_real_time_clock();
    cyg_clock_to_counter(system_clockH, &counterH);

    cyg_alarm_create(counterH, report_alarm_func,
                     (cyg_addrword_t) 4000,
                     &report_alarmH, &report_alarm);
    if (cyg_test_is_simulator) {
        time_report_delay = 2;
    } else {
        time_report_delay = 60;
    }

    cyg_alarm_initialize(report_alarmH, cyg_current_time()+200, 
                         time_report_delay*100);

    return 0;
}

/* main_program() -- frees resources and prints status. */
void main_program(cyg_addrword_t data)
{
#ifdef DEATH_TIME_LIMIT
    cyg_handle_t deathH;
    cyg_alarm death_alarm;
    int is_dead = 0;

    setup_death_alarm(0, &deathH, &death_alarm, &is_dead);
#endif /* DEATH_TIME_LIMIT */

    for (;;) {
        int handler_id = -1;
        int handler_pri = 0;

        cyg_mutex_lock(&free_handler_lock); {
            // If any handler has left its ID, copy the ID and
            // priority values to local variables, and free up the
            // global communication variables again.
            if (-1 != free_handler_id) {
                handler_id = free_handler_id;
                handler_pri = free_handler_pri;
                free_handler_id = -1;
            }
        } cyg_mutex_unlock(&free_handler_lock);

        if (-1 != handler_id) {
            stop_handler(handler_id, handler_pri);
        }

        // If it's time to report status or quit, set pause flag and
        // keep looping until all handlers have stopped.
        if (time_to_report) {
            // Pause clients
            cyg_mutex_lock(&client_request_lock); {
                clients_paused = 1;
            } cyg_mutex_unlock(&client_request_lock);

            // When all handlers have stopped, we can print statistics
            // knowing that all (handler allocated) resources should have
            // been freed. That is, we should be able to determine leaks.
            if (0 == handler_thread_in_use_count) {
                print_statistics(0);

                // We've done the printing now. Resume the system.
                time_to_report = 0;
                cyg_mutex_lock(&client_request_lock); {
                    clients_paused = 0;
                } cyg_mutex_unlock(&client_request_lock);
            } 
        }

#ifdef DEATH_TIME_LIMIT
        // Stop test if time.
        if (is_dead) {
            // Pause clients
            cyg_mutex_lock(&client_request_lock); {
                clients_paused = 1;
            } cyg_mutex_unlock(&client_request_lock);

            // When all handlers have stopped, we can print statistics
            // knowing that all (handler allocated) resources should have
            // been freed. That is, we should be able to determine leaks.
            if (0 == handler_thread_in_use_count) {
                print_statistics(1);
                CYG_TEST_PASS_FINISH("Kernel thread stress test OK");
            }
        }
#endif /* DEATH_TIME_LIMIT */

        cyg_thread_delay(3);
    }
}

/* client_program() -- an obnoxious client which makes a lot of requests */
void client_program(cyg_addrword_t data)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -