A dedicated kernel for multi-threading applications.

Friday, May 12, 2017

Continuous Integration in torokernel (travis)

Hi folks, this weekend I spent some time playing around Travis. This is a tool for continuous integration which is very well integrated into Github. Travis makes very easy to build and run tests after a push or before a pull request for a given branch. 
I started my experiments with a simple idea: make a test to check if a simple application in Toro Kernel is correctly executed. To do this, I choose a simple application named ToroHello.pas which just writes "Hello World" to the serial console. To check this application, I set up Travis to do two things:
1. To compile ToroHello example and generate the booting image ToroHello.img.
2. To run the image in Qemu and test if the example worked.  
I based on a previous work in https://github.com/nielsAD/travis-lazarus. So 1) was easy to do and I got a ToroHello.img compiled by using Travis very quickly (see Figure 1). 
The task 2) took me a bit more time. I set up to run qemu after the building and to output the serial port to a file. Then, I tested if the output contains 'Hello world". In such a case, the test passed. Following pictures show the output of the job:

Figure 1. Travis compiling ToroHello.pas

Figure 2. Travis running ToroHello.img in Qemu and outputting the serial
Figure 2 shows the output from the serial port. We can see Toro's initialization at line 3574.

Figure 3. Result of the building

To summarizes, in a very short time I was able to compile ToroHello and then produce a test to verify its correct behavior. This is a simple example but it allows to show how powerful might be CI for a kernel. So I am planing to use Travis in two different levels of testing. The first level is to verify the compilation of the examples after a push and/or pull request. The second level is to write specific tests to measure performance, leaks, wrong behaviors, exception faults, etc. This needs however a lot more experimentation.


Monday, May 08, 2017

Porting genext2fs to Windows 10

Last weekend I spent some time to find a tool to create ext2 images in Windows. I found a wonderful tool named genext2fs which allows to create an ext2 image and to populate it with a directory structure. I could not find a way to compile it in windows so I put hands on it and I got a windows version that seems working. You can find the patch at the end of this post. However, it is a horrible patch that only makes the thinks work. If anyone knows a better way to do it, please don't hesitate to tell me. I compiled without any problem in cygwin64. We have to be careful when we run it since, for a reason that I don't understand, the program tries to put all current directory into the image. To prevent this, I just run it from the directory that I want to put into the image. To summarize, I am now able to create a ext2 image and populate it with a directory structure. For example, I am experimenting by populating ToroFiles.img with the files that are used by the webserver in Toro. To do so, I am running the following command: 

../genext2fs.exe -v -d ../ToroFiles -b 8192 ../ToroFiles.img

This generates a 8MB image named ToroFiles.img that contains the files in the directory ToroFiles. I executed the command inside the directory ToroFiles. In the next days, I will commit the example TorowithFilesystem.pas that uses this tool to populate ToroFiles.img. Together with the example, I will upload the instruction to run it so stay tuned!

Matias Vara

This is a patch for genext2fs-1.4.1/genext2fs.c

< readsize = readlink(path, buf, bufsize); /* 1st try */
> // readsize = readlink(path, buf, bufsize); /* 1st try */
< if(st->st_mode & S_IRGRP)
> /* if(st->st_mode & S_IRGRP)
< mode |= FM_ISVTX;
> mode |= FM_ISVTX; */
< lstat(dent->d_name, &st);
> stat(dent->d_name, &st);
< case S_IFLNK:
> // case S_IFLNK:
< case S_IFSOCK:
> // case S_IFSOCK:
< if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
> if (!S_ISDIR(st.st_mode) /* && !S_ISLNK(st.st_mode) */ && st.st_nlink > 1) {
< nod = mknod_fs(fs, this_nod, name, mode|FM_IFCHR, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
> // nod = mknod_fs(fs, this_nod, name, mode|FM_IFCHR, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
< nod = mknod_fs(fs, this_nod, name, mode|FM_IFBLK, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
> // nod = mknod_fs(fs, this_nod, name, mode|FM_IFBLK, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
< case S_IFSOCK:
> /* case S_IFSOCK:
< break;
> break; */
< if((pdir = open(".", O_RDONLY)) < 0)
< perror_msg_and_die(".");
< if(chdir(dopt[i]) < 0)
< perror_msg_and_die(dopt[i]);
> //if((pdir = open(".", O_RDONLY)) < 0)
> // perror_msg_and_die(".");
> //if(chdir(dopt[i]) < 0)
> // perror_msg_and_die(dopt[i]);
< if(fchdir(pdir) < 0)
< perror_msg_and_die("fchdir");
< if(close(pdir) < 0)
< perror_msg_and_die("close");
> //if(fchdir(pdir) < 0)
> // perror_msg_and_die("fchdir");
> //if(close(pdir) < 0)
> // perror_msg_and_die("close");