contributed by < slipet >
fibdrv.c
存在著 DEFINE_MUTEX
, mutex_trylock
, mutex_init
, mutex_unlock
, mutex_destroy
等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題。嘗試撰寫使用 POSIX Thread 的程式碼來確認。 搭配閱讀〈並行和多執行緒程式設計〉In the original design, the Fibonacci sequence is stored in a long long
type array, which will overflow after fib(92). In this report, I followed the recommendation from link to implement two methods to deal with this issue:
__uint128
type:Declare the array for recording Fibonacci sequence using __uint128
type. The key difference between the long long
and __uint128
types is that printf()
cannot directly output the result with __uint128
type. As the result of this, we need to convert the number into a string and pass it to the user process through a buffer.
uint128_to_string
and uint128_len
are the functions associated with uint128_t
type. Below are the details of the implementation:
So far, we are able to accurately calculate the Fibonacci sequence up to n = 100; however, we still encounter overflow after n = 187.
There is an alternative for the large number representation mentioned in link, which is a customized data structure. I reference the implementations from AdrianHuang and SSO-23 to design myBigN
for large number representation.
Numbers up to 15 digits are represented using the myShort
structure. Whenever a number exceeds 15 digits, we dynamically allocate memory space to a pointer in myLong
for storing large numbers. Both structures include a reserved byte to record information about free space, size, and a control flag. The following is the implementation associated with myBigN
.
The strategy for myBigN
variables addition is implemented character by character. Below are the details of this method.
The macros MY_BIGNUM_TMP
and INIT_STRING_LITERALS
, referenced from AdrianHuang, leverage the designated initializer to make the initialization of variables more elegant and readable.
In MY_BIGNUM_TMP(x)
, we can initialize a myBigN pointer with NIT_STRING_LITERALS()
and a string literal. Declaring the INIT_STRING_LITERALS()
macro is equivalent to declaring a myBigN object. myBigN_init
receives the address of the object and a string literal to complete the subsequent allocation. Numbers with a digit length of up to 15 are stored in a character array. When the length exceeds 15, we allocate heap space to x->long_num.ptr
for storing the larger number.
Up until now, everything seemed set up to calculate Fibonacci sequence to fib(500). However, every time I execute $make check
command, a failure message appears, followed by my Ubuntu system freezing, requiring a restart to resolve. The failure message is looks like this:
Furthermore, the terminated numbers of the Fibonacci sequence are not the same and appear to occur randomly.
At first, I intserted printk
into the function and checked the information about myBigN variables. I used $sudo dmesg | grep "xxxxx"
to filter the kernel messages. With the help of the print messages, I found that there is a condition uncovered in myBigN_init
. The error was that the large number should be assigned to x->long_num.ptr
rather than x->short_num.data
when len = 16
. The revised code is as follows:
However, the failure message persists despite the modification. This leads me to suspect other parts of my implementation. Subsequently, I spent two days addressing this issue. Ultimately, I discovered that the problem lies in memcpy(myBigN_data(x), strNum, len);
. It copies the entire string including \0
into myBigN_data(x)
, but the allocated size for x->long_num.ptr
is only len - 1. Thus, an extra byte is copied into myBigN_data(x)
, overwriting the area designated for storing the size. Below is the modification:
Now, we are able to calculate Fibonacci sequence up to fib(500). The following is the result of fib(500) in the out file, which is same as link
TODO: I should learn using other debugging tools to help me debug kernel modules.
From the description of sysprog21/bignum 程式碼分析, we can found that