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:
frkis used to fork a new process. Replace allforkcalls in your code withfrk. Usingforkwill not generate the graph correctly.thread_createsimulates 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
waitfor 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 viaexitor returning frommainis 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:
initializedis a flag to check if the library has been initialized.depthis the depth of the current process in the tree. It is incremented byfrk.thread_nris the number of threads created by the current process. It is incremented bythread_createand reset to 0 byfrk.shared_datais a pointer to a struct containing the total process and thread count. It is shared memory created withmmapon initialization. The two integers in the struct areatomic_ints 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 graphvizon Ubuntu, or the equivalent on your distro. Graphviz provides thedotcommand to generate the image. - GCC (default) or Clang: GCC is installed by default on most distros. Set
CCto use other compilers, e.g.make CC=clangto use Clang. Compilers other than GCC and Clang won't work with the set flags, so you'll have to setCFLAGSmanually. 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.

