From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27442 invoked by alias); 26 Nov 2004 09:54:10 -0000 Mailing-List: contact ecos-discuss-help@ecos.sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: ecos-discuss-owner@ecos.sourceware.org Received: (qmail 27316 invoked from network); 26 Nov 2004 09:54:01 -0000 Received: from unknown (HELO hotmail.com) (64.4.43.197) by sourceware.org with SMTP; 26 Nov 2004 09:54:01 -0000 Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC; Fri, 26 Nov 2004 01:54:00 -0800 Message-ID: Received: from 164.164.160.11 by BAY17-DAV17.phx.gbl with DAV; Fri, 26 Nov 2004 09:53:05 +0000 X-Originating-IP: [164.164.160.11] X-Originating-Email: [vijaypadiyar@hotmail.com] X-Sender: vijaypadiyar@hotmail.com From: "Vijay Padiyar" To: "eCos Support" Date: Fri, 26 Nov 2004 10:51:00 -0000 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-OriginalArrivalTime: 26 Nov 2004 09:54:00.0672 (UTC) FILETIME=[DAC27600:01C4D39D] Subject: [ECOS] problem in thread creation and scheduling X-SW-Source: 2004-11/txt/msg00324.txt.bz2 Hi all We are having problems with thread creation in our application programs. So I made a subset of the code in question and put it in one file and ran it. I have a method 'Context::run()' inside a class 'Context'. I am creating two instances of class 'Context' and calling their 'run()' methods from the 'main()' function. The 'run()' method creates a thread and then starts it. After calling the method twice (which creates two separate threads), I call 'cyg_scheduler_start()' at the end of the program. However, the code inside the thread entry function doesn't seem to be executing! Particularly as I can't see the printf's inside the entry function on my terminal. Below is the code of my 'test.cpp' file: ---------------------------------------------------------------------------- ----- #include #include #include #include "test.h" #include #include #include //#define SIMPLE cyg_mutex_t condMutex, cliblock; cyg_cond_t cond; /* and now variables for the procedure which is the thread */ #ifdef SIMPLE cyg_thread_entry_t simple_program; #else //static void *contextStart(void *inst); static void contextStart(cyg_addrword_t *inst); //cyg_thread_entry_t contextStart; #endif int wait(bool value, int millisec); #ifndef SIMPLE void Context::startInternal() { cyg_mutex_lock(&cliblock); printf("Entering startInternal()\n"); printf("Context %d spawned", (int)this); cyg_mutex_unlock(&cliblock); int id; cyg_handle_t thread = cyg_thread_self(); id = (int)cyg_thread_get_id(thread); cyg_mutex_lock(&cliblock); printf("Exiting startInternal()\n"); cyg_mutex_unlock(&cliblock); } #endif int Context::run(int prio, char *taskname) { printf("Entering run()\n"); priority = prio; name = *taskname; printf("Context name - %s, Priority - %d, Stack Size - %d\n", taskname, priority, stackSize); // Check to see if run has already been called once - since it // should only be called once. Throw an exception if is has and // return if (started) { printf("context id %d (%08x) already running\n", id, id); //#error "Error!" return -1; } // Indicate the Contexts run has been started started = TRUE; printf("Stack pointer - %d, Stack address - 0x%08x, Thread entry data - 0x%08x\n", stackPtr, &stack[stackPtr], (cyg_addrword_t)this); #ifdef SIMPLE cyg_thread_create(priority, simple_program, (cyg_addrword_t)stackPtr, taskname, &stack[stackPtr], STACK_SIZE, &handle1, &handle); #else #if 1 cyg_thread_create(priority, (cyg_thread_entry_t *)&contextStart, (cyg_addrword_t)this, taskname, (void *)stack[stackPtr], STACK_SIZE, &handle1, &handle); #else cyg_thread_create(priority, contextStart, (cyg_addrword_t)this, taskname, (void *)stack[stackPtr], STACK_SIZE, &handle1, &handle); #endif #endif stackPtr++; // Increment Stack Pointer - Added by Vijay printf("Thread created\n"); cyg_thread_set_priority(handle1, (cyg_priority_t)(127 - priority/2)); cyg_thread_resume(handle1); printf("Thread started\n"); // wait in the run function until the actual contextEntry // point of the spawned task occurs (spawned condition) printf("Created context %s (%08x), waiting for spawned condition\n", taskname, id); int rc = wait(TRUE,100); if (rc != 0) { printf("Mutex failure %d spawning context %s (%08x)\n", rc, taskname, id); //#error "Mutex failure spawning context" return -1; } else { printf("Context %s: %d (%08x)\n", taskname, id, id); } printf("Exiting run()\n"); return 0; } #ifdef SIMPLE void simple_program(cyg_addrword_t data) { int message = (int) data; int delay; printf("Entering simple_program()"); printf("Beginning execution; thread data is %d\n", message); cyg_thread_delay(200); for (;;) { delay = 200 + (rand() % 50); /* note: printf() must be protected by a call to cyg_mutex_lock() */ cyg_mutex_lock(&cliblock); { printf("Thread %d: and now a delay of %d clock ticks\n", message, delay); } cyg_mutex_unlock(&cliblock); cyg_thread_delay(delay); } printf("Exiting simple_program()"); } #else void contextStart(cyg_addrword_t *inst) { cyg_mutex_lock(&cliblock); printf("Entering contextStart()"); cyg_mutex_unlock(&cliblock); ((Context *)inst)->startInternal(); //test.startInternal(); cyg_mutex_lock(&cliblock); printf("Exiting contextStart()"); cyg_mutex_unlock(&cliblock); } #endif int wait(bool value, int millisec) { int retVal = 1; bool state = 0; printf("Entering wait()\n"); // // We want to lock the guardCondition explicitly, not guard it. This // is so we can release it while waiting // HAL_DELAY_US(1000); if (state != value) { cyg_tick_count_t expire; cyg_resolution_t resolution; cyg_handle_t handle; int err; handle=cyg_real_time_clock(); resolution=cyg_clock_get_resolution(handle); expire=cyg_current_time()+(millisec*1000)*resolution.divisor/(resolution.div idend*1000); // // get the condition mutex... // cyg_mutex_lock(&condMutex); state = value; // Temporary fix while (state != value) { // wait for condition object to signal it has been set if (millisec < 0) err = cyg_cond_wait(&cond); else err = cyg_cond_timed_wait(&cond, expire); if (err == ETIMEDOUT) { printf("Timed out\n"); retVal = 3; break; } else if (err != 0) { printf("Unknown error: %d\n", err); //#error "unknown error" return -1; } // no error, so the condition var was signalled // return to the top of the loop and check // the state printf("Condition signalled\n"); } if (state == value) retVal = 0; cyg_mutex_unlock(&condMutex); } else { retVal = 0; cyg_mutex_unlock(&condMutex); cyg_cond_broadcast(&cond); } printf("Exiting wait()\n"); printf("returning %d\n", retVal); return retVal; } Context::Context() { //printf("This is the body of Context() constructor\n"); } int main(void) { printf("\nEntering main()\n"); char *name1 = "Task 1", *name2 = "Task 2"; Context test, test2; printf("Address of 'test' - 0x%08x, 'test2' - 0x%08x\n",&test, &test2); cyg_mutex_init(&cliblock); cyg_mutex_init(&condMutex); cyg_cond_init(&cond,&condMutex); test.stackSize = STACK_SIZE; printf("\nCalling run()\n\n"); test.run(10,name1); printf("\nCalling run()\n\n"); test2.run(20,name2); printf("Starting thread scheduler\n"); cyg_scheduler_start(); printf("Exiting main()\n"); return 0; } ---------------------------------------------------------------------------- Following is the associated header file: ---------------------------------------------------------------------------- #include #include #define NTHREADS 2 // Conservative estimate for now #define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL // Fixed at 5664 bytes for PowerPC static int stackPtr = 0; static char stack[NTHREADS][STACK_SIZE]; const int MAX_ECOS_NAME_LEN = 10; #define TRUE 1 #define FALSE 0 class Context { public: /// This enum contains public Class constants enum { /// defaults to 32 MAX_NAME_LEN = 32, /// defaults to 100 BASE_PRIORITY = 100, /// defaults to 4 (which translates to 4K) BASE_STACK_SIZE = 100 }; // // public Class methods // public: // ------------------------------------------------------------------------ /** * Returns the Context object associated with the currently executing * OS context * * @return Context object reference of currently executing OS context * * @exception NoSuchContextException if OS Context was not spawned * through the context class */ // ------------------------------------------------------------------------ //static Context& getCurrent(); // ------------------------------------------------------------------------ /** * Returns the Context ID associated with the currently executing * OS context * * @return Context ID of currently executing OS context */ // ------------------------------------------------------------------------ static int getCurrentId(); // ------------------------------------------------------------------------ /** * delay a task's execution for a specified time * * @param millisec number of milliseconds to delay */ // ------------------------------------------------------------------------ static void sleep(unsigned int millisec); // // public instance methods // public: // ------------------------------------------------------------------------ /** * dtor */ // ------------------------------------------------------------------------ virtual ~Context() {} // ------------------------------------------------------------------------ /** * abstract function to define a subclass' entry point */ // ------------------------------------------------------------------------ //virtual void contextEntry()=0; // ------------------------------------------------------------------------ /** * abstract function to return the currently executing process */ // ------------------------------------------------------------------------ //virtual Process& getProcess(); // ------------------------------------------------------------------------ /** * This function is called on the object to start the new OS context. * It will result in a subclass' contextEntry method being called * under the new context and this function will return to the * calling context. This function is analogous to exec() or * spawn() under functional systems. * * @exception ContextAlreadyRunningException if run is called more * than once for the same class * @exception ContextNotCreatedException if the OS context failed * to be created. */ // ------------------------------------------------------------------------ virtual int run(int prio, char *taskname); // ------------------------------------------------------------------------ /** * Blocks a caller until the OS context associated with this Context * object is terminated */ // ------------------------------------------------------------------------ void waitForExit(); // ------------------------------------------------------------------------ /** * Returns this Context's ID * * @return the ID given to this context by the OS */ // ------------------------------------------------------------------------ int getContextId() const; // ------------------------------------------------------------------------ /** * Returns this Context's name * * @return the name given to this context when instantiated */ // ------------------------------------------------------------------------ const char *getContextName() const; // ------------------------------------------------------------------------ /** * Dumps the state of the object to the Trace facility * * @param level Trace level constant to use * @param indent Level of indentation */ // ------------------------------------------------------------------------ //virtual void dump(int level, int indent = 0); // ------------------------------------------------------------------------ /** * Sets the Process priority * * @return */ // ------------------------------------------------------------------------ //void setPriority(int priority); // ------------------------------------------------------------------------ /** * Sets the Process StackSize * * @return */ // ------------------------------------------------------------------------ //void setStackSize(int stackSize); // // protected methods // //protected: // ------------------------------------------------------------------------ /** * ctor * * @param name string name to associate with the context * @param priority initial priority of this context * @param stackSize amount of stack space for the context (1 = 1K) */ // ------------------------------------------------------------------------ Context(const char *name, int priority=BASE_PRIORITY, int stackSize=BASE_STACK_SIZE); /// Hide constructor Context(); /// Hide constructor Context(Context &context); // ------------------------------------------------------------------------ /** * Terminates the OS context associated with this Context object */ // ------------------------------------------------------------------------ bool remove(); /// // protected // // // private // private: int id; // TID bool spawned; // indicates when task is spawned //Mutex idleMutex; // used in waitForExit for Windows/solaris //Mutex exitMutex; // used in waitForExit for VxWorks bool started; // indicates the OS Context has been started cyg_thread handle; cyg_handle_t handle1; public: //char name[MAX_NAME_LEN + 1]; // context Name char name; // context Name int priority; // current priority value int stackSize; // current stack size /// Implemenetation function ONLY - DO NOT CALL. Used at the OS context point to enter at/ void startInternal(); // this is an implementation function -- DO NOT CALL!!! }; inline bool Context::remove() { //return (pthread_cancel(id) == 0); return(cyg_thread_delete(id)); } ---------------------------------------------------------------------------- ------- Following is the output when the program is executed (with SIMPLE not defined): ---------------------------------------------------------------------------- ------- Entering main() Address of 'test' - 0xe4e98, test2 - 0xe4fa8 Calling run() Entering run() Context name - Task 1, Priority - 10, Stack Size - 5664 Stack pointer - 0, Stack address - 000d18a0, Thread entry data - 937624 Thread created Thread started Created context Task 1 (00000000), waiting for spawned condition Entering wait() Exiting wait() returning 0 Context Task 1: 0 (00000000) Exiting run() Calling run() Entering run() Context name - Task 2, Priority - 20, Stack Size - 286326802 Stack pointer - 1, Stack address - 000d2ec0, Thread entry data - 937896 Thread created Thread started Created context Task 2 (00000000), waiting for spawned condition Entering wait() Exiting wait() returning 0 Context Task 2: 0 (00000000) Exiting run() Starting thread scheduler ---------------------------------------------------------------------------- --- What could be going wrong? Between 'Thread created' and 'Thread started', we should see the printf's in the entry function. But we don't. All the data passed to the thread create function seems to be ok. However, when SIMPLE is defined and the program is run, the 'simple_function()' executes perfectly, and thread scheduler works just fine! Regards Vijay -- Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss