This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

problem in thread creation and scheduling


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 <cyg/kernel/kapi.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_intr.h>

#include "test.h"

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

//#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 <cyg/kernel/kapi.h>
#include <cyg/hal/hal_arch.h>

#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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]