Is Cheap Threads MISRA compliant? In a word, no.
Since I had never even heard of MISRA before I saw your post, I
obviously have made no effort to comply with MISRA. So I googled
a bit, found some MISRA rules at:
ftp://ftp.iar.se/WWWfiles/guides/MisraC.pdf
... and confirmed that Cheap Threads (including the embedded version)
is not compliant.
Most of the non-compliance consists of fairly superficial stylistic
differences. In these respects Cheap Threads could be brought into
compliance through a lot of tedious but mostly mindless tinkering.
However one of the MISRA rules is that the software not use
non-constant function pointers. I'm not sure exactly what MISRA
means by "non-constant", but if it means "not declared as const",
then Cheap Threads can never be compliant with MISRA.
Function pointers are an essential part of the client interface to
Cheap Threads. They define how a thread is to behave, and how it is
to clean up after itself when it terminates. They are treated as
constant in the sense that, once the function pointers are defined
for a given thread, they aren't changed. However they can't possibly
be declared as const, because then they couldn't be assigned values.
Likewise, MISRA prohibits casts of pointer types. While I'm not
sure if the Cheap Threads software itself casts any pointers, it
expects the client code to provide void pointers to thread-specific
data. In order to use the thread-specific data, the client-defined
code for each thread would have to cast the void pointer back to the
appropriate type. While it would be possible to avoid using this
feature, the resulting functionality would be extremely limited, or
require the use of ghastly and cumbersome workarounds to circumvent
MISRA's artificial restriction.
While Cheap Threads doesn't use all the same techniques that MISRA
mandates, it pretty much pursues the same goals, portability in
particular. So far as I know, Cheap Threads makes no assumptions
about the platform, explicitly or implicitly, beyond the availability
of Standard C and certain standard library functions.
If you want to use Cheap Threads, I expect you'll need to spend a lot
of time bringing it into compliance, largely in cosmetic changes.
For example MISRA requires that built-in types be disguised by
typedefs such as INT_16 for int. Since Cheap Threads doesn't care
how wide an int is, such a typedef would add nothing but obscurity.
In addition you'll need to get approval for exceptions for things like
the use of function pointers and void pointers. I gather that MISRA
allows exceptions when they are defensible and documented, but I don't
know just how much you can get away with.
Thanks for your interest. I wish I had better news for you.
Scott McKellar
http://home.swbell.net/mck9/ct/
--- jadhav_shubhangi <jadhav_shubhangi@...> wrote:
> Hi,
>
> I want to use the Embedded version of cheap threads in our
> software and it's a requirement that all our software is MISRA C
> compliant.
>
> Is Embedded cheap threads MISRA C compliant?
>
>
>
>
Hi,
I want to use the Embedded version of cheap threads in our
software and it's a requirement that all our software is MISRA C
compliant.
Is Embedded cheap threads MISRA C compliant?
I recently stumbled across a website that says nice things about Cheap
Threads. Well, I didn't exactly stumble on it, I was Googling.
Anyway here's the URL for the main page:
http://www.zedshaw.com/projects/myriad/introduction/introduction.html
This site, by Zed A. Shaw, is about Myriad -- a framework for writing
servers. He uses Cheap Threads for multithreading, or multitasking,
or whatever you want to call it.
In the context of a server you have to worry about blocking yourself
while you wait for IO. The usual approach is to do your IO in
separate threads, or separate processes, so that you can be doing
other things while you wait for the IO to complete.
This approach doesn't work for Cheap Threads because the
multithreading is only simulated, rather than real. If one Cheap
Thread waits for IO, they all wait.
Myriad addresses this issue by using asynchronous IO. The idea is
that you tell the operating system to start some IO, but instead of
waiting for it to finish, you get control back immediately so that you
can continue doing stuff. Later, by one means or another, you find
out that the IO has completed (or perhaps encountered an error), so
you can use the results and keep going.
Never having written a server, I'm not in a position to evaluate
Myriad, nor Shaw's extended rant against the socket-as-file paradigm.
I also haven't looked at the Myriad source code. However if you want
to know how to do asynchronous IO you might want to take a look.
Shaw also makes a point that I hadn't considered. He says that
conventional multithreading packages can make your application hard to
debug because they do weird things with stack memory. Since Cheap
Threads uses only normal function calls and a single stack, it doesn't
confuse tools like debuggers and garbage collectors.
I'm still doing most of my debugging with printf...
----
This list still gets occasional spam, even though I have configured it
to allow posting only from members. Apparently the spammers are
signing up for robotic memberships. The only way I can prevent the
spam is to make the list moderated, so that I have to approve each
message before it is broadcast. I don't want to take that step unless
the spam becomes intolerable, and so far it's at a pretty low level.
Meanwhile I'm deleting the spam from time to time. I haven't tried to
be very prompt about it because by the time I can delete it, it has
already cluttered your inboxes anyway.
Scott McKellar mck9@...
Depending on how you write to the serial port, Cheap
Threads probably won't help you. The Cheap Threads
web site mentions this point on the Pros and Cons
page.
In order to use Cheap Threads to do IO concurrently
with other processing, you need some form of
non-blocking IO. Most forms of IO, however, are
blocking.
For example, if you call the standard C function
fwrite(), it doesn't return control to the calling
program until it is finished. If you call fwrite()
from within a Cheap Thread, that thread can't continue
until fwrite() returns, and neither can any other
thread. Control switches from one thread to the next
only when the first thread gives up control, and it
can't do that when it's waiting for fwrite() to
finish.
With non-blocking IO you would call some special
function that would return immediately without having
actually done any IO yet. Then your code could do
whatever it wants to do while something in the OS, or
in the hardware, did the IO in the background. You
would also have some way of finding out later whether
the IO had completed, and whether it had been
successful.
Non-blocking IO is not very common unless you are
working at a very low level, with device drivers or
disk controllers or something. I've never done it
myself. There are two main ways to fake it:
1. Use true multithreading, as with Pthreads or Java.
2. Spawn a separate process to do the IO, and use some
form of interprocess communication to pass the data
back and forth, such as sockets or a shared memory
segment.
The choice between these two methods depends in part
on the environment. In UNIX and Linux it's probably
more common to spawn a separate process. In Windows,
where there's more overhead involved in spawning a
process, you may prefer to use some form of true
multithreading.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
--- dol_roshan <dol_roshan@...> wrote:
> im a student
> im new to this library
> i need help to run multi tasking in C
> i need to process the data and simultaniously send
> it through serial
> port through a queue
> plz help me to use this library
>
> roshan
im a student
im new to this library
i need help to run multi tasking in C
i need to process the data and simultaniously send it through serial
port through a queue
plz help me to use this library
roshan
After almost a year, I have finally updated the documentation on the
Cheap Threads website to reflect the new ct_return() function. See
my last couple of postings for a summary. The Freshmeat announcement
will probably come out tomorrow.
Also Yahoo! has notified me that they are about to shut down this
mailing list due to lack of activity. My post today will give it
another 90 days to live, and there may be a few more postings
generated from the Freshmeat announcement. However if there isn't
enough interest to keep the mailing list alive, I'm not going to post
occasional messages just to keep it on life support.
Ironically the only thing that kept it alive this long was spam.
Somehow we got onto somebody's sucker list and started to receive
various spam messages, many of them in some unintelligible font. I
changed the rules so as to allow posting only from registered
members, and that has kept the spammers out.
Unless there is an unexpected flurry of interest in Cheap Threads, I
don't plan to develop it much further -- not because it's dead but
because it's complete. It does what it's intended to do, correctly
so far as I know, and doesn't obviously need anything more. If you
want something further, you can probably build it yourself as an add-
on. If you can't add it without getting into the internals, maybe I
can help. You should be able to reach me by email even if the
mailing list disappears.
As Pieter Hintjens of iMatix once remarked (and I probably haven't
gotten the quote exactly right): don't confuse stability with
stagnation, nor change with progress.
I installed a new release of Cheap Threads that includes the new
ct_return() function. I described this function in my posting
of October 19. In brief, it returns control to the scheduler
by a setjmp/longjmp mechanism instead of by a normal return
statement.
This functionality is available only if you compile with the
macro CT_RETURN defined. Otherwise the code is unaffected by
this release.
The source code for this new function is included in the zipped
archive on the web site, both for standard Cheap Threads and for
embedded Cheap Threads. I haven't yet changed the documentation to
match. Writing the documentation generally takes longer than writing
the code.
I apologize for keeping this release in limbo for so long. I
got distracted by another project -- a utility for removing
unwanted elements from HTML files. See:
http://home.swbell.net/mck9/html_scrub/
The targetted user is someone who receives HTML contributions from
other people, and has to eliminate certain kinds of HTML tags or
attributes in order to apply site standards.
(In particular the targetted user is Pamela Jones of Groklaw, a
site that monitors legal issues surrounding Linux and other open
software. Visit Groklaw at http://www.groklaw.net.)
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
You can't call a C++ member function directly from C.
In the case of a non-static member function, the compiler arranges to
pass an additional parameter -- a pointer to the object instance --
that does not appear in the source code. So your int run(void * pData)
is really int run(PortChecker * pPC, void * pData).
On many systems the scheduler could probably invoke a static member
function, which does not receive such an additional parameter.
However the Standard does not guarantee that this approach will work.
The portable approach is to write a thin wrapper, which will probably
be some variant of the following:
extern "C" int run_PortChecker( void * pData )
{
PortChecker * pPC = static_cast< PortChecker * >( pData );
return pPC->run();
}
The above is uncompiled, untested, and probably garbled somewhere. but
it should point you in the right direction.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
Antz wrote:
>
> Greetingz all.
>
> Once again I have stumbled across a problem using the Cheap_Threads C-code
> in conjunction with my own C++ code. The story goes a bit like this...
>
> I have a class called PortChecker (for example), this class contains a
> member function called with the prototype: int run(void * pData)
>
> Now this run method is what I want the Cheap_Threads scheduler to call.
> I've tried a number of things including returning function pointers (with
> no success).
>
> Anyone have any useful ideas?
>
> Thnx.
>
> -Antz
Greetingz all.
Once again I have stumbled across a problem using the Cheap_Threads C-code
in conjunction with my own C++ code. The story goes a bit like this...
I have a class called PortChecker (for example), this class contains a
member function called with the prototype: int run(void * pData)
Now this run method is what I want the Cheap_Threads scheduler to call.
I've tried a number of things including returning function pointers (with
no success).
Anyone have any useful ideas?
Thnx.
-Antz
================================================================
Joe's Playa rules:
1. Con-fi-dence. If you KNOW you sexy, that MAKE you sexy, and IF you sexy, you
KNOW you sexy. It's a sexy circle.
2. Most women WANT to be seduced. You are NOT their opponent. You are their
partner in a very pleasurable crime.
3. Let nothin' and I mean not NOTHIN'... rattle you. See: Rule 1.
=================================================================
The attachments are new prerelease versions of the files
ct.h and ctsched.c, implementing a new function ct_return().
This function is intended to be called from a thread. It
returns control directly to the scheduler through a
setjmp/longjmp mechanism. Prototype:
void ct_return( int rc );
The argument passed should be either CT_OKAY or CT_ERROR,
signifying either success or failure, respectively.
Assuming that a thread is active, the function does not
return, since it transfers control directly to the scheduler.
If you call it when no thread is active, it issues an error
message through ct_report_error() and returns.
NOTE: the ct_return function is available *only* if you compile
ctsched.c with the macro CT_RETURN #defined. Otherwise your
call to ct_return() may compile, but the linker will complain
about an unresolved external reference.
By default -- i.e. if you compile ctsched.c without #defining
the CT_RETURN macro -- both the ct_return statement and the
related setjmp() call are eliminated by conditional compilation.
That way you don't need to incur overhead for functionality
that you don't use.
Until now, the only way for a thread to return control to the
scheduler was through an ordinary return statement. In a large,
complex thread, it may be necessary to return through several
layers of function calls. In such cases it may be more
convenient, or more efficient, to use ct_return().
In particular, it may be useful to use ct_return() when you
encounter an error condition. By returning directly from a
deeply nested function you can avoid cluttering up the other
levels with a lot of tedious and error-prone error checking code.
In this respect calling ct_return() is similar to throwing an
exception in C++ or other languages.
While ct_return() may be useful, I recommend that you not use it
without carefully considering the implications of using a function
based on setjmp() and longjmp(). These functions may not work
properly in some environments. For example, in my ancient creaking
copy of Borland C/C++ 3.0, they won't work reliably in programs
that use overlays. An overlay, in this context, is Borland's way
of sort of simulating virtual memory in an operating system (MS-DOS)
that doesn't really support virtual memory.
In particular, any use of setjmp() and longjmp() is hazardous in
a C++ program. Unlike the throwing of an exception, a call to
longjmp() does not call the destructors of any objects on the stack.
Even in C, calling longjmp() may bypass certain kinds of cleanup
code in the intervening levels.
Despite all these hazards, I thought it would be worthwhile to
provide another option for those who find it useful.
I have not yet tested this new feature very thoroughly, and until
I do, I won't post it to the website. Meanwhile, you're welcome
to give it a try. Regard it as beta. Feedback and bug reports
are welcome.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
-----Original Message----- From: Scott McKellar [mailto:mck9@...] Sent: 08 October 2003 05:23 To: cheapthreads@yahoogroups.com Subject: [cheapthreads] Re: Watchdog function & others ?
--- In cheapthreads@yahoogroups.com, "seabueg" <Josef.Bueger@e...> wrote:
<snip>
> The documention (somehow also mentioned in newsgroup) could be better.
What sort of improvement would you like to suggest?
More example code for "copy/paste".
> But during the first testing I have missed something like > a "watchdog". No matter you are working multi threaded/single > threaded applications the basic platform should/MUST have control > possibilities in case of something ended up in a infinitive loop or > something similar. > > In case of you could already provide something similar, I > appreciate... Properly something could be done already by reserving > the hightest priority to a supervision process (i.e. exit after n- > seconds seconds scheduler not running due to ...).
If a thread gets caught in an endless loop, there's nothing that Cheap Threads can do to detect or terminate the loop, because the loop prevents the scheduler from regaining control. Unlike conventional threads such as POSIX threads, these threads are synchronous. They do not interrupt one another. A thread has to return control to the scheduler before another thread (or the scheduler itself) can run.
Given the way Cheap Threads works, there's no *portable* way to eliminate this problem.
There may be a solution within a particular platform. For example, you may be able to trap a timer signal generated from the hardware. Let your signal handler increment a counter, and if the counter ever gets too big, do a longjmp into some kind of abort routine. Meanwhile some high priority thread, or better yet a user exit, resets the counter to zero whenever it gets a chance.
That much you could do without modifying the Cheap Threads package itself. You might also be able to modify Cheap Threads for a specific platform, but I don't know what such a modification might look like.
So far I have assumed that the infinite loop occurs within a single invocation of a thread. If the infinite loop involves multiple invocations of a thread, then the scheduler is part of the loop. In that case you have a chance to detect the problem by some kind of counter-checking scheme as described above.
All the points stated are (more or less) used already in current designs. I just wanted to know whether a reference design would already be available. > I have encountered the problem as I have tried to implement ~10 > threads including a timeout service for these applications. Properly > a timeout server could be imlemented per default also (reply > suggested message to a thread after supplied timeout, cancel, > restart, ...).
I'm not sure what you're saying here. The Cheap Threads scheduler provides a timeout facility as a compile-time option. However this facility depends on the scheduler's regaining control from the threads. If a thread never returns control, the timeouts won't do anything for you.
As I have started, I thought that the timeout function call "ct_wait_on_timeout" will put the thread immediately on hold and does return after timeout.
> I was just playing for a couple of yours, nevertheless I found it > very useful and awaiting an answer now. > > It seems that you are personally an experienced designer, do you have > an API to other-vendor RTOS platforms?
I've never worked with real time or embedded systems, and I don't have any particular APIs for them. My experience has mostly been in batch applications for businesses. In fact, on the job I have spent more time writing COBOL than writing C. Cheap Threads has been a way for me to play with something I didn't know anything about, and it's very different from anything I've ever done professionally.
In case of you was really just "playing" with C-Implementations, congratulations again... It is better done than a lot of persones do naming themself "expert at ..." > Best regards > Josef
--- In cheapthreads@yahoogroups.com, "seabueg" <Josef.Bueger@e...>
wrote:
<snip>
> The documention (somehow also mentioned in newsgroup) could be
better.
What sort of improvement would you like to suggest?
> But during the first testing I have missed something like
> a "watchdog". No matter you are working multi threaded/single
> threaded applications the basic platform should/MUST have control
> possibilities in case of something ended up in a infinitive loop or
> something similar.
>
> In case of you could already provide something similar, I
> appreciate... Properly something could be done already by reserving
> the hightest priority to a supervision process (i.e. exit after n-
> seconds seconds scheduler not running due to ...).
If a thread gets caught in an endless loop, there's nothing that
Cheap Threads can do to detect or terminate the loop, because the loop
prevents the scheduler from regaining control. Unlike conventional
threads such as POSIX threads, these threads are synchronous. They do
not interrupt one another. A thread has to return control to the
scheduler before another thread (or the scheduler itself) can run.
Given the way Cheap Threads works, there's no *portable* way to
eliminate this problem.
There may be a solution within a particular platform. For example,
you may be able to trap a timer signal generated from the hardware.
Let your signal handler increment a counter, and if the counter ever
gets too big, do a longjmp into some kind of abort routine. Meanwhile
some high priority thread, or better yet a user exit, resets the
counter to zero whenever it gets a chance.
That much you could do without modifying the Cheap Threads package
itself. You might also be able to modify Cheap Threads for a
specific platform, but I don't know what such a modification might
look like.
So far I have assumed that the infinite loop occurs within a single
invocation of a thread. If the infinite loop involves multiple
invocations of a thread, then the scheduler is part of the loop. In
that case you have a chance to detect the problem by some kind of
counter-checking scheme as described above.
> I have encountered the problem as I have tried to implement ~10
> threads including a timeout service for these applications.
Properly
> a timeout server could be imlemented per default also (reply
> suggested message to a thread after supplied timeout, cancel,
> restart, ...).
I'm not sure what you're saying here. The Cheap Threads scheduler
provides a timeout facility as a compile-time option. However this
facility depends on the scheduler's regaining control from the
threads. If a thread never returns control, the timeouts won't do
anything for you.
> I was just playing for a couple of yours, nevertheless I found it
> very useful and awaiting an answer now.
>
> It seems that you are personally an experienced designer, do you
have
> an API to other-vendor RTOS platforms?
I've never worked with real time or embedded systems, and I don't
have any particular APIs for them. My experience has mostly been in
batch applications for businesses. In fact, on the job I have spent
more time writing COBOL than writing C. Cheap Threads has been a way
for me to play with something I didn't know anything about, and it's
very different from anything I've ever done professionally.
> Best regards
> Josef
Thanks for writing.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
Hi!
I was searching of some kind of "of target simulation" environment
for embedded systems. We are using different kind of RTOS systmes for
our products (PABX systems), some of the RTOS suppliers do offer also
support for "soft-client applications". Unfortunately the tools are
always closely tied to a license server for online connection. In
case of you are teleworker (like I'm sometimes) you are forced to
keep the costly line up an running all the time.
After playing around with your demo items (performance,
threading, ...), and tried to transfer my basic needs:
CONGRATULATION, not that far away for "what would be needed".
The documention (somehow also mentioned in newsgroup) could be better.
But during the first testing I have missed something like
a "watchdog". No matter you are working multi threaded/single
threaded applications the basic platform should/MUST have control
possibilities in case of something ended up in a infinitive loop or
something similar.
In case of you could already provide something similar, I
appreciate... Properly something could be done already by reserving
the hightest priority to a supervision process (i.e. exit after n-
seconds seconds scheduler not running due to ...).
I have encountered the problem as I have tried to implement ~10
threads including a timeout service for these applications. Properly
a timeout server could be imlemented per default also (reply
suggested message to a thread after supplied timeout, cancel,
restart, ...).
I was just playing for a couple of yours, nevertheless I found it
very useful and awaiting an answer now.
It seems that you are personally an experienced designer, do you have
an API to other-vendor RTOS platforms?
Best regards
Josef
As list owner I have already deleted the message in question, along
with a couple of earlier spams. That's why, if you look at the full
message archive, there are a few missing.
If the spams get too bad I can restrict posting privileges to group
members, but I am reluctant to take that step.
Scott McKellar
http://home.swbell.net/mck9/ct/
xcelcior wrote:
>
> I too was offered a "very" similar offer and it ended up as a hoax.
> Unfortunately, I lost $200 for this.
>
You're asking about non-blocking IO, and the question
is not at all trivial.
For many forms of multithreading, there's no problem.
One thread can perform blocking IO, through scanf() or
whatever, and the other threads can keep running while
the first thread waits. That's a major reason for
using threads in the first place.
Cheap Threads isn't like that. If one thread blocks
for any reason, all threads are blocked. If you want
to perform non-blocking IO, you'll have to use some
platform-specific way to do it, because Standard C
doesn't provide this capability.
I do most of my Cheap Threads development on an
ancient Borland compiler. Borland provides a kbhit
function that tells you whether there is a keypress
waiting in the keyboard buffer. By using that
function, I can read the next keypress (potentially a
blocking operation) only when I know there's
a keypress to be read. At one time Microsoft's
compiler provided a similar kbhit function, but I
don't know about their current offerings.
One of my main testbed programs has several input
fields, each run by a separate thread. Another thread
checks the keyboard buffer and, if it detects a
keypress, passes it in a message to whatever input
field currently has focus. It's actually a bit more
complicated than that, but the point is that the user
interface is event-driven, and every keypress is an
event. This approach is rather more tedious than
using scanf(), especially if you want to handle
backspaces, delete keys, tabs, and arrow keys
sensibly, but it does enable background threads to do
work between keypresses.
Depending on what's available on your platform, you
may be able to use a similar approach. I don't know
of any Unix equivalent to kbhit, but maybe someone
else in the group does. Otherwise you're probably
better off using some other form of multithreading
such as POSIX threads, or maybe a separate process for
the background work.
Scott McKellar
http://home.swbell.net/mck9/ct/
xcelcior <blaze01211983@...> wrote:
> GREETINGS
> forgive me but I'm kinda new to multithreaded
programming d=)
> I'm just wondering how to implement a user interface
in a
> multithreaded programming environment or using cheap
thread.
> For example i have 2 threads. Thread A runs the user
interface while
> Thread B does other things. I mean how do i get the
input from the
> user through thread A since the two threads are
switching controls.
> I cant use scanf since it will wait for user input
at the same time
> suspending the execution of the other thread Thread
B.
>How can I run thread B on the background while thread
A gets user
> input?
> Forgive me if my question is a bit trivial =)
GREETINGS
forgive me but I'm kinda new to multithreaded programming d=)
I'm just wondering how to implement a user interface in a
multithreaded programming environment or using cheap thread.
For example i have 2 threads. Thread A runs the user interface while
Thread B does other things. I mean how do i get the input from the
user through thread A since the two threads are switching controls.
I cant use scanf since it will wait for user input at the same time
suspending the execution of the other thread Thread B.
How can I run thread B on the background while thread A gets user
input?
Forgive me if my question is a bit trivial =)
Oops. I forgot to include compilation guards in ct.h to ensure that
the Cheap Threads functions are declared as extern "C" when you
#include that header in a C++ file.
See the attachment for a slightly revised version of ct.h. Or you
can add the compilation guards yourself:
#ifdef __cplusplus
extern "C"
{
#endif
/* function prototypes here... */
#ifdef __cplusplus
}
#endif
With this change to the header, on my system I could compile cttimer
as a C++ program without alteration.
I will post this revision to the website this weekend.
Another possibility is to skip the compilation guards and compile all
the Cheap Threads modules as C++. I haven't tried it, and you might
need to tweak the code here and there if I left out a necessary
#include or something like that, but it ought to work.
I don't recommend that approach, though. For one thing, future
releases of Cheap Threads will include the compilation guards, so
if you upgrade to a new release you would have to remember to disable
them. Furthermore, compiling everything as C++ is likely to degrade
performance somewhat, at least if you compile with exceptions enabled.
The C++ compiler generates exception handling code that incurs
overhead even when no exceptions occur.
On the other hand you might want exceptions to propagate all the way
up through the scheduler into whatever calls ct_schedule(), so that
each thread doesn't have to include a lot of tedious code to keep
exceptions from escaping. If that's what you want, then you would
have to compile Cheap Threads as C++. Presumably you would be willing
to accept the extra overhead that would result.
Maybe I should make the compilation guards themselves subject to
conditional compilation. Then if you want to compile Cheap Threads
as C++, then you could compile it with CT_PLUSPLUS #defined, and the
compilition guards would be disabled, without your having to edit ct.h.
I'm reluctant to add yet another build option without feedback from
users. Does anybody have any preferences?
Thanks for writing. Please let us know how things turn out.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
Antz wrote:
>
> I've been playing around with the Cheap Threads download package on
> FreeBSD using the GNU C compiler (gcc) and so far it seems great.
> However I really need to use classes and some of the nice data structures
> in C++. Thus far trying to compile the cttimer test program using g++ has
> been utterly impossible.
> Is there any way that the cheap threads code can be used by a program
> written in C++? Or am I going to be forced to use POSIX threads and have
> to write completely different versions of this application for *NIX and
> Windows?
>
> Any help would be greatly appreciated.
> Thnx.
>
> -Antz
I've been playing around with the Cheap Threads download package on
FreeBSD using the GNU C compiler (gcc) and so far it seems great.
However I really need to use classes and some of the nice data structures
in C++. Thus far trying to compile the cttimer test program using g++ has
been utterly impossible.
Is there any way that the cheap threads code can be used by a program
written in C++? Or am I going to be forced to use POSIX threads and have
to write completely different versions of this application for *NIX and
Windows?
Any help would be greatly appreciated.
Thnx.
-Antz
I have posted a sample program on the website, named demo1. It is the
same sample program that I posted to this group a few weeks ago demo1.
It is not linked directly, but it is included in the download package.
It would be nice to have examples of message-passing code,
using the three different ways of passing messages: to a single
thread, to a class of subscribed threads, and to all threads.
I think that's what you're saying.
Maybe some day I will provide such examples on the website. The
test programs that I use for development aren't really good to use
as examples because they're not stable. I keep changing them to
test various kinds of things.
However before I worry about having more examples I want to post
the one I have (see the attachment from my last note). That means
I have to write some more HTML, rebuild the zip archive, and so
forth. None of that is hard but it takes time.
If any of you has any code using Cheap Threads that you have posted
on your website, or elsewhere, I'd love to link to it.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
gordonwkf wrote:
>
> May be lessions of 1(thread) to 1(thread), 1 to many, manay to manay?
> Anyway, when I get time to read over your source code, I will
> provide some example for it, I may try to port your CheatThread to
> Gameboy Advance, since I am developing a Simple OS for GBA to drive
> my GUI interface.
>
> --- In cheapthreads@yahoogroups.com, Scott McKellar <mck9@s...>
> wrote:
> > See response below...
> >
> > gordonwkf wrote:
> > >
> > > Dear Sir
> > > Can you write more doc for funciton prototypes' parameters?
> Which
> > > make it more easy to use? Are there any more examples?
> > >
> > > Gordon From Hong Kong
> > > thx
> >
> > I tried to provide detailed documentation, but there's always
> > room for improvement.
> >
> > Which parameters are you having problems with?
> >
> > As for examples...
> >
> > One weakness of the website, as it stands now, is that it has only
> > one example -- the cttimer program, which may be too simple to be
> > very helpful.
> >
> > I'm not sure how to provide good examples. In order to demonstrate
> > anything beyond the simplest concepts, a program may have to be
> > complicated enough that it's hard to follow.
<snip>
> > Another problem is that it's hard to show that multiple threads are
> > running without some kind of graphical display.
<snip>
May be lessions of 1(thread) to 1(thread), 1 to many, manay to manay?
Anyway, when I get time to read over your source code, I will
provide some example for it, I may try to port your CheatThread to
Gameboy Advance, since I am developing a Simple OS for GBA to drive
my GUI interface.
--- In cheapthreads@yahoogroups.com, Scott McKellar <mck9@s...>
wrote:
> See response below...
>
> gordonwkf wrote:
> >
> > Dear Sir
> > Can you write more doc for funciton prototypes' parameters?
Which
> > make it more easy to use? Are there any more examples?
> >
> > Gordon From Hong Kong
> > thx
>
> I tried to provide detailed documentation, but there's always
> room for improvement.
>
> Which parameters are you having problems with?
>
> As for examples...
>
> One weakness of the website, as it stands now, is that it has only
> one example -- the cttimer program, which may be too simple to be
> very helpful.
>
> I'm not sure how to provide good examples. In order to demonstrate
> anything beyond the simplest concepts, a program may have to be
> complicated enough that it's hard to follow. Just to have one
> thread send a message to another, I need to create the threads
> and call ct_schedule(). Then one of the threads has to send a
> message, and the other has to receive it and somehow show that it
> has received it. Then they have to both terminate or go to sleep,
> or one of them has to call ct_halt(). I don't know how many people
> would want to wade through several hundred lines of code just to
> see an example of one simple thing.
>
> Another problem is that it's hard to show that multiple threads are
> running without some kind of graphical display. The main program
> that I use for testing puts some blinking lights on the screen,
one
> thread per light, plus a couple of other threads to read the
> keyboard and control the timing of the blinks. However this
program
> depends on some compiler-specific function calls for controlling
the
> display. I don't want to use it for an example because it's not
> portable. About all I can do portably is to have different
threads
> write different lines of text. That's not very exciting, but I'm
> not sure how to do better.
>
> The attachment contains an example slightly more complex than the
> cttimer program. Two threads take turns writing to standard
output.
> Each thread runs for a different number of iterations. The main
thing
> that this program demonstrates is that two threads can run the
same
> code but behave differently, because they store different values
in
> their thread-private data.
>
> In order to get the attachment you may need to be a member of the
> mailing list (I don't know exactly how Yahoo handles attachments).
> One of these days I'm planning to put this example up on the
website.
> Until then, if you're not a member you can ask me for a copy by
> private email.
>
> Scott McKellar mck9@s...
> http://home.swbell.net/mck9/ct/
See response below...
gordonwkf wrote:
>
> Dear Sir
> Can you write more doc for funciton prototypes' parameters? Which
> make it more easy to use? Are there any more examples?
>
> Gordon From Hong Kong
> thx
I tried to provide detailed documentation, but there's always
room for improvement.
Which parameters are you having problems with?
As for examples...
One weakness of the website, as it stands now, is that it has only
one example -- the cttimer program, which may be too simple to be
very helpful.
I'm not sure how to provide good examples. In order to demonstrate
anything beyond the simplest concepts, a program may have to be
complicated enough that it's hard to follow. Just to have one
thread send a message to another, I need to create the threads
and call ct_schedule(). Then one of the threads has to send a
message, and the other has to receive it and somehow show that it
has received it. Then they have to both terminate or go to sleep,
or one of them has to call ct_halt(). I don't know how many people
would want to wade through several hundred lines of code just to
see an example of one simple thing.
Another problem is that it's hard to show that multiple threads are
running without some kind of graphical display. The main program
that I use for testing puts some blinking lights on the screen, one
thread per light, plus a couple of other threads to read the
keyboard and control the timing of the blinks. However this program
depends on some compiler-specific function calls for controlling the
display. I don't want to use it for an example because it's not
portable. About all I can do portably is to have different threads
write different lines of text. That's not very exciting, but I'm
not sure how to do better.
The attachment contains an example slightly more complex than the
cttimer program. Two threads take turns writing to standard output.
Each thread runs for a different number of iterations. The main thing
that this program demonstrates is that two threads can run the same
code but behave differently, because they store different values in
their thread-private data.
In order to get the attachment you may need to be a member of the
mailing list (I don't know exactly how Yahoo handles attachments).
One of these days I'm planning to put this example up on the website.
Until then, if you're not a member you can ask me for a copy by
private email.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
Dear Sir
Can you write more doc for funciton prototypes' parameters? Which
make it more easy to use? Are there any more examples?
Gordon From Hong Kong
thx
The previous release of Cheap Threads (v2.5) introduced a
reference-counting scheme to
reduce the churning of memory associated with the delivery of messages.
Unfortunately that change introduced a memory leak in some circumstances
-- namely,
when the application sends an enqueue rather than a message with any
content. An
enqueue tells the scheduler to enqueue a thread for execution but does
not pass
it any message content, not even zero-length content.
The new scheme makes each thread responsible for deleting the event
associated with
the message, and uses reference counting to avoid deleting the same
event more than
once. The problem was that an enqueue is treated differently. A thread
has no access
to the associated event and cannot delete it. Oops.
The solution is to let the scheduler delete any event associated with an
enqueue.
This fix is confined to a single function, namely
dispatch_event_queue(). Identical
copies of this function appear in the two versions of the scheduler
module: ctsched.c
(for standard Cheap Threads) and ectsched.c (for embedded Cheap
Threads). The new
version of this function is below. (Yahoo's web interface to this
mailing list
suppresses indentation, or (if you look at the HTML source) uglifies it
with HTML tags.
The email version should look okay.)
/****************************************************************
Dispatch all the pending events.
***************************************************************/
static void dispatch_event_queue( void )
{
Ct_event * pE;
while( ev_head != NULL )
{
/* Detach event from queue */
pE = ev_head;
ASSERT( EVENT_MAGIC == pE->magic );
ev_head = ev_head->pNext;
pE->pNext = NULL;
/* Dispatch event according to type */
switch( pE->dispatch_type )
{
case CT_DISPATCH_ADDRESSEE :
dispatch_addressee( pE );
break;
case CT_DISPATCH_SUBSCRIBER :
ct_dispatch_subscription( pE );
break;
case CT_DISPATCH_ALL :
dispatch_all( pE );
break;
default :
ct_report_error( "dispatch_queue: Illegal event type" );
ct_fatal_error();
break;
}
if( CT_EV_ENQ == pE->ev_type )
{
/* For an enqueue we don't attach the event to any */
/* threads, so we can't rely on the threads to */
/* destruct it. Destruct it now. */
ct_destruct_event( &pE );
}
}
ev_tail = NULL;
/* If the current thread sent an event to itself, we */
/* didn't enqueue it yet. Now that we have enqueued */
/* all other recipients, enqueue the current thread. */
if( self_msg )
{
int saved_priority;
ASSERT( pCurr_thread != NULL );
ASSERT( CT_MAGIC == pCurr_thread->magic );
/* Detach the thread from whatever queue it's on */
pCurr_thread->pPrev->pNext = pCurr_thread->pNext;
pCurr_thread->pNext->pPrev = pCurr_thread->pPrev;
/* Enqueue it at the highest priority */
saved_priority = pCurr_thread->priority;
pCurr_thread->priority = 0;
insert_thread( pCurr_thread );
pCurr_thread->priority = saved_priority;
self_msg = 0;
}
}
The change is in the second part of the while loop, where for enqueues
we call
ct_destruct_event().
I have not yet posted this fix on the website, but I hope to do so later
today.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
Comments below...
xcelcior wrote:
>
> greetings
> Im using cheap thread in my project and i cant quite make as desired.
>
> problem description:
> one of my modules is a transparent bridge system. (a PC with 2 NICs)
> basically, this system just throws all packets sniffed from NIC A to
> NIC B and also the other way around.
>
> so in my program i've created 2 threads and called the ct_sched()
>
> The 1st thread sniffs packets from NIC A then throws it to NIC B for
> retransmission.
>
> The 2nd thread does the same thing but the other way around NIC B to
> NIC A.
>
> All went fine until I tested it and what happended is that when a
> packet is received from NIC A thread 1 callback function is executed
> but thread 2 is also executed which should not happen since no
> packet is detected on NICB. i think it got something to do with the
> shared memory space (void * pdata) but i dont know how to use it.
>
> WELL I HOPE SOMEONE COULD HELP ME THNX
I'm not sure what you're complaining of. You say that thread 2
runs. It's supposed to. That's what the scheduler does for you --
it runs the threads repeatedly. Assuming that the two threads are
at the same priority, and that no other threads are involved, the two
threads will take turns.
(Actually you're likely to have at least one other thread running so
that it can terminate the first two. Otherwise you have an endless
loop until both threads encounter an error and call ct_exit().)
You're not referencing pData within thread_NIC1(), so I don't think your
problem has anything to do with pData.
I assume that pcap_next_ex() reads a packet from the NIC and loads its
contents into pkt_data[]. I further assume that pcap_sendpacket()
writes the contents of pkt_data[] to the specified NIC.
> source code:
> int thread_NIC1( void * pData )
> {
> //pcap_next_ex() will only return if a packet
> //is detected on a NIC
I *think* you mean that it will return a positive number only when it
detects a packet. Your logic suggests that pcap_next_ex() returns zero
if no packet is detected, and -1 if an error occurs. Any other
negative values probably should never happen, but if they do, you treat
them the same as a zero.
> //thread 2 has a callback function called thread_NIC2()and
> //identical to thread_NIC1() the only difference
> //is if((res = pcap_next_ex(g_opennic2handle, &header, &pkt_data))
> //>= 0)
If that is truly the only difference then you have a problem, because
both threads will write to the same NIC. There should also be
differences in the call to pcap_sendpacket() and in one of the
calls to printf().
> if((res = pcap_next_ex(g_opennic1handle, &header, &pkt_data)) >= 0)
I'm not familiar with the API you're using, but did you mean to
pass &pkt_data rather than pkt_data? If you pass a pointer to a
pointer where you should pass a pointer to an array, then the results
are unpredictable. If you have a prototype for pcap_next_ex() in
scope then the compiler should detect such an error -- unless the
third parameter is declared as a void *, which is assignment-compatible
with any kind of pointer.
However I suspect that pkt_data is not an array, but rather a
pointer that pcap_next_ex() overwrites so that it points directly
into the packet data. That would eliminate a layer of copying. If so,
then you're passing the right thing. It's hard for me to tell because
you didn't include the declarations of your variables.
> {
> if(res == 0)
> return CT_OKAY;
>
> for(i=0;i<12;i++)
> {
> if(pkt_data[i]!=5)
> return CT_OKAY;
>
> }
I don't know what the above loop is all about, but I'm going to
assume that it makes sense, and ignore it.
<snipped: code for logging the packet to stdout>
> pcap_sendpacket(g_opennic2handle,pkt_data,
> (int)header->caplen);
>
> return CT_OKAY;
> }
> else if(res == -1)
> {
> printf("Error reading the packets: %s\n", pcap_geterr
> (g_opennic1handle));
> return ct_exit();
> }
> else
> return CT_OKAY;
> }
In short I don't really understand what your problem is, nor can
I explain it, nor fix it. However I will suggest a use for the
pData parameter.
Declare a type like the following:
typedef struct
{
NIC_handle from_handle; /* or whatever the appropriate */
NIC_handle to_handle; /* type is... */
} NIC_route;
Before creating the threads, populate two NIC_routes with the
NIC_handles, but in the opposite order. When you create the threads,
initialize them with pointers to their respective NIC_routes.
This way you can have a single callback function that works for
both threads:
int thread_NIC{ void * pData )
{
const NIC_route * pRoute = ( NIC_route * ) pData;
ASSERT( NIC_route != NULL );
if((res = pcap_next_ex(pRoute->from_handle, &header, &pkt_data))
>= 0)
{
/* ... */
pcap_sendpacket(pRoute->to_handle, pkt_data,
(int)header->caplen);
/* ... */
}
/* else etc... */
}
This approach avoids the duplication of code, and guarantees that
each thread will behave identically, except for the direction in
which they shovel the packets. If you want to add a bridge between
two other NICS you can just add another pair of threads, instead of
another pair of functions.
I hope the above will at least give you some ideas, even if it
doesn't fix your problem.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
greetings
Im using cheap thread in my project and i cant quite make as desired.
problem description:
one of my modules is a transparent bridge system. (a PC with 2 NICs)
basically, this system just throws all packets sniffed from NIC A to
NIC B and also the other way around.
so in my program i've created 2 threads and called the ct_sched()
The 1st thread sniffs packets from NIC A then throws it to NIC B for
retransmission.
The 2nd thread does the same thing but the other way around NIC B to
NIC A.
All went fine until I tested it and what happended is that when a
packet is received from NIC A thread 1 callback function is executed
but thread 2 is also executed which should not happen since no
packet is detected on NICB. i think it got something to do with the
shared memory space (void * pdata) but i dont know how to use it.
WELL I HOPE SOMEONE COULD HELP ME THNX
source code:
int thread_NIC1( void * pData )
{
//pcap_next_ex() will only return if a packet
//is detected on a NIC
//thread 2 has a callback function called thread_NIC2()and
//identical to thread_NIC1() the only difference
//is if((res = pcap_next_ex(g_opennic2handle, &header, &pkt_data))
//>= 0)
if((res = pcap_next_ex(g_opennic1handle, &header, &pkt_data)) >= 0)
{
if(res == 0)
return CT_OKAY;
for(i=0;i<12;i++)
{
if(pkt_data[i]!=5)
return CT_OKAY;
}
//if(getpacket)
//{
/* convert the timestamp to readable format*/
ltime=localtime(&header->ts.tv_sec);
strftime( timestr, sizeof timestr, "%H:M:%",
ltime);
printf("\nWinPcap pkt_header content: \n");
printf("\n%s,%.6d len:%d\n", timestr, header-
>ts.tv_usec, header->len);
printf("\npkt_data content: \n");
for(i=0;i<((int)(header->caplen+1));i++)
{
printf("%x",pkt_data[i]);
if(((i+1)%LINE_LEN)==0)
printf("\n");
}
printf("\n\n");
printf("\nForwarding packet to NIC2
interface\n");
pcap_sendpacket(g_opennic2handle,pkt_data,
(int)header->caplen);
//}
//getpacket = TRUE;
return CT_OKAY;
}
else if(res == -1)
{
printf("Error reading the packets: %s\n", pcap_geterr
(g_opennic1handle));
return ct_exit();
}
else
return CT_OKAY;
}
I just came home from vacation to find the first three members
of the cheapthreads group, other than myself. Perhaps it's
time to introduce ourselves.
I wrote the Cheap Threads library for a hobbyist project, just
for fun.
It started when I downloaded a version of Zork for my daughter
to play. Zork is an old, text-based game, similar to the
classic Adventure game. She loved it. She also loved to
write, and I thought she might like to be able to create her
own Adventure-style games.
However, she doesn't know how to program, and doesn't care
to learn. I would have to create a mini-language for defining
the dungeon, the objects to collect, and so forth.
That part seemed fairly straightforward to do, and I set to work.
However another idea occurred to me. While the player wandered
around in the dungeon, I wanted other things to be happening
in the background, out of sight. The pirate would wander from
room to room. The dragon would wake up, and start to get
hungry. The water would slowly drain from the lake.
In order to make that kind of thing possible, but definable at
run time by a text file, I needed some form of multithreading.
Since I was writing for MS-DOS (I haven't the courage to write
for Windows), and I didn't want to spend money on a commercial
multithreading package, I would have to provide the
multithreading myself.
Without quite knowing what I was doing, I started to add
multithreading. However, the multithreading code became
all tangled up with logic that was highly specific to the
game project. Things were getting messy.
Finally I realized that multithreading had nothing to do
with Adventure-style games. It is a far more general
abstraction. I needed a separate layer of generic
multithreading code, cleanly separated from the game logic.
Thus was Cheap Threads born.
My daughter lost interest in Zork, and I lost interest in
the game project, but the multithreading code remained.
Cheap Threads is nothing like the kind of programs I write
on my job, and so far I have had no real use for it, but I
thought that someone else might find it useful -- so I
posted it on my website.
If you've joined this group, you presumably have some
interest in Cheap Threads, and I'm curious to know, for
example:
1. Are you using Cheap Threads (or planning to)?
2. What sort of application are you using Cheap Threads for
(or considering it for)?
3. Are you more interested in the standard version or
the embedded version?
4. Have you found it necessary or useful to extend Cheap
Threads, or modify it, for your purposes? If so, how?
5. Have you encountered any bugs, or annoying limitations?
6. What features of Cheap Threads make it particularly
attractive (or unattractive) to you?
7. Are there any new features or extensions that you'd
like to see added?
This is not a questionnaire, just a request for feedback.
If Cheap Threads were a commercial product, you could say
I'm doing some market research. Or you could say I'm
trying to get the discussion started. I hope to hear
from you soon.
Scott McKellar mck9@...http://home.swbell.net/mck9/ct/
Welcome to the cheapthreads group.
This group is a forum for discussion of Cheap Threads, a portable
C library for cooperative multitasking. The approach taken by
Cheap Threads has three main advantages:
1. Completely portable -- needs nothing beyond Standard C
(specifically C89; I don't have a C99 compiler with which to test it).
2. Low memory requirements, because it doesn't maintain a separate
stack for each thread.
3. No need for mutexes, locks, critical sections, or other gimmicks
to keep threads from interfering with each other.
The main disadvantage, if it is one, is that each thread must yield
control from time to time with an explicit return statement. This
requirement may require a somewhat non-intuitive style of programming,
more akin to finite state machines than to conventional procedural
code.
Cheap Threads is free software -- free as in speech and free as in
beer -- licensed under the GNU Lesser General Public License (LGPL).
For more information about Cheap Threads, see:
http://home.swbell.net/mck9/ct/
This mailing list is currently unmoderated. If it attracts abuse
in the form of spam, flame wars, job postings, or excessive
off-topic posts, I will reluctantly reconfigure it as a moderated
group. Besides being more work for me, moderation will slow
everything down, so I'm hoping that this step will not be necessary.
Scott McKellar
http://home.swbell.net/mck9/ct/