Implementing Semaphores in Cyclone


For this project, it should be reasoanble to implement the semaphores part in Cyclone.  I've set up the kernel to include a Cyclone file called cycsem.cyc in the src/geekos directory, along with sem.h in the include/geekos directory.  You can implement your code within these files, and then call it from geekos/syscall.c.

Calling Cyclone code from C

To call a Cyclone function from C code, we must take into account that the Cyclone function might throw an exception (like an array bounds violation or a null pointer exception, as in Java). We have therefore provided two macros to simplify calling Cyclone from C. These are provided in geekos/cyclone.h. To call a Cyclone function f(es) which returns void, use the syntax void_cyc_call(f(es)). If the Cyclone function throws an exception, then void_cyc_call will return its name, as a string. Otherwise it will return NULL. For example, to call the Cyclone function foo with argument arg, we would do:
#include <geekos/cyclone.h> // for void_cyc_call
#include <geekos/screen.h> // for Print

...

char *exn = void_cyc_call(foo(arg));
if (exn)
Print("Oops! Cyclone function threw an exception %s!\n",exn);
Note that the Cyclone compiler, when compiling Cyclone code to C code (which is then compiled to assembly), it prepends every Cyclone function with the prefix Cyc_. Therefore, the void_cyc_call and cyc_call macros prepend this prefix to the function call provided.  This also means that when writing headers for Cyclone routines called by C, you need to put the Cyc_ in front of each routine declared in the header.  Look at geekos/sem.h as an example.

The cyc_call macro is similar, except that you must also provide it with a variable to store the value returned from the Cyclone function. For example, if the Cyclone function foo returns an integer, then we would call it as follows:
#include <geekos/cyclone.h> // for void_cyc_call 
#include <geekos/screen.h> // for Print

...

int ret = 0;
char *exn = cyc_call(ret,foo(arg));
if (exn)
Print("Oops! Cyclone function threw an exception %s!\n",exn);
At the conclusion of this code, if exn is NULL, then ret contains the value returned from the Cyclone code, otherwise it will contain 0.

An example of how this is used is in the Sys_P function in geekos/syscall.c, to call the P() function defined within your cycsem.cyc file.

Calling C code from Cyclone

Calling C functions from Cyclone is straightforward, and is described in the Cyclone manual.  You will need to do this to, among other things, call kthread functions from cycsem.cyc to implement semaphores.  There are two choices for creating a "conduit" to call C code from Cyclone:

Use buildlib.  This is a tool that sucks in a C header file, and based on a specification that you provide, generates a Cyclone version of the header.  This Cyclone version is then included by a Cyclone file, and calls to functions defined in that header are as if to other Cyclone functions.  We use buildlib during the build process of the Cyclone kernel.  Look at the headers placed in the include/libc/cyclone directory to see what is generated, and look at include/libc/cyclone/cyclib.cys to see the specification file.  More details about buildlib are in the manual.

Use extern "C include".  This facility allows you to declare C code within your Cyclone file, and make its functions available to be called from Cyclone code.  Note that C code can always be called directly from Cyclone code (you do not need to use macros like cyc_call).  You can see some examples in the Cyclone manual.  For this project, you'd do something like:
extern "C include" {
#include <geekos/kthread.h>
} export { fun1, fun2, ...; }
The code inside the first set of braces is regular C code, and the export statement indicates that it should be callable from Cyclone.  Note that all typedefs, struct definitions, #defines, etc. are exported by default; you do not need to put them in the export list.  In general, it may turn out that the C type in the geekos file you are including does not correspond to the Cyclone type that you need.  For example, C does not specify zero-termination or other qualifiers that Cyclone does.  There is a facility for defining Cyclone types to override the C codes, called cyclone_override, that is described in the manual.  Beware that you should not #include geekos/string.h or geekos/malloc.h, since these could result in problematic types (but your mileage may vary).  Instead, include libc/cyclone/string.h as shown in the sample cycsem.cyc file, and core.h.

Web Accessibility