neilbradley wrote on Thursday, May 01, 2008:
> What type of function call are you making both from task level and from an ISR?
I’ve got a perfect example for that - I have a windowing system that I’ve written that has two sources of stimulus. One is foreground code, that expires a timer or an asynchornous programmed event that causes a window region to be updated (message queue based). The other is an interrupt based event for pointer/stylus events that causes window regions to be updated as well (also the same message queue). So I’m depositing messages into the same queue from two different contexts, and there’s a single WindowDepositMessage() API that I call that allocates a message, fills in appropriate detail, and deposits the message. Yeah, I know I could create two different call points, but this is something the OS could do for me quite easily so I (and others doing so) wouldn’t have to.
> My preference is to ‘defer’ interrupt processing to the task level.
Sure (this is how I’m using it), and this doesn’t negate that.
> On the negative side, maybe I have missed some tricks, but note the comment just made about other people making claims over the FreeRTOS.org code.
I don’t know about the other claims that you mention (I didn’t see the post), but the most appropriate phrase I can think of is “know thy enemy”. I think it all depends upon what you want FreeRTOS to end up being. After being used to several other RTOSes (ThreadX/uCOS-II being the most prominent in my experience), there were simply several aspects of FreeRTOS (missing features) that I needed, so I didn’t use FreeRTOS (I bought uCOS-II licenses instead for the last two projects). If you’re interested in making FreeRTOS ubiquitous and attractive to other users of RTOSes, I strongly recommend looking at least at their APIs, because anyone approaching FreeRTOS as an option are likely going to be coming from the perspective of “How do I do x like I do on RTOS y?”.
I’m one of the last individuals to recommend “do it like someone else”, but in a few cases here, doing it like other OSes is exactly the right thing to do. APIs and approaches that ThreadX/uCOS-II use have been battle hardened 15-20 years now, and there’s a LOT to be learned from their examples.
>For example, queues can be used from interrupts of higher priority than the tick. At some point this will get migrated into the FreeRTOS.org code too. That might be an opportunity to add in your suggestion, but I would see this as being done on a port by port basis on a ‘who shouts loudest’ basis.
Well, here’s an example of expectations and implementation that differ. Based on my experience, I expected FreeRTOS to already handle nested interrupts and know when it’s in an interrupt context. Based on that, the xxxFromISR procedures just seemed odd. It seemed like a relatively simple, attainable goal that is of direct benefit to the consumer (which is why I brought it up).
>This is an example of what I mentioned at the top of this post. I see counting semaphores to be of little value to small embedded systems, but people asked for them (over and over again) so I added them in.
Case in point. I don’t think people would repeatedly ask for them if there weren’t a need, and as I mentioned above, they are an expected feature in other RTOSes. I’ve used semaphores for more than just binary purposes, specifically in one case where I had a dual CPU situation. The slave CPU would interrupt the master to “come get” the info from it, but it was low priority, and we had realtime requirements that made servicing the slave CPU unacceptable at interrupt time. We wanted to use FreeRTOS to do it, but at the time didn’t have counting semaphores, so we bought uCOS-II (for a few other reasons as well as this was not our only criteria) and used its counting semaphores to wake a high priority task up when it needed to be serviced.
>The recursive semaphore feature was for one particular customer who needed it to facilitate their implementation of some communications stacks. It’s a bit of an oddity (although posix I think has them).
They’re probably using it as a mutex. I can’t recall (but I don’t think) that mutexes existed at the last point where I worked with FreeRTOS, so I can understand the need.
>2) I have a whole library of ports and suggestions that people have sent me. I would like to create an ‘unofficial’ archive of such things that people can download. This is a little tricky with respect to maintainability, as people will often send something, then two days later they will send it again with a fix, etc. Also as previously mentioned I have to be VERY careful with publishing things for which the origin is unknown by me.
Totally understood, and agreed. In the case of timers, this gets back to what I’d consider to be an expected feature. And the module I submitted to you I mentioned I was writing from scratch in FreeRTOS’s style and that you were free to use it as is for whatever purposes you want. I needed the functionality, and I’ve seen others ask for it on the message boards as well. I’m still just surprised that there isn’t an OS-based timer function that’s available to the user.
>3) I think we have discussed a couple of times the issues regarding event flags, and to a lesser extent timers, readers can search through the forum for this so I won’t repeat it here…but basically I am unhappy with including code that searches lists in an undeterministic way from within an interrupt.
The code I had submitted wasn’t nondeterministic (or maybe we’re using the word slightly differently). It would only decrement timers based on if they were running (if they weren’t, there was no penalty), and only timers that were running would get searched.
But I really do need to ask the question, since I’ve seen it before, is the concern over microoptimizations like searching lists really all that big of a deal? Let’s assume for a second that we have a paltry 10Mhz ARM, with a timer tick that fires once every millisecond. That timer tick is going to fire no matter if a user timer is running (because of the scheduler). Let’s also assume that each instruction takes 100ns to execute, and that to “skip” a node, it would require 4 instructions, or 400ns (this isn’t unrealistic). Let’s say there are 10 timers that aren’t running, but allocated. So, that means it takes 4usec per timer tick, or .4% of the CPU. So even with exaggerated/unrealistic examples, it’s still less than .4% of the overall CPU execution time, and in practice it only goes down from there. Why is this such a large concern, considering that all other operations will absolutely dwarf it?
While I certainly understand and respect the concept of optimization, I don’t think that avoiding such a feature to gain another .4% (or less) of the CPU in terms of performance is worth the extra work other consumers of FreeRTOS would have to go through to work around a lack of timers.
> I have not come up with an event flag implementation yet that gets around this.
Maybe you and I have differnt ideas in mind. Only one thread can block on an event flag, and the only time that there’s any check at all is when something posts to the event flag mask.
> Timers are less of a problem, and my preferred implementation is to use a switch statement to switch on an incrementing value. My implementation is faster, your implementation is much more user friendly.
I’d argue that it’s “faster by insigificant amounts”. I cannot imagine that a timer handler would be of any appreciable CPU time in practice. Context switches and other operations’ execution are orders of magnitude longer.
> I could write one page showing my (very basic) implementation, and then you could have a page (with due credits given) showing your more generic and user friendly approach - with a link to the source code. I would be happy to do this, provided we also included a paragraph on the pros and cons of each approach.
I guess we could, but I just have a hard time believing that the "user friendly" way is of a detriment to anyone in practice.
>One of my next targets is to improve the time it takes to select the next task. This is currently fast and deterministic when moving from a low priority task to a high priority task (the critical case), but could be improved when moving from a high to low priority task.
Before I share my experiences with my own RTOS implementations, in practice is this really a significant time sink?
Anyway, not sure how this is going to come across conceptually, but here’s what I did:
* Kept an array of pointers to the head and tail of all TCBs of a given priority - one index per priority (32 at the time I think)
* Kept an array of pointers to the heads/tails of all TCBs of a given priority in the “ready to run” linked list
* Two prior/next pointers were kept in each TCB - one when it was in the “ready to run” linked list, and one that was linked to its TCB priority prior/next list
* Kept a head pointer to a “ready to run” linked list of TCBs. That way any task waking up was an instant pointer dereference.
* When a task was finished and was put back to sleep, it got removed from the head of the “ready to run” list and put back at the tail of that task’s priority, and removed from the “ready to run” list
I’m probably not doing a very good job of describing this, but I found that the implementation was worse than a linear search of the “ready to run list” approach for anything less than 12 tasks.
Anyway, not sure if it’s helpful, but hopefully it’ll get the creative juices flowing.