<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://homeostasis.scs.carleton.ca/wiki/index.php?action=history&amp;feed=atom&amp;title=Operating_Systems_2021F_Lecture_19</id>
	<title>Operating Systems 2021F Lecture 19 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://homeostasis.scs.carleton.ca/wiki/index.php?action=history&amp;feed=atom&amp;title=Operating_Systems_2021F_Lecture_19"/>
	<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2021F_Lecture_19&amp;action=history"/>
	<updated>2026-04-06T04:46:31Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2021F_Lecture_19&amp;diff=23533&amp;oldid=prev</id>
		<title>Soma: Created page with &quot;==Video==  Video from the lecture given on November 23, 2021 is now available: * [https://homeostasis.scs.carleton.ca/~soma/os-2021f/lectures/comp3000-2021f-lec19-20211123.m4v...&quot;</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2021F_Lecture_19&amp;diff=23533&amp;oldid=prev"/>
		<updated>2021-11-23T20:27:42Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;==Video==  Video from the lecture given on November 23, 2021 is now available: * [https://homeostasis.scs.carleton.ca/~soma/os-2021f/lectures/comp3000-2021f-lec19-20211123.m4v...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==Video==&lt;br /&gt;
&lt;br /&gt;
Video from the lecture given on November 23, 2021 is now available:&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/os-2021f/lectures/comp3000-2021f-lec19-20211123.m4v video]&lt;br /&gt;
* [https://homeostasis.scs.carleton.ca/~soma/os-2021f/lectures/comp3000-2021f-lec19-20211123.cc.vtt auto-generated captions]&lt;br /&gt;
Video is also available through Brightspace (Resources-&amp;gt;Class zoom meetings-&amp;gt;Cloud Recordings tab)&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Lecture 19&lt;br /&gt;
----------&lt;br /&gt;
 - plan for rest of term&lt;br /&gt;
 - kernel modules, T7&lt;br /&gt;
 - concurrency, T8&lt;br /&gt;
&lt;br /&gt;
Tutorial 8 is about the producer consumer problem&lt;br /&gt;
 - classic problem in concurrency (one of the simpler ones)&lt;br /&gt;
&lt;br /&gt;
When you think producer/consumer, think pipes (FIFOs)&lt;br /&gt;
&lt;br /&gt;
If we run something like&lt;br /&gt;
&lt;br /&gt;
  cat /dev/urandom | less&lt;br /&gt;
&lt;br /&gt;
Note that the cat command doesn&amp;#039;t keep running; it is paused when less&lt;br /&gt;
stops asking for input&lt;br /&gt;
  - standard out from cat is going to standard in for less,&lt;br /&gt;
    via an anonymous pipe&lt;br /&gt;
  - the left side of the pipe pauses when the right side isn&amp;#039;t actively&lt;br /&gt;
    reading (consumer pauses when producer doesn&amp;#039;t need more input)&lt;br /&gt;
  - similarly, the consumer will pause when there is no output from&lt;br /&gt;
    the producer&lt;br /&gt;
  - note there is a buffer between the producer and consumer&lt;br /&gt;
    (as part of the pipe)&lt;br /&gt;
      - so whether it is full or empty governs whether the producer&lt;br /&gt;
        or consumer is going to be paused&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Basic structure of a producer consumer problem&lt;br /&gt;
&lt;br /&gt;
                  ----------&lt;br /&gt;
  producer  &amp;lt;-&amp;gt;   | buffer |  &amp;lt;-&amp;gt;  consumer&lt;br /&gt;
                  ----------&lt;br /&gt;
&lt;br /&gt;
Buffer has many slots, think of it as a circular array&lt;br /&gt;
  - producer writes entries to buffer&lt;br /&gt;
  - consumer reads and removes entries from buffer&lt;br /&gt;
&lt;br /&gt;
Producer will sleep when buffer is full&lt;br /&gt;
  - and will wait for consumer to wake it up&lt;br /&gt;
Consumer will sleep when buffer is empty&lt;br /&gt;
  - and will wait for producer to wake it up&lt;br /&gt;
&lt;br /&gt;
Note that if producer and consumer sleep at the same time,&lt;br /&gt;
the programs deadlock and no progress will ever be made again&lt;br /&gt;
  - unless there are timeouts&lt;br /&gt;
&lt;br /&gt;
This can happen because of a failure in communication, generally due to timing&lt;br /&gt;
 - producer and consumer sleep &amp;quot;at the same time&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In above example, cat is the producer (it writes to standard out)&lt;br /&gt;
 and less is the consumer (it reads from standard in)&lt;br /&gt;
&lt;br /&gt;
But if the buffer isn&amp;#039;t full and isn&amp;#039;t empty&lt;br /&gt;
 - both producer and consumer run at the same time&lt;br /&gt;
&lt;br /&gt;
To maximize throughput, you ideally never have the producer or consumer&lt;br /&gt;
go to sleep&lt;br /&gt;
  - but not possible if they don&amp;#039;t work at the same rate&lt;br /&gt;
&lt;br /&gt;
So the buffer and the sleep/wake mechanisms ensure that progress continues to be made at the maximum rate possible&lt;br /&gt;
&lt;br /&gt;
Recall what is | doing?&lt;br /&gt;
  - a pipe system call&lt;br /&gt;
  - you get two file descriptors connected together, so writes from one become reads for the other&lt;br /&gt;
     - buffer is implemented in the kernel to coordinate reads and writes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note in 3000pc-fifo, the buffer is in the kernel&lt;br /&gt;
 - we don&amp;#039;t control it directly&lt;br /&gt;
 - so we don&amp;#039;t see its size&lt;br /&gt;
 - The only shared resource between the processes is the pipe&lt;br /&gt;
&lt;br /&gt;
But, 3000pc-rendevous* uses a shared buffer&lt;br /&gt;
 - note that this is two processes sharing a portion of memory&lt;br /&gt;
   using mmap&lt;br /&gt;
 - could get the same thing using multiple threads in one process&lt;br /&gt;
   but this is safer and should be as performant&lt;br /&gt;
&lt;br /&gt;
T8 is really an example of why multithreaded programming is no fun&lt;br /&gt;
 - and generally not worth the effort&lt;br /&gt;
&lt;br /&gt;
Note that 3000pc-rendezvous is broken&lt;br /&gt;
 - 3000pc-rendevous-timeout is the fixed version&lt;br /&gt;
&lt;br /&gt;
Specifically, 3000pc-rendezvous can deadlock&lt;br /&gt;
 - even though it seems to use semaphores correctly&lt;br /&gt;
 - but on a multicore system, it isn&amp;#039;t enough&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What is a kernel module?&lt;br /&gt;
 - inserting code into the Linux kernel&lt;br /&gt;
 - lsmod - see the modules currently loaded&lt;br /&gt;
    (where do you think it gets its info?)&lt;br /&gt;
&lt;br /&gt;
In general, monolithic kernels allow for code to be added to them&lt;br /&gt;
 - most commonly, for device drivers&lt;br /&gt;
&lt;br /&gt;
Linux kernel modules are used for device drivers, but are also&lt;br /&gt;
used for many other things (e.g., anything that might not&lt;br /&gt;
always be needed)&lt;br /&gt;
&lt;br /&gt;
Note that kernel modules run in supervisor mode on the CPU&lt;br /&gt;
 - same as all other kernel code&lt;br /&gt;
 - so, can do anything that the kernel can do&lt;br /&gt;
 - strictly more powerful than code running as root in a process&lt;br /&gt;
&lt;br /&gt;
A process with root privileges is still executing in user mode on the CPU&lt;br /&gt;
 - just when it makes system calls, the kernel will likely always&lt;br /&gt;
   say &amp;quot;yes&amp;quot;&lt;br /&gt;
 - still has to follow the system call interface, can&amp;#039;t&lt;br /&gt;
   just mess with kernel data structures&lt;br /&gt;
     - unless it decides to load a kernel module!&lt;br /&gt;
&lt;br /&gt;
Currently the Linux kernel is written in C&lt;br /&gt;
 - but some people are trying to get parts written in Rust&lt;br /&gt;
 - note that C was designed to be a portable assembler&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
userspace - code running in user mode on the CPU, processes&lt;br /&gt;
kernelspace - code running in supervisor mode on the CPU, kernel code&lt;br /&gt;
              (including modules)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you make a kernel module, note that you can&amp;#039;t include standard C library headers, only kernel headers.  Why?&lt;br /&gt;
 - kernel code can&amp;#039;t make system calls directly&lt;br /&gt;
   - it implements system calls, so can&amp;#039;t depend on them&lt;br /&gt;
   - a system call is a userspace -&amp;gt; kernel space switch,&lt;br /&gt;
     but in kernel code we&amp;#039;re already in kernel space running&lt;br /&gt;
     in supervisor mode on the CPU&lt;br /&gt;
   - kernel *can* make function calls, but it gets weird&lt;br /&gt;
     because system call code assumes it is working&lt;br /&gt;
     on behalf of a specific process&lt;br /&gt;
 - virtually all regular libraries depend on system calls&lt;br /&gt;
 - but for anything you need the Linux kernel has something&lt;br /&gt;
   equivalent (but it may have a very different interface)&lt;br /&gt;
&lt;br /&gt;
When you &amp;quot;print&amp;quot; in the kernel, there is no standard out or standard error.  So where does it go?&lt;br /&gt;
 - kernel log, can be seen in /var/log/kern.log or dmesg&lt;br /&gt;
 - messages are written using printk() or a macro that&lt;br /&gt;
   turns into printk()&lt;br /&gt;
&lt;br /&gt;
If /var/log/kern.log gets too big, you can just delete it&lt;br /&gt;
 - but you&amp;#039;ll have to reboot to get the space back&lt;br /&gt;
 - because it will still be written to, and as long as a file is&lt;br /&gt;
   open its inode refcount won&amp;#039;t be zero&lt;br /&gt;
&lt;br /&gt;
Note you&amp;#039;ll get &amp;quot;tainting&amp;quot; messages when you load the class kernel modules&lt;br /&gt;
 - this is because they aren&amp;#039;t digitally signed with an authorized key&lt;br /&gt;
 - on many desktop Linux systems, they run in &amp;quot;lockdown&amp;quot; and won&amp;#039;t&lt;br /&gt;
   allow any unauthorized modules to be loaded&lt;br /&gt;
&lt;br /&gt;
So what about eBPF-based tools?&lt;br /&gt;
 - eBPF loads code into the kernel, but much more safely&lt;br /&gt;
    - restrictions on execution&lt;br /&gt;
    - verifier checks byte code before JIT compiling bytecode&lt;br /&gt;
      and inserting it into the kernel&lt;br /&gt;
&lt;br /&gt;
There are no checks on regular kernel modules beyond code signing&lt;br /&gt;
and basic sanity checking&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s how eBPF can see so much&lt;br /&gt;
 - it is running in the kernel!&lt;br /&gt;
&lt;br /&gt;
ptrace-based programs can&amp;#039;t see so much&lt;br /&gt;
 - they are just using the ptrace system call to observe &amp;amp;&lt;br /&gt;
   manipulate one other process&lt;br /&gt;
 - this system call can mess with the observed process,&lt;br /&gt;
   hence it isn&amp;#039;t suitable for production generally&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Kernel modules can easily corrupt the kernel.  With eBPF, it is almost impossible to mess things up&lt;br /&gt;
 - eBPF isn&amp;#039;t even Turing complete (no unbounded loops)&lt;br /&gt;
&lt;br /&gt;
.bt code is for bpftrace, it generates eBPF bytecodes that are inserted into the kernel&lt;br /&gt;
 - eBPF is a machine-code like byte code&lt;br /&gt;
    - so portable across CPUs&lt;br /&gt;
 - highly restricted, but by formal verification, not a virtual machine&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Soma</name></author>
	</entry>
</feed>