Internship wrap up

Journey summary

When I started the internship journey, I was worried that I may not be up to the task . I wanted to grasp a lot of thing at once which was a difficult thing to do. My first patch series were rejected. I worried I was not doing enough .

After following the advice of my mentor Boqun Feng, I started gaining confidence. I realised I have to learn one subject at a time.

I did not believe myself when I got 30 patches accepted without revision. It turns out that my worry did not come true. I had the best mentor.


How did your Outreachy mentor help you along the way?

The mentor was a guide for me and a friend. I learned a lot from him. At first when I had my first patchset rejected, he automatically requested that I sent him patches first before sending them to the community. I did so and he advised me on which one will be accepted and I follow his advice and understood why a patch is rejected. He often send me some link to article to read , then we have our weekly video call where we catch up.

I would also send him a mail when I felt stuck, he would reply suggesting me a direction to take.

How did Outreachy help you feel more confident in making open source and free software contributions?

Getting into Outreachy internship is not easy as one has to pass the requirement and commit to work on an approved project .

However nothing good comes with ease. The internship was an exciting opportunity, a chance to dive deep into an Open Source project of your interest and get hands on experience.

The project I applied for was titled “Fixing lock related warning in the core Linux Kernel”.

I fortunately did fix many of these warnings and currently commit to put aside some time to continue working on these warnings.

I admit I could not have understood the project without the help of my mentor Mr Boqun Feng, an expert in the Linux Kernel.

I appreciate his help and mentorship. He was a guide for me and helped me understand the Linux Kernel. I really owe him a lot.

Outreachy provides me with this opportunity to dive deep into a project from a newbie perspective to mastering. Outreachy works with experts in Open source to provide mentorship to newbie like me and help us improve our skills.

What communication skills have you learned during the internship?

When sending patched, I interact with maintainers, the social interaction is one of the best part of the internship for me, I improved my communication skills. Also we were required to write blogs of our progress, I felt scared to write a blog as this was y first time ever. I have realised that by writing about a technical subject I master it. I would like to continue bloging on technical topics.

What technical skills have you learned during the internship?

I learned about linked List , Scheduler, Sparse, RCU (this is my favourite subsystem : D)

My project pushed me to dive into compilers with Sparse which I found fun.

What parts of your project did you complete?

The part of fixing lock related warnings, I believe I have fixed all the up to my skills lock warning in the Linux Kernel.

What are my next steps ?

My next steps are

  • Thoroughly examine how to solve the remaining more difficult locks related warning problems
  • Rewrite and add more technical blogs.
  • Build a project.
  • Being a Linux Kernel engineer is my final destination.

I just want to say thank you to Outreachy program and to my mentor Mr Boqun Feng.

Types of context imbalance warnings and how to annotate

Types

There are three types of context imbalance warnings:

  1. warning: context imbalance – unexpected unlock
  2. warning: context imbalance – wrong count at exit
  3. warning: context imbalance – different lock contexts for basic block

How to annotate

Unexpected unlock

This is the easiest of all, what happens here is that the function enters the critical section at entry without exiting or it can be the function exit the critical section without entering, both ways Sparse will throw a warning. Locking is not balanced, for each entry to the critical section, there should be a corresponding exit from it.

Adding __releases() or __acquires() annotation to the function will generally solve the issue .

Wrong count a exit

This situation generally happens when Sparse gets confused of the logic function. It thinks the function releases the lock at exit when it s still holding the lock or acquires when it releases or finally hold the lock when

Different lock contexts for basic block

This situation happens when the function has many branches or conditions with different locking outcomes. This may be a bug or just a logic that hit the limit of Sparse.

To solve this issue one may consider refactoring the code if necessary.

Please consider that the situation described above are general, this implies that one may encounter more complex situation throwing one of the above warnings.

Annotations for Sparse context imbalance warnings

Sparse has a validation folder which includes rules in form of C files, that a target source code should meet; if it does not , warnings and errors will be thrown once it is compiled with Sparse enabled.

https://git.kernel.org/pub/scm/devel/sparse/sparse.git/tree/validation/attr-context.c
https://git.kernel.org/pub/scm/devel/sparse/sparse.git/tree/validation/context-stmt.c
https://git.kernel.org/pub/scm/devel/sparse/sparse.git/tree/validation/context.c

There are many types of warnings that Sparse throws, in this article , we will particularly  focus on one type of these warnings: the context imbalance warnings.

Given the fact that locks coordinate the operations of multiple running processes to prevent conflicts or race condition, Context imbalance warnings occur when a possible locking fault is detected in the source code. This can be an acquire lock without the release counterpart or vice verca.

For more details about lock, click on the link.

Fixing context imbalance warnings may either require adding the right annotations or refactoring the code. It is the responsibility of the programmer to find the appropriate solution.

We discussed so far about Sparse and its context imbalance. It’s time for annotation.

What is an annotation ? Well, a small piece of code that conveys information about how functions handle locks; a function acquires lock when entering a critical section, releases when exiting this critical section, lock can also be held at entry and exit.

Having said that , there are three types of annotations describing the three situations above:

__must_hold – The specified lock is held on function entry and exit.

__acquires – The specified lock is held on function exit, but not entry.

__releases – The specified lock is held on function entry, but not exit.

These annotations are actually macros, undefined for GCC but defined during a Sparse run to use the “context” tracking feature of sparse, applied to locking. Annotations tell sparse when a lock is held, with regard to the annotated function’s entry and exit.

Annotations are however not always needed: If the function enters and exits without the lock held, acquiring and releasing the lock inside the function in a balanced way, no annotation is needed.

eg.

unsigned int kstat_irqs_usr(unsigned int irq)
{
        unsigned int sum;

        rcu_read_lock();
        sum = kstat_irqs(irq);
        rcu_read_unlock();
        return sum;
}
      

The three annotations cited above are for cases where Sparse would otherwise report a context imbalance.

At definition, the annotations or macro functions respectively __must_hold(x), __acquires(x) and __releases(x) have each the extended attribute.

This can be found in the file include/linux/compiler_types.h of the linux kernel source code.

# define __must_hold(x) __attribute__((context(x,1,1)))
# define __acquires(x)  __attribute__((context(x,0,1)))
# define __releases(x)  __attribute__((context(x,1,0)))
# define __acquire(x)   __context__(x,1)
# define __release(x)   __context__(x,-1)

Our focus is is on the first three macro.

__attribute__ is a __ GCC__ extension , it can refer a return type or data type .

__context__  is a Sparse specific specifier  .

we can easily see that the format is :

__attribute__((context(expression,in_context,out_context))

The functions require the context expression (for instance, a lock) to have the
value in_context (a constant non negative integer) when called, and return
with the value out_context (a constant non negative integer).


In the case of

 __must_hold(x) is defined as
 # define __must_hold(x) __attribute__((context(x,1,1)))

The expression is x in_context = 1 out_context = 1
  __acquires(x)
# define __acquires(x)  __attribute__((context(x,0,1)))
The expression x or lock is disabled when in_context = 0 before then enter critical section x becomes enable and out_context = 1
__releases(x)
 # define __releases(x)  __attribute__((context(x,1,0)))
expression x in_context = 1 and out_context = 0

When an API is defined with a macro, the specifier __attribute__((context(…))) can be replaced
by __context__(…). Hence the above can be rewritten as

 # define __acquire(x)   __context__(x,1)
 # define __release(x)   __context__(x,-1)