Posts

CST334 week 7 (31/100)

  This week we discussed persistence and I/O. We reviewed the two types of i/o devices, block devices and stream devices. Block devices are like hard drives that have a fixed size of data that can be accessed randomly. Stream devices generate a stream of bytes that are not addressable; they come in a stream and are ephemeral. Each i/o device has its own hardware that is like a computer and has 3 registers. Status register is read to check the device state, command register to execute read, write or seek commands, and data register to actually transfer data. There are three ways to interact with devices: polling, interrupt-driven, and DMA. Polling put the cpu in a tight loop checking the status register and when the device is idle, executing a command and transferring data. It has the least latency. Interrupt driven uses less cpu because instead of a loop it puts the thread or process to sleep while waiting for the device. DMA uses special hardware to copy data from a device to a me...

CST334 week 6 (30/100)

  Josh Goldberg CST 334-40_2262 Apr 14, 2026 Journal Entry Week 6 This week we covered how to write proper sync barriers for threads to prevent a variety of locking conditions. We started by reviewing condition variables, which let a thread sleep until a signal is generated by another thread that the sleeping one should wake up. This uses pthread_cond_wait and pthread_cond_signal or pthread_cond_broadcast to wake one or all threads waiting on the CV, respectively. The Anderson-Dhalin method is a recipe to write these code patterns: 1. Design the class as usual, 2. Add locks, 3. lock/unlock around the method, 4. add CVs with names that accurately describe the condition, 5. Signal after the state changes, and 6. Add waits inside a loop. The loop is important to deal with spurious wakeups. We discussed using semaphores instead of CVs because semaphores hold a value. They are useful for different patterns with the same constructs such as locking (like with CVs), ordering and joining, a...

CST 334 week 5 (29/100)

This week we covered concurrency using multithreaded programming with the POSIX api. Concurrency solves the problems of parallelism and avoiding i/o blocking. This is important to operating systems because it allows for better sharing of the hardware resources. Threads allow for independent execution context within a process. Each thread has its own program counter, stack, and registers, but they all share the same memory space. This gives them a lower cost to create. One thing to be careful about is critical sections of code where multiple threads need to access a shared resource. We can’t allow them to operate on that resource simultaneously or else we could have a race condition where the output depends on the timing of thread execution. When a program has different output from one run to another it is called indeterminate. To avoid this we use locks to isolate the shared data such that only one thread can access it at a time - mutual exclusion. Atomic operations are operations that...

CST 334 week 4 (28/100)

  Josh Goldberg CST334 40_2262 Mar 30, 2026 This week we went deeper into paging and free space management. We reviewed the malloc() and free() library functions and how they manage memory allocation with a free list. The free list contains chunks that have a size and a pointer to the next free node in a linked list. Behind these functions are the mechanisms that satisfy the memory allocation policies. Splitting will split a chunk into two to right-size a chunk for an allocation request and keep the remainder fragment in the free chunk list. Coalescing is the inverse. It will merge adjacent free chunks to reduce small fragments. Each chunk has a header that indicates the next chunk, whether this chunk is free or not, and a magic number for integrity checks. Following the header is the actual chunk space to be allocated. When a free(ptr) is called with a pointer to space, it’s pointing at the free space. We find the header at ptr - sizeof(header_t). Allocator goals: correctness, spe...

CST 334 Week 3 (27/100)

  Josh Goldberg CST 334-40_2262 Mar 24, 2026 This week was a study on memory management. We covered address spaces, the C memory API, address translation with base & bounds, segmentation, free space management, and paging.  There are three address spaces a program cares about: code, heap, and stack. The code holds executable instructions, heap has dynamically allocated memory, and the stack has local variables and other things that are automatically generated by the compiler and used in execution. Between the heap and the stack is free space, and the two grow towards each other. To solve the problems of address generation, protection, and capacity, the OS gives virtual memory to programs. It allows for many processes to use RAM without conflict. Programs are unaware that the addresses they use are virtual. The virtualization must be fast, and virtual memory must be isolated per process.  The main API functions are malloc() and free(). malloc() makes an allocation on t...

CST 334 Week 2

  Josh Goldberg CST 334-40_2262 Mar 17, 2026 This week we learned about processes. What is a process, the difference between a process and a program, and how the OS manages processes. A process is an instantiation of a program and has a state; the program is just code and data on disk that is turned into a program when the OS starts executing the code. Last week we talked about CPU virtualization which is the gateway to this week. Each process gets to behave like it has it’s own CPU through virtualization, and the OS has time sharing mechanisms and policies by which it shares the CPU between processes. Mechanisms describe how things work, and policies describe what is acted on by the mechanisms. For example, how does the OS perform a context switch vs. how does it decide which process to switch in and out of a running state. Each process state describes the process’s address space reserved for code, heap, and stack, what is in the registers for each process, and information about a...

CST334 week 1 (25/100)

  This week was a good overview of the main purpose of operating systems: abstracting the hardware away from software, enabling concurrent program execution, and persisting data to non-volatile storage. The lectures starting working from the ground up, tying together these concepts. Computer architecture review of cpu execution and memory layout, access, and management brought us to the operating system discussion. The history of unix and linux gave an overview of what the operating system abstraction layer is that we’ll be working with. Programming in C is how we interact with the operating system and get a window into the lower level system. C abstracts away the cpu cycles and most of the memory management, but still gives us the ability to directly address and manipulate memory if we want to. The command line is a much safer way to interact with the operating system through system calls, most of which are written in C. This is the main userspace interface to the operating system...