I guess cogstart is my fault. I thought that passing the address and size of the stack would likely result in fewer errors than passing the top of the stack but I guess that didn't really work out. The scheme that _start_cog_thread has the advantage that one fewer arguments have to be passed to the function but it is awkward because you have to do the funky "array + sizeof(array)" thing to pass the correct address. Not sure which is better.
David, perhaps it would be a good idea to create a new (inline) function that starts a cog and takes 4 parameters: (1) cog code load address (2) pointer to stack array, (3) sizeof stack array (4) value to put at the bottom of the stack. Basically something like this:
int8_t // Returns cogid or -1
inline __ez_start_cog(
uint32_t *load_start __HUBDATA, // start of code
uint32_t *stack __HUBDATA, // start of stack array
size_t stacksize, // sizeof stack array including mailbox
uint32_t mailbox) // Value to pass in *__PAR
{
if (stacksize)
{
// Move pointer to the last word of the array and store the mailbox value there
stack += (stacksize - 1) / sizeof(uint32_t);
*stack = mailbox;
}
// Pass pointer to mailbox to cognew
// Note, the actual stack space is one less than the provided space because
// the mailbox value takes up one long in the array
return __cognew(load_start, stack);
}
...
static long thestack[STACK_SIZE];
struct mymailbox
{
...
} themailbox;
thecog = __ez_start_cog(my_cog_load_start, thestack, sizeof(thestack), (uint32_t)&themailbox);
I know the above is a little funky too because it stores the mailbox parameter even though the array can probably be statically initialized (so storing may not be necessary). Also the stack size ends up one longword less than what you specify to the function.
But at least the call to the function should be a lot clearer to beginners than this ugly construct which I used in my code:
Is there documentation somewhere that will teach me how to use threading completely, as implemented in PropGCC? I just looked at "struct _thread" and noticed there seems to be a lot of stuff in there that I didn't know about and could potentially be very useful someday
For the moment, I'm switching to cogstart() since it is simpler and I'm not using any of the threading functionality anyway.
It is very important to read the pthread.h comments with good attention to detail. The first comment is probably the most important.
/**
* @file include/pthread.h
* @brief Provides API for implementation of pthread functions.
*
* POSIX threads are a set of functions that support applications
* with requirements for multiple flows of control, called threads,
* within a process. Multithreading is used to improve the
* performance of a program.
*
* The pthread module provides a subset of the POSIX standard
* pthread library for allowing multiple threads to run on
* multiple COG instances of the PropellerGCC LMM interpreter.
* Multiple threads can also run on an XMM interpreter, but
* only one XMM interpreter can run at any given time.
*
* @pre It is very important to understand that pthreads provide
* a cooperative non-preemptive multithreading system.
* The consequences are that certain rules will apply. I.E.
* @li The Propeller waitcnt() function can not be used.
* @li Delays can only be introduced with usleep() and its variations.
* @li Standard printf() and friends must be used.
* @li Do not use -Dprintf=__simple_printf with pthreads.
* @li Threads must not hog the LMM COG kernel; they must yield.
* @li Gobal data must be protected by mutex/semaphore.
*
* Copyright (c) 2011 Parallax, Inc.
* Written by Eric R. Smith, Total Spectrum Software Inc.
* MIT licensed.
*/
The great thing about propeller-gcc pthreads is that it allows full SMP in CMM/LMM modes (more threads than cogs) and generally follows typical pthreads usage.
The down side is that threading is an advanced topic. Copy/pasters will fail in using pthreads. Anyone with a computer science background, like you, should do fine though.
* The pthread module provides a subset of the POSIX standard
* pthread library for allowing multiple threads to run on
* multiple COG instances of the PropellerGCC LMM interpreter.
* Multiple threads can also run on an XMM interpreter, but
* only one XMM interpreter can run at any given time.
*
* @pre It is very important to understand that pthreads provide * a cooperative non-preemptive multithreading system.
There is some ambiguity in the description in the pthread.h file.
"...multiple threads to run on multiple COG instances..." does not square with "...cooperative non-preemptive..."
Clearly if your threads are running on a single COG we would expect them to be cooperative. But if they are running on multiple-cogs I would hope that is not true.
* The pthread module provides a subset of the POSIX standard
* pthread library for allowing multiple threads to run on
* multiple COG instances of the PropellerGCC LMM interpreter.
* Multiple threads can also run on an XMM interpreter, but
* only one XMM interpreter can run at any given time.
*
* @pre It is very important to understand that pthreads provide * a cooperative non-preemptive multithreading system.
There is some ambiguity in the description in the pthread.h file.
"...multiple threads to run on multiple COG instances..." does not square with "...cooperative non-preemptive..."
Clearly if your threads are running on a single COG we would expect them to be cooperative. But if they are running on multiple-cogs I would hope that is not true.
I guess you're right about them not exactly being "cooperative" if they run in separate COGs but they are still "non-preemptive".
Sort of, yes, no, maybe. "cooperative" and "preemptive" don't really apply to parallel execution. Or is there something weird going on I don't know about?
Sort of, yes, no, maybe. "cooperative" and "preemptive" don't really apply to parallel execution. Or is there something weird going on I don't know about?
I don't think there is anything magic going on. Threads that run on a single COG are cooperative and non-preemptive. Of course, each COG can run one thread at a time and those threads run in parallel.
Comments
David, perhaps it would be a good idea to create a new (inline) function that starts a cog and takes 4 parameters: (1) cog code load address (2) pointer to stack array, (3) sizeof stack array (4) value to put at the bottom of the stack. Basically something like this:
I know the above is a little funky too because it stores the mailbox parameter even though the array can probably be statically initialized (so storing may not be necessary). Also the stack size ends up one longword less than what you specify to the function.
But at least the call to the function should be a lot clearer to beginners than this ugly construct which I used in my code:
(Sorry if none of the above compiles - it's been a while since I used PropGCC)
===Jac
I couldn't stand looking at _start_cog_thread and trying to remember how to use it ... that's why cogstart exists.
For the moment, I'm switching to cogstart() since it is simpler and I'm not using any of the threading functionality anyway.
The best propeller-gcc specific threading documentation we have to offer at the moment is here: https://code.google.com/p/propgcc/source/browse/lib/include/pthread.h
It is very important to read the pthread.h comments with good attention to detail. The first comment is probably the most important.
The great thing about propeller-gcc pthreads is that it allows full SMP in CMM/LMM modes (more threads than cogs) and generally follows typical pthreads usage.
The down side is that threading is an advanced topic. Copy/pasters will fail in using pthreads. Anyone with a computer science background, like you, should do fine though.
Here is an interesting pthread tutorial. https://computing.llnl.gov/tutorials/pthreads/
Propeller-gcc pthreads is not a complete pthread implementation, so not all of that tutorial applies.
It may be instructive to look at the linux.die.net pthread_create man page: http://linux.die.net/man/3/pthread_create
"...multiple threads to run on multiple COG instances..." does not square with "...cooperative non-preemptive..."
Clearly if your threads are running on a single COG we would expect them to be cooperative. But if they are running on multiple-cogs I would hope that is not true.