public inbox for ecos-discuss@sourceware.org
 help / color / mirror / Atom feed
* [ECOS] problem in thread creation and scheduling
@ 2004-11-26 10:51 Vijay Padiyar
  2004-11-26 11:18 ` Nick Garnett
  0 siblings, 1 reply; 5+ messages in thread
From: Vijay Padiyar @ 2004-11-26 10:51 UTC (permalink / raw)
  To: eCos Support

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

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [ECOS] problem in thread creation and scheduling
  2004-11-26 10:51 [ECOS] problem in thread creation and scheduling Vijay Padiyar
@ 2004-11-26 11:18 ` Nick Garnett
  2004-12-02 13:07   ` Vijay Padiyar
  0 siblings, 1 reply; 5+ messages in thread
From: Nick Garnett @ 2004-11-26 11:18 UTC (permalink / raw)
  To: Vijay Padiyar; +Cc: eCos Support

"Vijay Padiyar" <vijaypadiyar@hotmail.com> writes:

> 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:

> 
> 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!


The problem is that there are bugs in your code. After a brief
inspection I found the following:

1. The test and test2 objects are allocated as locals in main(). Since
   your constructor does no initialization, the fields of these
   objects will contain whatever random data was on the stack. When
   main exits these objects will be destroyed and may be overwritten.

2. In most configurations main() runs in a thread so
   cyg_scheduler_start() has already been called. Calling it again
   will have undefined effects.

3. You call cyg_thread_set_priority() with a priority of (127 - priority/2).
   eCos only supports priorities in the range 0..31.


I have no idea whether fixing these bugs will cause your program to
run, but it certainly won't run without it.


-- 
Nick Garnett                    eCos Kernel Architect
http://www.ecoscentric.com/     The eCos and RedBoot experts


-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [ECOS] problem in thread creation and scheduling
  2004-11-26 11:18 ` Nick Garnett
@ 2004-12-02 13:07   ` Vijay Padiyar
  2004-12-02 13:21     ` Andrew Lunn
  0 siblings, 1 reply; 5+ messages in thread
From: Vijay Padiyar @ 2004-12-02 13:07 UTC (permalink / raw)
  To: Nick Garnett, eCos Support

Hi Nick

Hey yeh you were right! Somehow we overlooked the vital fact that the
priority levels need to be between 0 and 31 for eCos!!! Actually we're
developing code to run on both VxWorks and eCos, so we have common variables
that are passed to the equivalent functions in all the files. Here, we
passed the 'priority' variable directly to 'cyg_thread_create()' without
realizing that its value ranges between 0 and 255.

I now added the following lines to my code:

#ifdef ECOS
..
priority = (int)(priority/8);
..
cyg_thread_create(priority,...)
..
#endif

Thanks a lot for your help mate!!!

Regards

Vijay


----- Original Message -----
From: "Nick Garnett" <nickg@ecoscentric.com>
To: "Vijay Padiyar" <vijaypadiyar@hotmail.com>
Cc: "eCos Support" <ecos-discuss@sources.redhat.com>
Sent: Friday, November 26, 2004 4:37 PM
Subject: Re: [ECOS] problem in thread creation and scheduling


> "Vijay Padiyar" <vijaypadiyar@hotmail.com> writes:
>
> > 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:
>
> >
> > 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!
>
>
> The problem is that there are bugs in your code. After a brief
> inspection I found the following:
>
> 1. The test and test2 objects are allocated as locals in main(). Since
>    your constructor does no initialization, the fields of these
>    objects will contain whatever random data was on the stack. When
>    main exits these objects will be destroyed and may be overwritten.
>
> 2. In most configurations main() runs in a thread so
>    cyg_scheduler_start() has already been called. Calling it again
>    will have undefined effects.
>
> 3. You call cyg_thread_set_priority() with a priority of (127 -
priority/2).
>    eCos only supports priorities in the range 0..31.
>
>
> I have no idea whether fixing these bugs will cause your program to
> run, but it certainly won't run without it.
>
>
> --
> Nick Garnett                    eCos Kernel Architect
> http://www.ecoscentric.com/     The eCos and RedBoot experts
>
>

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [ECOS] problem in thread creation and scheduling
  2004-12-02 13:07   ` Vijay Padiyar
@ 2004-12-02 13:21     ` Andrew Lunn
  2004-12-03  5:42       ` Vijay Padiyar
  0 siblings, 1 reply; 5+ messages in thread
From: Andrew Lunn @ 2004-12-02 13:21 UTC (permalink / raw)
  To: Vijay Padiyar; +Cc: eCos Support

On Thu, Dec 02, 2004 at 06:37:44PM +0530, Vijay Padiyar wrote:
> Hi Nick
> 
> Hey yeh you were right! Somehow we overlooked the vital fact that the
> priority levels need to be between 0 and 31 for eCos!!! Actually we're
> developing code to run on both VxWorks and eCos, so we have common variables
> that are passed to the equivalent functions in all the files. Here, we
> passed the 'priority' variable directly to 'cyg_thread_create()' without
> realizing that its value ranges between 0 and 255.
> 
> I now added the following lines to my code:
> 
> #ifdef ECOS
> ..
> priority = (int)(priority/8);

This might not be the best solution, depending on your code.  You
might find somebody has written code which uses the fact that VxWorks
priority 9 and 10 are different. With eCos this will not be true.  You
probably need to check all your code to see how prorities are actually
used. You might need to map each unique priority your application is
using to a unique eCos priority.

> ..
> cyg_thread_create(priority,...)
> ..
> #endif

I suggest you enable assertions. eCos will then tell you about things
like this where you are using the API wrongly.

        Andrew

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [ECOS] problem in thread creation and scheduling
  2004-12-02 13:21     ` Andrew Lunn
@ 2004-12-03  5:42       ` Vijay Padiyar
  0 siblings, 0 replies; 5+ messages in thread
From: Vijay Padiyar @ 2004-12-03  5:42 UTC (permalink / raw)
  To: Andrew Lunn, eCos Support

Hi Andrew

Yes I realized that mapping the priority levels to a narrower range might
have that effect. However, we are only using certain fixed priorities like
10, 75, 100, etc., so it won't matter for our code. Thanks a lot for
pointing it out though!

By the way, we wish to port a section of our code where the Windows portion
creates a named pipe using 'CreateNamedPipe()' and the VxWorks portion
creates a simple TTY-type terminal using 'ptyDevCreate().' The aim is to
implement some kind of Telnet service on the system. Can you suggest any
appropriate eCos function for the same? One option suggested was to create
message boxes for the eCos portion, using 'cyg_mbox_create().' Will this
serve the purpose? We tried to set a TTY interface using the eCos TTY
functions, but didn't get too far as it didn't seem to fit in.

Regards

Vijay



----- Original Message -----
From: "Andrew Lunn" <andrew@lunn.ch>
To: "Vijay Padiyar" <vijaypadiyar@hotmail.com>
Cc: "eCos Support" <ecos-discuss@sources.redhat.com>
Sent: Thursday, December 02, 2004 6:50 PM
Subject: Re: [ECOS] problem in thread creation and scheduling


> On Thu, Dec 02, 2004 at 06:37:44PM +0530, Vijay Padiyar wrote:
> > Hi Nick
> >
> > Hey yeh you were right! Somehow we overlooked the vital fact that the
> > priority levels need to be between 0 and 31 for eCos!!! Actually we're
> > developing code to run on both VxWorks and eCos, so we have common
variables
> > that are passed to the equivalent functions in all the files. Here, we
> > passed the 'priority' variable directly to 'cyg_thread_create()' without
> > realizing that its value ranges between 0 and 255.
> >
> > I now added the following lines to my code:
> >
> > #ifdef ECOS
> > ..
> > priority = (int)(priority/8);
>
> This might not be the best solution, depending on your code.  You
> might find somebody has written code which uses the fact that VxWorks
> priority 9 and 10 are different. With eCos this will not be true.  You
> probably need to check all your code to see how prorities are actually
> used. You might need to map each unique priority your application is
> using to a unique eCos priority.
>
> > ..
> > cyg_thread_create(priority,...)
> > ..
> > #endif
>
> I suggest you enable assertions. eCos will then tell you about things
> like this where you are using the API wrongly.
>
>         Andrew
>

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2004-12-03  5:42 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-11-26 10:51 [ECOS] problem in thread creation and scheduling Vijay Padiyar
2004-11-26 11:18 ` Nick Garnett
2004-12-02 13:07   ` Vijay Padiyar
2004-12-02 13:21     ` Andrew Lunn
2004-12-03  5:42       ` Vijay Padiyar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).