-
Notifications
You must be signed in to change notification settings - Fork 67
Implement config file reloading and improve the config parser #47
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
Conversation
This will be used when re-parsing the config.
…date, fixed definition in header
I still need to fix the item order and persistent separators.
Previously, it would add items to the end of the list every second update. This was because we kept track of where to add the item based on the index of the *original* menu, but this changes when we add our items. To fix this, we get the action to add items before *after* we remove our own ones.
It's not actually needed. This reverts commit 979d6e5.
|
This is ready for testing. In particular, I'd like someone to try and break the update mechanism (try and make it incorrectly detect an update or lack thereof, also ensure the items are in the correct order, make sure it still works correctly after a USBMS session), I want to make sure I didn't leave any edge cases (no menu items, etc) unhandled, and I would like another pair of eyes on the pointer/memory handling in In addition, you shouldn't be able to cause it to crash at any point (e.g. I tested that it wouldn't crash if the config files were modified while a menu was open and an item was pressed, and it worked fine because we only check for config updates when the menu is opened). Also, @NiLuJe, can you ensure that your KFMon generator works with KFMon running, with KFMon changes (you'll need to P.S. A code review would also be appreciated. |
|
I do have one idea for automatic updates for KFMon: In another PR, I could implement generator updates and the KFMon one could check the mtime of the socket (which KFMon can |
|
I'm trying to figure my way through the code, but I have to admit, first impressions are... convoluted. Mainly around the More thoughts when I can (hopefully) figure most things out. |
|
The code in I would have thought a better way would be to have a single global struct that contains all the required state, with the required updating functions updating it directly, preferably via a pointer parameter (to make it clear what's being modified). The menu ejecting code could then just check needed flags, and any error messages etc. What am I missing? |
|
Just had another thought. You might need to go back through the config parser code and check for memory leaks, now that config parsing is no longer a one-time affair. (I'm specifically thinking about returning on error without freeing the calloc'ed |
|
I won't have time to give this a proper look-see until this week-end, but it's on top of the list ;). |
Yes, it is somewhat convoluted. I ended up on the current design after thinking of how I can keep pointers valid for as long as possible, free stuff as soon as possible, and be the most efficient. The first thing I did was to split the file scanning from the config. The other option I was considering was to add a file/date field to each config item (or just the first one from each file), but I realized that would limit future flexibility, it isn't that clean, and nothing uses it (or should use it) except during the initial parsing. This led to Then, I was thinking about how to update it in a way which would allow returning errors while leaving the original one untouched, and also handle freeing the memory. This led to Afterwards, I had to figure out the best way to manage the config and errors with the least code duplication, specifically around the error items (I wanted to create those in one place during the parsing rather than in the menu for each error). This led to the 4 variables: For That's basically how I ended up with the current design. I'll have a look at the config parsing itself and see if I can simplify the memory management in it (probably by making the struct on the stack first, then only allocating them memory on success rather than beforehand). |
* No more memory leaks on error. * Properly handle memory allocation errors. * Cleaner code. * Less chance of making mistakes when adding features in the future. * Also made if statements easier to read. There are still a few things which could be simplified.
|
I've basically rewritten the config parser over the last 3 commits. It should be faster, more stable, more efficient, easier to extend, and won't leak memory anywhere (even when errors occur). The only downside is that it is twice the lines of code. I've already done some tests with it, but while testing the config reloading, also try out different config errors to make sure they are still handled properly. If you have any suggestions for improving the config parser further, I'd be happy to hear them. |
|
And that's it for tonight, I think ;). (I've also implemented and tested the mtime-on-kfmon-socket thing on KFMon's side, and that works beautifully :). Also made the config order alphabetical there, too). |
|
Also, random easy refactor idea: move the config filtering to the actual (And get rid of the logging on |
Yes, thanks for catching that. The list used to be linked in reverse until I refactored the config parser. Then, that made the menu item adapter go in the wrong order, which, as you noticed, I fixed. But, I tested the generators before that fix, making me forget about the generator code. I'll probably apply your first fix, as I feel it's a bit more concise than the second.
👍
I noticed. Is there a particular case which is broken with
I can't remember why I decided against it, but upon looking at it again, I don't see why not. Did you happen to test the config errors yet? |
Hmm, which config errors? ^^ EDIT: The Clang SA stuff? If so, yep, the fixes did the trick, and I think I agree with you on the false-positives left ;). |
|
The usual ones (just to make sure I didn't mess them up during the refactor). I've already tested some of them. |
Besides the action/generator fields no longer being validated, I haven't noticed anything new. Bogus args are handled on a per-action basis, IIRC, so that shouldn't have been affected. Not quite sure what else could go wrong ;). |
This regression allows chains to continue menu items from the previous config file.
980a59a to
64b3822
Compare
|
I've tested the error handling with: I deleted the first line each time I tested it. |
|
I think this is pretty much ready now. The parser emits errors properly, and I think I've fixed all regressions from the refactor. I've also tested all the examples and my own config. I'll probably merge this, and I might post a beta version on MR later this week for testing. |
|
Another random thought: at boot, config parsing is bracketed between the failsafe mechanism. That's no longer the case when updating configs. Should we care? (I say that because I did manage to busy-loop nickel when breaking the linked list stuff ^^). |
I originally thought of that (hence the now-reverted instant failsafe destruction commit), but I decided against it, as it would mean I need a mutex to ensure the failsafe isn't already running, and if it was going to crash, it would do it during the initial parsing, which would trigger the failsafe. And, if it did happen to cause issues only after the first parse (i.e. when the menu is opened), NM can be uninstalled manually by connecting via USB or telnet without using the menu. Does this seem reasonable? |
|
@geek1011: Nope, sounds good. In any case, if an uncaught bug does cause an issue during a config update, Nickel will softlock, which means sickel will reboot the device. Since the device was essentially unusable, the configs won't have been touched, at which point they'll trigger the exact same issue during the newt boot, except this time it'll be during the failsafe window, so, everybody wins ;). It essentially boils down to simply needing two reboots instead of one to "fix" it by self-destruct. EDIT: Which is what you just said :D. It's late ^^. |
…ting one (fixes #57) Instead of returning a bool from `nm_global_config_update` indicating whether the menu items were modified, return an int indicating the current config revision which can then be compared against one stored as a property of the menu. This issue was found by @jackiew1. See #56 for more details. This fixes an issue in ee0eb7c (#47).
…ting one (fixes #57) (#58) Instead of returning a bool from `nm_global_config_update` indicating whether the menu items were modified, return an int indicating the current config revision which can then be compared against one stored as a property of the menu. This issue was found by @jackiew1. See #56 for more details. This fixes an issue in ee0eb7c (#47).
This fixes a regression in ee0eb7c (#47) which caused vague error messages to be returned instead of specific error messages from nm_config_parse__line_*. These functions should have returned true on error, but were returning NULL (i.e. false) instead, causing nm_config_parse to treat it as an unknown line type instead of returning the specific issue with the line. This regression does not cause any issues other than vague error messages being returned for certain errors during config parsing. In addition, this fixes another regression discovered by @NiLuJe where configuration errors would persist in rare situations due to nm_config_files not clearing existing errors as expected. This issue does not happen if the config error menu item is pressed to see the error message since nm_menu_item_do clears errors.
This PR implements config file reloading.
Every time the menu is opened, the config files are scanned. If the number of files or the modification time of one changes, they are re-parsed and re-generated. If there is a config error or I/O error while parsing or scanning the files, an item is added showing it like usual. If there aren't any config entries, the usual one referring to the documentation is shown.
There should not be any noticeable delay in opening the menu, except around another 200ms (up to 500ms) when opening it after a config change.
closes #42
For the config parser improvements, see #47 (comment).
closes #48