This is a small library I made to help study for my Operating Systems exam. The exam involves an exercise where you either have to write code to generate a given process tree, or to draw the process tree generated by a given piece of code. When practicing for the exam, I made this library to generate pictures of the process tree, so I could check if my solutions were correct.
This library generates a DOT language description of the process tree generated by a forking program, which can be used to draw the tree using the dot
command.
A Makefile is included to generate the image automatically.
There are two functions provided:
frk
is used to fork a new process. Replace allfork
calls in your code withfrk
. Usingfork
will not generate the graph correctly.thread_create
simulates the creation of a new thread. The drawn graph will specify the number of threads created by each process, and in total. This does not actually create a new thread, it just simulates it for the purposes of the exercise (a real thread would require a function pointer to start running). It is assumed that threads are not copied when a fork is made (this is the Linux and POSIX behavior), and that the threads don't create any forks of their own.
See the existing programs in src
for examples of how to use the library.
Things to keep in mind:
- You do not need to manually
wait
for the child processes, the library will do that for you with an exit handler. - Avoid crashing the program (i.e. using
abort
, or segfaulting) as the exit handler will not be called in that case, preventing the graph from being printed correctly. Normal exit viaexit
or returning frommain
is fine. If you see a PID in the graph instead of a label (depth and thread count if not 0), it means a process crashed, preventing the label from being printed. If the root process crashes, a syntax error will occur because the closing bracket is not printed. - Do not write to stdout, as it is used for the graph. Write to stderr instead if you need to display something.
Just add your C file to the src
folder and run make
. The generated images are stored in the img
folder.
You can also manually generate an image using make out/yourprog; out/yourprog | dot -Tpng -o out/yourprog.png
, or out/yourprog | dot -Tx11
to display the graph in a window.
The library doesn't do any rendering itself, it just writes the graph to stdout in the DOT language. Run a program from out
to see this output.
The provided Makefile pipes the output to the dot
command to generate the images.
The first time you call a library function, it will initialize a few hidden global variables, including some mmap
-ed shared memory for the total process and thread count:
initialized
is a flag to check if the library has been initialized.depth
is the depth of the current process in the tree. It is incremented byfrk
.thread_nr
is the number of threads created by the current process. It is incremented bythread_create
and reset to 0 byfrk
.shared_data
is a pointer to a struct containing the total process and thread count. It is shared memory created withmmap
on initialization. The two integers in the struct areatomic_int
s to allow incrementing from multiple processes without synchronization issues.
An exit handler, registered with atexit
, prints the label of the process, including the number of threads it created
When the root process exits, it also prints the total process and thread amounts, read from the shared memory.
frk.c
is less than 100 lines of code, so you can read it to see how it works.
- Linux (other Unix-like systems may work, but are untested). If you use Windows I recommend setting up WSL. You can use Visual Studio Code to edit your code and run it in WSL using the WSL extension.
- Graphviz: Install it with
sudo apt install graphviz
on Ubuntu, or the equivalent on your distro. Graphviz provides thedot
command to generate the image. - GCC (default) or Clang: GCC is installed by default on most distros. Set
CC
to use other compilers, e.g.make CC=clang
to use Clang. Compilers other than GCC and Clang won't work with the set flags, so you'll have to setCFLAGS
manually. When settingCFLAGS
, The repo's root directory must be in the include path (-I.
does this for GCC and Clang). - GNU Make: Installed by default on most distros. You can also manually compile the code and generate the image if Make doesn't work for some reason.