LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 02-14-2014, 08:25 AM   #196
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513

Either way works. The nice part of the thread is that it serves as a common history log.
 
Old 02-15-2014, 09:54 PM   #197
schmitta
Member
 
Registered: May 2011
Location: Blacksburg VA
Distribution: UBUNTU, LXLE
Posts: 352

Original Poster
Rep: Reputation: Disabled
Have you heard of valgrind? it works with binaries and can find problems with bad pointers etc. I think in linux you type valgrind and then your binary name. Since it works with binaries you can write your application in any language. you can even run interpreters under it. Applications as large as 25 million lines of code have been run under it. See: http://valgrind.org/info/ http://www.valgrind.org/docs/manual/QuickStart.html

Last edited by schmitta; 02-15-2014 at 11:43 PM.
 
Old 02-16-2014, 06:46 AM   #198
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
I know of it, but haven't really needed it (not doing that much with threaded applications, where it really would help). As long as the debugging phase is fast enough (it runs 1/4 the full speed) it can really help. It only runs on x86/PPC (though how well on the PPC I don't know - it isn't used as much).
 
Old 02-21-2014, 04:28 AM   #199
schmitta
Member
 
Registered: May 2011
Location: Blacksburg VA
Distribution: UBUNTU, LXLE
Posts: 352

Original Poster
Rep: Reputation: Disabled
Could an RTOS be used with your stack machine? Maybe multiple copies of your interpreter? If you handle interrupts a form of multitasking could be had by using the interrupts to set/reset flags and have the main body execute code based on those flags - a superloop. As long as state was preserved for each operation it would be sort of multitasking.
 
Old 02-21-2014, 06:58 AM   #200
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
Sure. That is how emulation works - In one case, the local data for the svm (those in the svm function - the pc, stack pointer, registers, and stack storage) are a structure, and there is an array of that structure (one entry for each "CPU"). At the end of the current SVM loop all it does is increment an index (modulo number of active "CPUS"). That way the emulation is to switch CPUs at the end of each instruction. This is also where interrupt handling would be put (both device, and inter-CPU).

This would allow sharing the memory, and the program segment (though multiple stacks would be needed - one per emulated CPU).

It is also possible to have multiple memory/program segments too - this would be closer to emulating multiple separate systems - and the inter-CPU communication would have to be treated more like an I/O operation as there would be no "shared memory".

A side effect is that unless the host has multiple CPUs, the throughput for each SVM emulation will be reduced (divided by the number of active CPUs).

Now if the host is actually a multi-core, then just have each thread invoke the svm function, that would have all code/data/stack segments for each thread. I don't think you would want to share memory in that case, because of the problems getting synchronized data segment access (you could share the code segment, as that isn't modified during the svm operation, shared stack wouldn't work at all).

Last edited by jpollard; 02-21-2014 at 07:00 AM.
 
Old 02-23-2014, 03:41 PM   #201
schmitta
Member
 
Registered: May 2011
Location: Blacksburg VA
Distribution: UBUNTU, LXLE
Posts: 352

Original Poster
Rep: Reputation: Disabled
Still debugging. Came across a data structure I did not particularly like whose base was an array all written at the beginning of the project when I was not as aware as I am now about what I am doing so I changed it. It was actually two data structures dealing with the symbol table and arrays which I collapsed into a single data structure that I now allocate with a calloc. Had always used arrays (I guess going back to my FORTRAN days) and had not used calloc which it looks like it will save me a lot of data area instead of allocating one huge block of array storage. So I am now refractoring large amounts of code which feels like a cleansing and is somewhat refreshing.

How are you coming? Sounded like you are making great progress! Spring will be here soon!
 
Old 02-23-2014, 04:53 PM   #202
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
I have managed to get some of the documentation going, and have an outline for how the parsing is done along with the translations...

Hopefully it will make sense.

One thing it did bring to mind was the similarity with some early studies I had done. I found an IBM publication while an undergrad that used a parser generator (at the time, only precedence grammars were fully understood), and the book (wish I had it) started with a very simple language - not much more than variable declarations and assignments - calling it PL0. Then each chapter or two of the book would add more, the second unit was PL1 and had control structures. The third had subroutines with local variables (PL3) added. By the end of the book (PL12 as I recall, but could be wrong) it was a very usable PL/1 subset compiler, and was capable of compiling itself, as most of the structures used had been implemented.

The compiler generator, as I recall, was written in PL/1 though, as it needed dynamic memory for the language analysis, though once the tables were written there was no problem with compiling.
 
Old 02-23-2014, 11:19 PM   #203
schmitta
Member
 
Registered: May 2011
Location: Blacksburg VA
Distribution: UBUNTU, LXLE
Posts: 352

Original Poster
Rep: Reputation: Disabled
I wrote a lot of code in PL/1 but all that is now gone the way of the dodo but I still have a lot of it on 9 track tape.
 
Old 02-24-2014, 04:46 AM   #204
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
Well, the language is still around... Even has a compiler available for Linux:http://www.iron-spring.com/
 
Old 03-17-2014, 04:56 PM   #205
schmitta
Member
 
Registered: May 2011
Location: Blacksburg VA
Distribution: UBUNTU, LXLE
Posts: 352

Original Poster
Rep: Reputation: Disabled
I need to write a simple cooperative RTOS. Just two system functions: yield(); back to the kernal and wait_on_timer(int count); the kernal would set a counter to count and decrement it after each timer interrupt holding the calling task in BLOCKED state until the allocated timer reached zero at which time the task would be released from BLOCKED to READY. Know of any books/info on the subject? For the PIC12F1840. Thanks. Alvin....
 
Old 03-17-2014, 09:12 PM   #206
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
For something that simple you don't even need a kernel...

A small library would be sufficient - the program would be

1. set isr (to handle future interrupts)
2. set counter (and enable interrupt)
3. wait
4. process stuff (needs to complete before the next interrupt)
5. go back to 3, (assuming the ISR resets the count itself before returning).

The wait only does that - when interrupted I think the wait instruction is completed and goes to the next instruction when the interrupt service returns.

The only time you need more is if there are two cooperating tasks - in which case you might have a producer/consumer tasks - but usually these are not timer based but device interrupt based. At which time the "process stuff" gets to select which task to call... (at which time you get a task status check to see if it is ready to "process stuff", if not, go to the next one... If neither is ready, then go back to the wait. Alternatively, the processing is done in the interrupt service function... and only needs to check to see if data is available for the device... If not, then the interrupt is disabled (and dismissed). When the other task provides data, the interrupt is enabled again. And the only status is for the data buffer.

Again, these are simple synchronous processing...

For much more complex issues you might look at http://www.freertos.org/, they have some book references.
 
Old 03-17-2014, 09:57 PM   #207
schmitta
Member
 
Registered: May 2011
Location: Blacksburg VA
Distribution: UBUNTU, LXLE
Posts: 352

Original Poster
Rep: Reputation: Disabled
I will probably have 3 or 4 tasks running. One task will be somewhat complex measuring time for a signal that is high or low for 40 bits of this signal. The time delay of the rtos clock would be 5 us and the first time signal of the bit would be a constant 50 us of a signal low value ( delay(10); ). The second half of the bit would be high for either 25us (indicating a zero) or high 75us (indicating a one (1)). This would go on for 40 bits. The total time to transmit the 40 bits to me would be ~5ms. So yielding back to the kernel would be necessary. The device I am reading from is a DTH22 temperature/humidity sensor. The RTOS SALVO is simple enough for this but the lite version costs $750. So I thought I would try to make a simple RTOS that provided 1) separately executable tasks and 2) a delay mechanism with an atomic timer.

Last edited by schmitta; 03-18-2014 at 05:09 AM.
 
Old 03-21-2014, 06:42 AM   #208
schmitta
Member
 
Registered: May 2011
Location: Blacksburg VA
Distribution: UBUNTU, LXLE
Posts: 352

Original Poster
Rep: Reputation: Disabled
Sent a reply to RTOS question above. WW2 spy transceiver at: https://www.youtube.com/watch?v=B73SwHqCbU4
 
Old 03-21-2014, 08:51 AM   #209
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
Fun video. Never mind that the tuning cycle broadcasts and allows triangulation to locate it...

There is also microLinux (for systems without an MMU). I've never used it (or the others either). I also don't know how well the project is being maintained either.

http://www.uclinux.org/

Sorry about the long delay in an answer - I had to think about it for a while (it has been a long time since I've actually thought much about real time systems).

The main key for super simple systems is the stack management. I believe by default the initial stack is also the interrupt stack, so each task has to have a stack large enough to accept an interrupt (it has to preserve the registers and current state) plus whatever use it has. The "interrupt stack" now becomes the kernel stack - as every interrupt has to switch to it so that it has enough stack space for its own use. This makes the register save/restore as simple as possible as it just uses the task stack for that purpose. A slightly more complex one has a task structure that has a special register area - and that usually means it also has to copy some of the stack entries (as they are some/all of the registers saved). The assumption is that there is only one stack pointer for the CPU.

Starting the task requires setting the corresponding stack pointer, and calling the main function of the task. A "yield" function has to complete a software emulation of an interrupt (it is also possible there is a special instruction that will do this as well, but sometimes it is faster to emulate it). During system initialization the yield does nothing but cycle through this initial call. Once all tasks have been invoked once (allowing them to perform local initialization only). This can be tested by the yield function as a status bit for the task (initialized/not initialized). If the task has not been initialized it calls the starting function. If the task has been initialized it uses a "return from interrupt" instead.

Once the yield has saved the current context it has two choices - either switch to the kernel stack for the purpose of searching for a "next task", or if the next task is already known it switches stack pointers and returns from interrupt (this goes back to the task that was using the stack). Note: the saved context has the proper stack pointer value - if the operation of selecting the next task uses just a little bit of stack then the task stack must have enough free space to be used - and the switch to the kernel stack is unnecessary. If the amount of free space is unknown/unknowable, then it must switch to the kernel stack).

A simple round robin scheduler has "yield" increment a task index to the next task, do a "ready" test, if ready, then returns from interrupt. It is also useful to have an internal test flag to see if it goes through the entire list without finding anything to do - in which case it can process a "null" task that just waits.

There are several places to be careful -

1) switching stacks almost always has to be done with interrupts disabled - this is to prevent another interrupt from being put on the task stack and possibly overflowing it.

2) searching for a "next task" is sometimes done with interrupts disabled. I say sometimes because if the interrupt service routine checks to see if it is already using the kernel stack then there is no need to switch stacks (this can be done with a software "kernel mode flag" - but setting/clearing this has to be done with interrupts disabled, and is best done as part of the stack switching function.

Depending on the hardware, nested interrupts are not always permitted - thus when an interrupt occurs all other interrupts are disabled until explicitly enabled, or a return from interrupt enables it.

The "search for next task" is where either a round-robin scheduling is done (described above) or if a priority list is desired the search always starts from the highest priority task (the task index is always started at 0, whenever a search is done). The weakness here is that the lowest priority task may be starved for CPU time, where in the round-robin search it will always get a run if it is ready to run. This still doesn't prevent starvation, as any task that uses up "too much" CPU time will still get it. But that is what a clock interrupt is for - to compensate for the starvation.

The yield function itself is only called from a task:

1. it marks the task as "not ready" - after all it called the function because it is finished.

2. searches for a new task - if the task has not been initialized, it switches the stack and calls the init function

3. if the task is ready, then it switches the stack and returns from interrupt (to resume executing the task).

4. if no task is ready, then does a wait. It could just loop around searching, but that sometimes causes longer interrupt latency, and more jitter in the response.

The "yield" as a function may actually be two functions - one that does nothing but invokes the initialization of a task (but then it has to have a different name - the initialization of a task has to use that name instead of "yield" so that the context will be saved right.

The advantage of two functions is that the actual yield function can have whatever kind of scheduling you want (priority, round-robin, round-robin within a priority...) and still have all tasks initialized before enabling interrupts.

The scheduling part of yield can be in a high level language, but the stack switching can't and the return from interrupt can't (not easily anyway, some languages allow you to embed assembly).

On interrupt service: I've mentioned the stack switching... and that it isn't always necessary.

If an interrupt service routine only has to copy a byte from one place to another (usually incrementing a counter/adding to a checksum) then a stack switch isn't always necessary. I've done interrupt service routines that did this, just copying a packet from a serial line, once the count was complete I did have to switch the stack because processing the packet needed registers that weren't available by default.

The minimum stack size is always twice the amount needed for a single interrupt + registers (this is because a software/emulated interrupt just might be occurring at the time a hardware interrupt occurs). Thus when the hardware interrupt is finished and the task resumed, it will resume processing the software interrupt. If possible I would suggest at least 2K for a stack (which should a good bit more than two interrupt stack frames) with 4k or more depending on the task requirements. As a side note, the linux kernel has been moving to a 4k stack size for internal processing - it used to be 8k, with some driver tasks taking nearly 2/3 of that... overflows cause a crash.
 
Old 03-21-2014, 08:37 PM   #210
schmitta
Member
 
Registered: May 2011
Location: Blacksburg VA
Distribution: UBUNTU, LXLE
Posts: 352

Original Poster
Rep: Reputation: Disabled
The PIC12F1840 has only 3.5k words of flash and 256 bytes of ram. With the PIC 10,12 and 16 it has a hardware 16 level stack (8 for most with the above PIC 16). Believe it or not you cannot get to the hardware stack without executing a return or return from interrupt! Salvo ( http://www.pumpkininc.com/ ) does run an rtos from pic12,10,16 but I think that instead of calling a yield() routine they branch directly to it first saving registers then save the address to return to in ram. Its a harvard architecture with program in flash and data in ram. I would like to know how they do it but it would cost about $900 to find out (at that price they give you the source). The hardware stack only contains the return address; no other registers. They do not save the registers in the task control block - it is somehow local to the routine.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Regular Expressions nova49 Linux - Newbie 4 07-13-2011 07:05 AM
Regular Expressions Wim Sturkenboom Programming 10 11-19-2009 01:21 AM
regular expressions. stomach Linux - Software 1 02-10-2006 06:41 AM
Regular Expressions overbored Linux - Software 3 06-24-2004 02:34 PM
help with REGULAR EXPRESSIONS ner Linux - General 23 10-31-2003 11:09 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 09:23 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration