/Teaching/Operating Systems/Tutorials/Your first Syscall

Your first Syscall

In this tutorial, we will write a simple syscall that returns the number of threads the scheduler knows of. We will walk through it from “top down”, i.e. we will start in userspace and work our way towards the scheduler.

Userspace

First, we have to decide which name to give to the libc function. We’ll settle for get_thread_countand add the following to userspace/libc/include/pthread.h

extern int get_thread_count(void);

so that the function is recognized by the compiler when it compiles a userspace program. Of course, we also need to implement the function. We will implement the function in userspace/libc/source/pthread.cas well as the following:

int get_thread_count(void) {
  return __syscall(sc_threadcount, 0x0, 0x0, 0x0, 0x0, 0x0);
}

Note that all syscalls take exactly 5 arguments, but as we don’t need any arguments, we just pass  0x0.Check the read()-syscall in read.c for an example of a syscall that takes arguments. You can place the implementation in any .c file in the libc/source folder, all files are compiled and linked to every SWEB binary.

Another small piece that’s missing is the sc_threadcount constant, which needs to be declared in common/include/kernel/syscall-definitions.h. But first, while we are already at it, we should include that header in pthread.h as well, so add these lines

#include "sys/syscall.h"
#include "../../../common/include/kernel/syscall-definitions.h"

Proceed to open common/include/kernel/syscall-definitions.h and add

#define sc_threadcount 2048

You can choose any number you want when adding a new syscall, but it is probably a good idea to group them somehow to have related syscalls together, which makes debugging easier. Also, a number of syscall constants is already defined, so check before you add one, if it’s not already there.

After that we’re done insofar, as userspace programs can now call the function get_thread_count(),which will then call into the kernel and print an error message, because the syscall is not implemented (yet). If a userspace program calls the function get_thread_count() right now, the request is handed over to the kernel and ends with an error message telling us that the kernel-side implementation is still missing. Try this to see what this error message looks like.

Kernel

The next step is to open common/source/kernel/Syscall.cpp and add a new case to the switch in Syscall::syscallException

case sc_threadcount: 
  return_value = get_thread_count(); 
  break; // you will need many debug hours if you forget the break

Of course we also need to add the get_thread_count()-method to the Syscall-class. As the file is already open, we add the following in common/source/kernel/Syscall.cpp

uint32 Syscall::get_thread_count() {
  return Scheduler::instance()->getThreadCount();
}

Before we occupy ourselves with this method of the scheduler, we’ll quickly add our method to common/include/kernel/Syscall.h as well:

static uint32 get_thread_count();

Note: This is a static method, because there isn’t really an instance of the Syscall-class. It is just used as a semantic grouping of the syscall entry points.

The final step is to make sure that the Scheduler provides the required functionality, by adding the method we’re calling above to it. First in common/include/kernel/Scheduler.h:

uint32 getThreadCount();

Make sure, that the method is declared public, so we can access it from the syscall. Finally, we’ll need to add the code for the method to common/source/kernel/Scheduler.cpp:

uint32 Scheduler::getThreadCount() {
  return threads_.size();
}

Now we are already done.

Test program

To check whether the syscall works, we’ll need some test program, though. Create a file userspace/tests/threadcount.c with the following content:

#include "stdio.h"
#include "pthread.h"

int main(int argc, char *argv[]) {
  printf("Threadcount: %d", get_thread_count());
  return 0;
}

To run your new test program, just type threadcount.sweb (i.e. the filename of your test program with .c replaced with .sweb) in the SWEB shell that is started automatically once SWEB has finished booting. Alternatively, to automatically start threadcount.sweb instead of or in additon to the shell or other test programs, change common/include/kernel/user_progs.haccordingly. Now you can test your newly created syscall. Don’t forget to run cmake . in the build folder* so that the newly added program is compiled as well. After that, just run make and make qemu and you should see something along the lines of Threadcount: 5 in SWEB.

Some final notes: The value returned by this syscall is not very interesting, but there is no problem with returning something more useful. You’ll probably also want your syscalls to do some work rather than just return some information, but once you are in the kernel, you can just execute code and do whatever you want. One small thing of note is the usage of uint32 in the above code instead of just unsigned int, which is considered more clean as you explicitly state how many bits the variable has.

Relating Chapters


* Note that cmake . is equivalent to cmake /path/to/sweb if you called cmake /path/to/sweb once before in the same directory