[NSWI004] A03 grading and notes

Vojtech Horky horky at d3s.mff.cuni.cz
Thu Nov 26 09:21:15 CET 2020


Hello,

I will be uploading comments for A03 assignment to your grading 
repository shortly.

Generally, your solutions were pretty good - only two teams had some 
failing tests, most of the solutions were simple and elegant and quite 
easy to read (hence there are not that many comments this time). Good 
job and thank you!




Several issues that are worth mentioning are described below as they 
might be interesting to more teams even if not directly relevant to 
their code. They are in no particular order.


Note the difference between having the following in the scheduler:

static list_t* ready_queue_ptr;
static list_t ready_queue;

Both are correct but the first approach requires extra kmalloc and 
panic_if in the initialization to actually allocate the memory. It is 
much simpler to use the second variant as it means less complicated 
code. This is not Java where every object has to be created via "new".

Similarly, it is completely okay (and better as well) to have context_t 
directly embedded inside thread_t (instead of having a pointer) as you 
need only one allocation for the object. It is also a bit more cache 
friendly and it simplifies allocation code.


As already mentioned in some previous e-mails - check for errors where 
possible and also ensure that you are not leaking memory.

void *ptr1 = malloc(..);
if (ptr1 == NULL) { return NULL; }
void *ptr2 = malloc(...);
if (ptr2 == NULL) { return NULL; }

This code leaks memory of ptr1 if the second allocation fails. Correct 
approach is to add free(ptr1) the second "if" or use error gotos as are 
for example used in Linux [1].

[1] 
https://github.com/torvalds/linux/blob/156c05917e0920ef5643eb54c0ea71aae5d60c3d/tools/testing/selftests/cgroup/test_memcontrol.c#L27


I also need to stress once again the usefulness of the list_t/link_t 
data structures. I understand that they are different from what you 
might have been used to and they might look funny but they have one big 
advantage: adding an item to a list does not require any memory 
allocation. Hence, adding link_t sched_link to thread_t means that 
adding or removing a thread from ready queue does not require an 
allocation. An allocation that might fail. In a function that shall not 
fail as it cannot announce its failure.

There were solutions where thread_yield() could actually fail with 
out-of-memory condition. It is rather funny that a thread that 
voluntarily let other threads run would be punished by being killed (or 
by shutting down the whole kernel).

I also discovered a bug in thread/exhaust test that should have actually 
checked against this. The fixed test is now in the upstream repository. 
Please merge and fix your implementation if you are affected by this. 
There should be plenty of time to fix this until next assignment but 
feel free to contact us for an extension for this particular test. Sory 
for the confusion.


For completeness, the scheduler functions can be only thin wrappers 
around list_append() and list_remove() and thread functions will be 
using them:

thread_suspend() - scheduler_remove, scheduler_schedule_next
thread_yield() - scheduler_schedule_next
thread_finish() - scheduler_remove, thread_wakeup(joining_thread_if_set)
etc.

Teams that realized that scheduler_remove_thread() actually makes sense 
has the scheduler implementation about 6 added lines long and thread 
functions (except for thread_create) less than 10 lines each.


On a related note - if you decided to give threads explicit states, it 
it much easier to set them in the threads module rather than in the 
scheduler. Because then the following implementation is sufficient

thread_suspend - state = suspended; remove and yield
thread_finish - state = finished; remove, wake-up joining, yield

while if we set the states in the scheduler, we would need to either add 
an extra method or pass an extra argument or extra "if".


Perhaps this was not clearly stated in the assignment - thread_join 
practically invalidates the thread handle. I.e. any operation on 
thread_t that was already joined is undefined and does not make any sense.

thr = thread_create(...)
while not thread_finished(thr):
     print("still working")

thread_join(thr)
if thread_finished(thr): // ERROR! - thr is no longer valid
     print("finished")

Note that in managed environments (e.g. Java) this may not happen as the 
object will be around as long as you have a reference to it. In C, there 
would be no other place to actually destroy the thread if thread_join 
would not behave in this manner.


While having comments in your code is generally a good idea, please, 
comment things that are not clearly visible in the code. The following 
comments

// Set the thread as ready for execution
thread->state=READY;
// Append it to the ready list
list_append(&thread_queue, &thread->queue_link);

really do not add any new information that would not be provided by the 
actual code. It is not an error but it visually clutters the code and 
such comments are often not updated and thus become confusing over time.


Last note is related to your Git activity (and scoring). We will be 
recomputing the score to actually compute only reasonable lines of code 
as several of you managed to commit the whole target/ subdirectory and 
thus with each commit gained thousands of added lines because of the 
modifications of the log files under target/.

I do not want to prescribe any workflow but any decent Git client should 
be able to show you a diff prior a commit. If you see unrelated changes 
it is perhaps time to split your commit into multiple ones or remove the 
build files from the repository completely.

Note that on command-line, it is possible to use git add -p to split 
changes in one file into multiple commits.


As usual - if you have any comments/questions, do not hesitate to 
contact us (this ML for general questions and teachers-nswi004 for 
complaints/comments/questions about your grading).

When contacting us about grading or asking for a help for a particular 
piece of code, please, add your team mates to CC to speed up the 
communication.

Cheers,
- VH


More information about the NSWI004 mailing list