-
Notifications
You must be signed in to change notification settings - Fork 45
!syscalls/threadsinfo: return more granular thread information #720
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
base: master
Are you sure you want to change the base?
Conversation
Summary of ChangesHello @oI0ck, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly refactors the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
55881ff to
c647754
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a more flexible threadsinfo syscall, which is a great improvement for querying thread information. The refactoring of proc_threadsList into smaller helper functions is also a positive change. However, I've identified a few critical issues that must be addressed. These include a typo that will cause a compilation error, and incomplete validation of user-provided arguments in the syscall handler, which poses a security risk. Please see my detailed comments for each issue.
c647754 to
5104b56
Compare
3c6ba52 to
93985e7
Compare
93985e7 to
fbb7eaf
Compare
Unit Test Results9 462 tests ±0 8 839 ✅ - 34 48m 59s ⏱️ -57s For more details on these failures, see this check. Results for commit e2d308f. ± Comparison against base commit cbfa646. ♻️ This comment has been updated with latest results. |
fbb7eaf to
e3f8392
Compare
|
CI test fails are a result of the fact that this PR breaks compatibility and it requires correspondent changes in |
e3f8392 to
36b7461
Compare
| } | ||
|
|
||
|
|
||
| static inline int _proc_calculateVmem(thread_t *thread) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefixed with _ - does it require any external sync? there is a spinlock inside, so I guess not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It uses a thread_t *, so we have to guarantee that it won't be deallocated, therefore it should be called with threads_common.lock set, as all the other functions here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would make it explicit in the comment then, as the use of thread_t * alone doesn't imply that - usually you just up the refcnt on a thread, guaranteeing that it won't get deallocated when you need it and threadsinfo is an exception.
proc/threads.c
Outdated
|
|
||
|
|
||
| int proc_threadsList(int n, threadinfo_t *info) | ||
| static inline void _proc_makeProcessName(thread_t *thread, char *name, int sz) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefixed with _ - does it require any external sync?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above
| if (tid == PH_THREADINFO_THREADS_ALL) { | ||
| t = lib_treeof(thread_t, idlinkage, lib_rbMinimum(threads_common.id.root)); | ||
|
|
||
| if ((flags & PH_THREADINFO_OPT_THREADCOUNT) == PH_THREADINFO_OPT_THREADCOUNT) { | ||
| do { | ||
| i++; | ||
| t = lib_idtreeof(thread_t, idlinkage, lib_idtreeNext(&t->idlinkage.linkage)); | ||
| } while (t != NULL); | ||
|
|
||
| (void)proc_lockClear(&threads_common.lock); | ||
|
|
||
| return i; | ||
| } | ||
| else | ||
| #endif | ||
| if (map != NULL) { | ||
| (void)proc_lockSet(&map->lock); | ||
| entry = lib_treeof(map_entry_t, linkage, lib_rbMinimum(map->tree.root)); | ||
|
|
||
| while (entry != NULL) { | ||
| info[i].vmem += (int)entry->size; | ||
| entry = lib_treeof(map_entry_t, linkage, lib_rbNext(&entry->linkage)); | ||
| } | ||
| (void)proc_lockClear(&map->lock); | ||
| while (i < n && t != NULL) { | ||
| proc_threadInfo(t, flags, &info[i]); | ||
| i++; | ||
| t = lib_idtreeof(thread_t, idlinkage, lib_idtreeNext(&t->idlinkage.linkage)); | ||
| } | ||
| else { | ||
| /* No action required */ | ||
| } | ||
| else { | ||
| t = lib_idtreeof(thread_t, idlinkage, lib_idtreeFind(&threads_common.id, tid)); | ||
| if (t == NULL) { | ||
| (void)proc_lockClear(&threads_common.lock); | ||
| return -ENOENT; | ||
| } | ||
|
|
||
| ++i; | ||
| t = lib_idtreeof(thread_t, idlinkage, lib_idtreeNext(&t->idlinkage.linkage)); | ||
| proc_threadInfo(t, flags, info); | ||
| i++; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe wrap it in do { ... } while (0); and just break instead of returns inside to always converge into same branch with lockClear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, that is pretty ugly. I've rewritten PH_THREADINFO_THREADS_ALL as a do-while loop and it's better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, what I meant was that since all your if-else returns were not nested in a loop, you could just wrap everything in the do { ... } while (0); and replace any branch like
if (....) {
...
} else {
t = lib_idtreeof(thread_t, idlinkage, lib_idtreeFind(&threads_common.id, tid));
if (t == NULL) {
(void)proc_lockClear(&threads_common.lock);
return -ENOENT;
}
}
(void)proc_lockClear(&threads_common.lock);
return i;with
do {
if (....) {
...
} else {
t = lib_idtreeof(thread_t, idlinkage, lib_idtreeFind(&threads_common.id, tid));
if (t == NULL) {
i = -ENOENT;
break;
}
}
} while (0);
(void)proc_lockClear(&threads_common.lock);
return i;so that the code doesn't diverge inside the if-else. This way there is always one returning path that clears the threads_common.lock and you don't need to remember about in other branches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I know what you mean, but it still looks a bit better, since in PH_THREADINFO_THREADS_ALL case, we will have to use the loop either way, so making two loops inside of two branches (when they do mostly the same thing) is kinda ugly and the way I rewrote it also addresses having two return points.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is still one return in else, that's what confused me, but if you think that forcibly reducing the divergence would clutter the code more than solve anything here, then it's fine by me
proc/threads.c
Outdated
| i++; | ||
| t = lib_idtreeof(thread_t, idlinkage, lib_idtreeNext(&t->idlinkage.linkage)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we shouldn't just maintain a global thread count instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be, though I'd say that's good enough for the amount of changes here. We'd have to guarantee that this counter will be kept in sync with node count in tree, which I'd say is besides the point in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you're right. Maybe add a TODO/REVISIT then for now?
36b7461 to
bad1fa0
Compare
julianuziemblo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MISRA nits (for a better (worse) evening)
proc/threads.c
Outdated
| int i = 0, argc; | ||
| unsigned int len, space; | ||
| thread_t *t; | ||
| int i, len, left = sz; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd leave left as int (or maybe long?) and change type of i and len and sz to size_t or unsigned int, as sz is always passed from sizeof.
Then of course remember to cast to int when assiging to left as for MISRA...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed all of them to size_t as well as parameter sz, since we always pass sizeof
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the test in line 2103 (left <= 0) is pointless because left cannot be < 0. You should change back the type as this probably introduces an error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eh, right, was tired when commiting that, i'm changing left to long
| entry = thread->process->entries; | ||
| if (entry != NULL) { | ||
| do { | ||
| vmem += (int)entry->size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ik this would break the interface, but is there a reason [threadinfo_t]::vmem is int? if not - could it be changed to unsigned (or size_t) to avoid these awkward casts?
After a quick look: this shouldn't break much, at least in the main repo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 - these changes are already breaking, so IMO this is a good opportunity to tidy up types in threadinfo_t and potentially reduce casts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so another thing if this is breaking: signal it with ! in PR title and checkbox in description
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm dropping the vmem type change, correcting those type may have bigger implications and should be considered on its own.
bad1fa0 to
ee5ddc6
Compare
julianuziemblo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More comments to threadsinfo_t data structure. Some of its members seem to have improper types with no explanation and we could fix it while at it.
|
|
||
| typedef struct _threadinfo_t { | ||
| pid_t pid; | ||
| unsigned int tid; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tid seems to sometimes be signed, and sometimes unsigned. Broader question here - do you happen to know if there's a reason for this? Even proc_getTid() returns int. @adamgreloch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Internally tid is an idtree key which is signed to support POSIX handles
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A signed thread identifier makes little sense as a key in a tree structure. By convention, values such as PID are unique ID based on a counter, so making it signed is seemingly pointless, unless to signal a possibility of returning an error within the negative domain.
| int priority; | ||
| int state; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
state and priority seem to be bitmasks too, could probably be changed to unsigned int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
priority is an index into thread_common.ready, which is an array of arrays containing threads divided by their priority. Signedness of this value is more engraved in the system, as apparent by proc_threadPriority and the priority syscall, changing this seems unnecessary, at least as a part of this PR.
state is an enum with 3 possible values, READY (0U), SLEEP (1U), GHOST (2U), so while, sure, we could change this type here, it is not only breaking, but it might be, that in the future, someone may want to introduce a state signalling an error as a negative value, which would the require changing it back to int, so further breaking changes.
I'd personally stray from making further breaking changes within this PR, as it will be harder to merge it, reason about implications of it, and so on and so forth. The fact that it is already breaking should not be a signal to break even more, without a proper discussion. Review comments are a place to talk through changes made in a specific PR, to probably make it better, not introduce more changes unrelated to the PR.
This should be talked through in-person or on our issue tracker, so if you are keen making those changes, please create a new ticket, I'll be glad to participate in the discussion.
threadsinfo is not very flexible, takes a long time and causes unnecessary overhead in programs using it. This commit means to make it more flexible, by being able to query a thread identified by tid and query for specific thread attributes as specified in flags bitmask. Moreover, previously there was no was of inexpensively checking amount of present threads in the kernel, therefore the buffer passed to threadinfo may have been often reallocated to check all threads. Now threadsinfo, if passed a PH_THREADINFO_OPT_THREADCOUNT flag will yield no information in passed buffer, but will return amount of currently present threads. JIRA: RTOS-1187
ee5ddc6 to
e2d308f
Compare
Description
This commit means to make
threadinfomore flexible, by being able to query a thread identified bytidand query for specific thread attributes as specified inflagsbitmask.Motivation and Context
threadsinfois not very flexible and causes unnecessary overhead in programs using it.Moreover, previously there was no was of inexpensively checking amount of present threads in the kernel, therefore the buffer passed to
threadsinfomay have been often reallocated to check all threads. Nowthreadsinfo, if passed aPH_THREADINFO_OPT_THREADCOUNTflag will yield no information in passed buffer, but will return amount of currently present threads.JIRA: RTOS-1187
Types of changes
How Has This Been Tested?
ia32-generic-qemu,riscv64-generic-qemu,sparcv8leon-generic-qemu,armv7a9-zynq7000-qemu,armv7r5f-zynqmp-qemu.Checklist:
Special treatment