Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TODOs and ideas #12

Open
75 tasks
diggit opened this issue Apr 13, 2020 · 11 comments
Open
75 tasks

TODOs and ideas #12

diggit opened this issue Apr 13, 2020 · 11 comments

Comments

@diggit
Copy link
Contributor

diggit commented Apr 13, 2020

Hi, I've tried to split todos and ideas into groups. Maybe the are in wrong one. I guess, you should be able to edit this post. Most of points come from doc/argon_todo.txt

Ideas

Timing

  • Handle changing system clock by updating SysTick. Need to add API?
  • High resolution timers. Tickless idle could be used to support timers with resolutions higher than a tick.
  • Deal with wrapping of tick counter.
  • Move to a solely tickless architecture.
  • Replace tick counter with 64-bit microsecond time.

Features

  • Add link from thread to object it's blocked on. (?)
  • Unprivileged support?
    • Run kernel in privileged mode and use SVCall for most kernel APIs?
  • Event flags?
  • Handle a thread changing its own priority when it owns a mutex and has been hoisted in priority.
  • Run main() in a thread.
  • Replace main thread support with API to turn main() into a thread and start scheduler.
  • Track time spent in scheduler. (requires microsecond <= timer resolution)
  • Abstracted MPU support.
    • Protect thread stacks with MPU.
  • Only defer irq operations if the kernel is locked, otherwise execute immediately.
  • Main thread needs to be able to stop by returning from main()
  • Add optional support for blocks.
  • Consider possibilities of run-to-completion threads that share a stack.
  • Need to be able to restart a thread once it has completed execution.
  • Have an installable error handler to deal with errors in ctors. (?)
  • Add kernel event recording/trace capability, with ability to report via ITM.
  • Free dynamically allocated stack when thread is deleted.
  • Add config option to compute thread stack usage and provide via ar_thread_get_report().

Refactoring

  • Reduce kernel object sizes as much as possible.
  • Move more internal stuff into Ar namespace.
  • Channels only need one blocked list.
  • ar_kernel_enter_scheduler() no longer does anything but call ar_port_service_call(). Merge the two.
  • Use MSP for idle thread and timers. (?)
  • Replace queue with buffered channel?
  • Reset MSP when kernel starts so there is no wasted stack space.
  • Make ar_kernel_run() set the current thread to the idle thread so the scheduler doesn't need a special case the first time it is executed.
  • Add port kernel data struct so the extended frame flag can be included in g_ar. (Really useful?)
  • Clean up enter_scheduler() vs ar_port_service_call() usage, switch threads.
  • Separate tick timer routine sources so they can easily be replaced by the user (or make weak).
  • Do we even need the suspended thread list? (used for cpu usage and thread reports)
  • Limit channel and queue element size to a single word. (?)
  • Return errors for non-zero timeouts in calls from timers, like for ISRs. (?)
  • Can we replace the ar_list_node_t object pointer member with a calculation of node struct offset from the header of the containing kernel object struct?
  • Change kernel flags to bool so writes are atomic. (this goes against kernel object size reduction)
  • Use 16-bit atomic operations to reduce deferred action and runloop perform queue struct sizes (indexes).
  • Make thread load computation work for tickless idle.
  • Add thread stack usage to ar_thread_status_t and compute in ar_thread_get_report().
  • Only run the scheduler when we know we need to switch threads. (maybe already the case)
  • Only handle round-robin in the tick timer (except for tickless).

Language

  • Use nullptr instead of NULL (provide compatibility macro for pre-C++11).
  • Switch to using C11 or C++11 atomics? (increases code size noticeably)(maybe as a weak fallback?)

Api

  • implement C api as wrappers allowing kernel to fully benefit from C++ features
  • (Re) define a cleanup API for port
  • Split ar_port sources (timing, generic,...)
  • Add Thread::join()?
  • Invert thread priorities, so that 0 is highest priority? This is the more common arrangement for RTOSes.
  • Rename _halt() to ar_port_halt_cpu().
  • Add a common header to kernel object structs with type and name pointer?
  • Improve thread init and port APIs so the Thread class doesn't require an extra entry point wrapper.
  • Change to a single ar_object_get_name() API?
  • Change function pointer types to not be pointers, then make params etc pointers.
  • Consider replacing special member function callback support with member function thunk class.
  • Provide option to coalesce function calls added to runloop queue.

testing

  • More thorough testing using cppunit. [Massive effort to get cppunit compiling under IAR.]
  • Write an automated test suite.

Uncathegorized (need to move)

  • Normalize channel and queue class send() and receive() methods' use of ptrs, references, or by value.
  • Remove "m_" from kernel object member names since they are public and accessed directly?
  • Remove need for idle thread by staying in scheduler until a thread becomes ready.
  • Share a common timeout list for timers and blocked threads?
  • Add config option for enabling dynamic stack allocation option, so malloc() is not required.
  • Need a kernel object that can broadcast to wake up multiple threads.
  • Let user allocate runloop function call queue.
  • Remove queue and channel handler function support from runloops?

Issues

  • Use of timers requires another stack.
  • System load has garbage value if idle thread is only run to invoke timers.
  • It's very unintuitive to have default ctor for sem, mutex, channel? not actually init the object.
  • ? Sometimes deferred actions are not being executed as soon as the kernel is unlocked, or the kernel is not being properly unlocked, causing a situation where the deferred action queue can overflow.
  • ? Idle thread will WFI sometimes when we don't want it to, like when running timers back to back.
  • Blocking the idle thread will cause the scheduler to assert.
@diggit
Copy link
Contributor Author

diggit commented Apr 13, 2020

What do you think about full kernel conversion to C++ and C API being implemented as wrappers? This way, Argon could benefit from (modern) C++ features. Even Splitting code into more meaningful namespaces and classes would help with organizations and clearing API.

@flit
Copy link
Owner

flit commented May 2, 2020

(Sorry I missed your question until now.)

Several thoughts about C vs C++ as the main API…

My original goal for Argon was to have a very small kernel that still had a good feature set, and supports fully statically allocated kernel objects (among other goals). C++ wrapping C produces smaller code because you can't include the C++ defines from the C header, meaning inline implementations of the APIs aren't possible.

Another issue with C wrapping C++ is that it makes static allocation for kernel objects difficult and/or ugly.

There's also the concern that embedded developers still tend to prefer C. But that's pretty minor… I don't give it much weight now.

Otoh, I almost exclusively use C++ for embedded projects, though I tend to use it in a "C++ lite" style and try to avoid template metaprogramming.

So… I'm leaning towards dropping the C API. 😄 (For a C API, I'm wondering if it would be better to have a separate project, or at least a separate implementation.)

@diggit
Copy link
Contributor Author

diggit commented May 3, 2020

My original goal for Argon was to have a very small kernel that still had a good feature set, and supports fully statically allocated kernel objects (among other goals).

Yeah that one of main reasons I like Argon even though it's not mainstream rtos and has some hiccups. Internal principles are clear ad easy to debug/tackle with.

There's also the concern that embedded developers still tend to prefer C. But that's pretty minor… I don't give it much weight now.
Otoh, I almost exclusively use C++ for embedded projects, though I tend to use it in a "C++ lite" style and try to avoid template metaprogramming.

I used to program embedded systems in C too, but ~2 years ago, I've switched to C++ because there were advantages only. I went even further and utilize template meta-programming quite a lot (where it makes sense). With that, I have a lot of things solved at compile time.

Well, decision about C API and everything is up to you (I am kind of alien here :). I don't see strong reason to have C API when compiler has to be able to compile C++ anyway.

There are changes I'd like to see in Argon, but I'd prefer not to do fork and play on my sand alone. So I want to know you opinions about them and thus ask about everything.
In case of dropping C API

  • Struct naming: ar_kernel_t -> Ar::Kernel etc. ?
  • migrating to scoped enums (de-bloating global namespace, stricter type checking) ?
  • switching to constexprinstead of enums for constants ?
enum _ar_timeouts
{
    kArNoTimeout = 0,                   //!< Return immediately if a resource cannot be acquired.
    kArInfiniteTimeout = 0xffffffffUL   //!< Pass this value to wait forever to acquire a resource.
};

to

using Time = uint32_t; //eg. easier to change when switching to uint64_t and us resolution everywhere
namespace timeout {
    constexpr Time None = 0;
    constexpr Time Infinite = std::numeric_limits<Time>::max();
};

or go even further about units. Even though custom literals are floats, ctors are constexpr and floats get optimized out. A lot of templating there to afterwards easily select which operators apply to which unit...

  • if constexpr (...) could replace most o ifdefs, but that's C++17, so not at this moment I guess...
  • wrap assert(...) and let user decide if he wants to use standard one from <assert.h> or some custom implementation
  • C++ RAII wrapper for Mutex ?
Ar::Mutex mutex("some mutex");

void foo() {
    auto _mtx = Ar::ScopedMutexAcquisition(mutex); //C++20 would allows us to put this `if(here; ...)`
    if (_mtx) {
        //block of code executed when/if mutex acquired
        //some code with multiple returns
        //where you don't have to bother about mutex releasing before each return thanks to RAII
    }
}
  • etc...

@flit
Copy link
Owner

flit commented Jul 6, 2020

In my absence, I've had a lot of time to think about this… (I was really conflicted!) So:

  • In the main-line Argon, I'd like to keep the structure of the C API with C++ wrapper. But we can move to C++14 internally.
  • At the same time, I'm really curious and excited to see what can be done with full C++14 utilization and would whole-heartedly support an "Argon++" alternative API and implementation.

There are several things going into the rationale for this.

  • The argument for having a C API is about the users rather than compiler support. (It's fine to require a C++ compiler; everyone has one available now.) A lot of users either aren't totally comfortable with C++ for whatever reason, or just want to use C because it's simple. For certain research projects we use C because it's more easily understandable by more people and is closer to the metal.
  • I have to admit my advanced-C++ skills are pretty lacking lately, as most of the code I write needs to be as widely accessible as possible or conform to existing projects that—meaning C and/or C++ "lite" (aka C with classes). And for research projects at work, Rust is become really popular (though I'm not using it just yet).
  • Sadly, I doubt I have time to work on a new Argon implementation myself beyond incremental stuff. If I'm working on RTOS code, I'd rather spend my time on research projects to extend Argon.

Btw, there is an Ar::Mutex::Guard RAII wrapper already defined. 😄

@flit
Copy link
Owner

flit commented Jul 6, 2020

I was thinking about making a separate GitHub organization for Argon, so it has a home of its own away from my other repos. What do you think?

@diggit
Copy link
Contributor Author

diggit commented Jul 8, 2020

The argument for having a C API is about the users rather than compiler support. (It's fine to require a C++ compiler; everyone has one available now.) A lot of users either aren't totally comfortable with C++ for whatever reason, or just want to use C because it's simple. For certain research projects we use C because it's more easily understandable by more people and is closer to the metal.

C++ has features allowing code to be more safe and compile time checked and evaluated. IMO users should be pushed towards solutions which provide safer application. Yeah, many people don't want to use C++ (on embedded), a few I know..

And for research projects at work, Rust is become really popular (though I'm not using it just yet).

I am really happy to see Rust gaining popularity! (Even though I am total noob in Rust, key concepts and features of rust really appeal me.)

Btw, there is an Ar::Mutex::Guard RAII wrapper already defined. 😄

Whoopsie, did not spot it. I also have another RAII helper which serves as proxy to access some mutex protected data. It is a way how to ensure, that some data are accessed with acquired mutex only.

I was thinking about making a separate GitHub organization for Argon, so it has a home of its own away from my other repos. What do you think?

Well, it's up to you. If you want so separate if from your account, go for it. I don't think it's necessary from outside POV. It would make sense if Argon had more developers and public interest.

BTW, I use Argon RTOS in my diploma thesis 😄
I'd like to experiment with dropping C API and analyzing code size and speed changes, but no time for that at this moment (deadline is close)).

@flit
Copy link
Owner

flit commented Jul 18, 2020

C++ has features allowing code to be more safe and compile time checked and evaluated. IMO users should be pushed towards solutions which provide safer application. Yeah, many people don't want to use C++ (on embedded), a few I know..

I completely agree. I've repeatedly pushed for and tried to use C++ in industry projects, but the argument has always been that users won't accept it…

I am really happy to see Rust gaining popularity! (Even though I am total noob in Rust, key concepts and features of rust really appeal me.)

Yeah, I'm a Rust noob too, slowly learning. :) But ironically, I've recently become the maintainer of a Rust project cmsis-pack-manager since it's used by pyOCD and the original author moved on.

Btw, there is an Ar::Mutex::Guard RAII wrapper already defined. 😄

Whoopsie, did not spot it. I also have another RAII helper which serves as proxy to access some mutex protected data. It is a way how to ensure, that some data are accessed with acquired mutex only.

Nice! That looks very much like how mutexes work in Rust.

Well, it's up to you. If you want so separate if from your account, go for it. I don't think it's necessary from outside POV. It would make sense if Argon had more developers and public interest.

The main reason would be to increase visibility of Argon. For the time being I probably won't change anything.

BTW, I use Argon RTOS in my diploma thesis 😄

Awesome!

I'd like to experiment with dropping C API and analyzing code size and speed changes, but no time for that at this moment (deadline is close)).

Totally understood, same here.

@0Grit
Copy link

0Grit commented Aug 18, 2020

Yeah just look at what happened to livius. He completely rewrote cmsis in c++ and got mostly negative feedback.

Though C is my strongest language, I despise it.

@diggit
Copy link
Contributor Author

diggit commented Aug 19, 2020

@Loverdeg can you provide more info, links etc.? I am interested in details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants