Introduction
When I was growing up I was sitting in front of a computer every chance I got. Not because I was programming, but because I was fascinated by what was possible with this amazing machine. I grew up as a computer user using ICQ, Winamp, and Napster.
As I got older I spent more time playing video games on the computer. At first I was into first-person shooters and eventually spent most of my time playing real-time strategy games. And then I discovered that you can play these games online! Throughout my youth I was a 'computer guy': I knew how to use computers, but I had no idea how they worked under the hood.
The reason I'm giving you my background is because I want you to know that I was not a child prodigy. I did not teach myself how to program Basic at age 7. When I took my first computer programming class I was not teaching the teacher and correcting his mistakes.
It wasn't until my second year of a University degree that I really came to love programming as an activity. Some may say that I'm a late bloomer, but I have a feeling that I'm closer to the norm than you may think.
Although I came to love programming for the sake of programming itself I still didn't have a good grasp of how the computer was working under the hood. If you had told me back then that all of my code ran inside of a process I would have looked at you sideways.
Fortunately for me I was given a great work opportunity at a local web startup. This gave me a chance to do some programming on a real production system. This changed everything for me. This gave me a reason to learn how things were working under the hood.
As I worked on this high-traffic production system I was presented with increasingly complex problems. As our traffic and resource demands increased we had to begin looking at our full stack to debug and fix outstanding issues. By just focusing on the application code we couldn't get the full picture of how the app was functioning.
We had many layers in front of the application: a firewall, load balancer, reverse proxy, and http cache. We had layers that worked alongside the application: job queue, database server, and stats collector. Every application will have a different set of components that comprise it, and this book won't teach you everything there is to know about all of it.
This book will teach you all you need to know about Unix processes, and that is guaranteed to improve your understanding of any component at work in your application.
Through debugging issues I was forced to dig deep into Ruby projects that made use of Unix programming concepts. Projects like Resque and Unicorn. These two projects were my introduction to Unix programming in Ruby.
After getting a deeper understanding of how they were working I was able to diagnose issues faster and with greater understanding, as well as debug pesky problems that didn't make sense when looking at the application code by itself.
I even started coming up with new, faster, more efficient solutions to the problems I was solving that used the techniques I was learning from these projects. Alright, enough about me. Let's go down the rabbit hole.
Primer
This section will provide background on some key concepts used in the book. It's definitely recommended that you read this before moving on to the meatier chapters.
Why Care?
The Unix programming model has existed, in some form, since 1970. It was then that Unix was famously invented at Bell Labs, along with the C programming language or framework. In the decades that have elapsed since then Unix has stood the test of time as the operating system of choice for reliability, security, and stability.
Unix programming concepts and techniques are not a fad, they're not the latest popular programming language. These techniques transcend programming languages. Whether you're programming in C, C++, Ruby, Python, JavaScript, Haskell, or [insert your favourite language here] these techniques WILL be useful.
This stuff has existed, largely unchanged, for decades. Smart programmers have been using Unix programming to solve tough problems with a multitude of programming languages for the last 40 years, and they will continue to do so for the next 40 years.
Harness the Power!
I'll warn you now, the concepts and techniques described in this book can bring you great power. With this power you can create new software, understand complex software that is already out there, even use this knowledge to advance your career to the next level.
Just remember, with great power comes great responsibility. Read on and I'll tell you everything you need to know to gain the power and avoid the pitfalls.
Overview
This book is not meant to be read as a reference manual. It's more of a walkthrough. To get the most out of it you should read it sequentially, since each chapter builds on the last. Once you're finished you can use the chapter headings to find information if you need a refresher.
This book contains many code examples. I highly recommend that you follow along with them by actually running them yourself in a Ruby interpreter. Playing with the code yourself and making tweaks will help the concepts sink in that much more.
Once you've read through the book and played with the examples I'm sure you'll be wanting to get your hands on a real world project that's a little more in depth. At that point have a look at the included Spyglass project.
Spyglass is a web server that was created specifically for inclusion with this book. It's designed to teach Unix programming concepts. It takes the concepts you learn here and shows how a real-world project would put them to use. Have a look at the last chapter in this book for a deeper introduction.
System Calls
To understand system calls first requires a quick explanation of the components of a Unix system, specifically userland vs. the kernel.
The kernel of your Unix system sits atop the hardware of your computer. It's a middleman for any interactions that need to happen with the hardware. This includes things like writing/reading from the filesystem, sending data over the network, allocating memory, or playing audio over the speakers. Given its power, programs are not allowed direct access to the kernel. Any communication is done via system calls.
The system call interface connects the kernel to userland. It defines the interactions that are allowed between your program and the computer hardware.