When learning a new programming language, I either write something I've written multiple times, or dive-in head first into some random project for a drive-by contribution. Historically, I've written web servers, as that usually exercises things I care about in a language (string processing, I/O, concurrency, memory management, etc); having spent over a decade working on Lwan, I'm kind of tired of writing web servers – so I decided to look into programming languages, specifically, their runt...| L. Pereira
C lacks the concept of constructors, making it hard to define global variables that are semi-constants in a foolproof way. Here's a trick I'm now using in Lwan, that might be useful for those wanting semi-constants that are initialized exactly once, or that are thread-local variables that require some kind of initialization.| L. Pereira
Defining things in different sections in a binary is really useful – and used by quite a few projects, from operating system kernels to web servers, like Lwan. Lwan makes extensive use of this:| L. Pereira
Many years ago, I helped a friend with her capstone project. She wanted to design the clothes used by dancers, in a performance similar to the The Wrecking Crew Orchestra, a Japanese group that performs in pitch-black theaters, with eletro-luminescent wire sewed into their suits; this EL wire is controlled with precision, according to the music. It's a spectacle light no other and she really wanted something like that.| L. Pereira
Here's a fun trick: implementing a Blurhash-like thing for galleries, without requiring JS, just plain CSS.| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
Some people over the years told me they were interested in knowing how asynchronous I/O works in Lwan. I've already written a bit how asynchronous I/O works with HTTP clients, but this was a long time ago and a refresher might be useful, as new features have been added. Of note, connection handlers can now sleep, or await for another file descriptor, allowing proxies and other async patterns to be implemented in Lwan.| L. Pereira
The other day I saw this toot by Stargirl, and it caught my eye:| L. Pereira
Before C and C++ standardized attributes for functions, pretty much any industrial-strength compiler would implement some sort of mechanism. GCC (and, to offer compatibility, Clang) are no exceptions.| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
After reading Daniel Stenberg's post on case-insensitive string comparison in cURL, I decided to take a stab at implementing something like this in Lwan for the same reasons. (Lwan used to use strcasecmp() before using the one described in this blog post.)| L. Pereira
It's been a while since I've blogged about the JSON library optimization work I did for Lwan's entry in the TechEmpower Web Framework Benchmarks. I've been taking a break from a lot of my personal projects, so the work to generate machine code from the JSON descriptors to serialize data has been put on hold indefinitely. However, there's one thing that I'd like to share, that might be useful for other people.| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
Out of the many benefits of HTTP/2 is its ability to not waste bandwidth with headers when compared to HTTP/1.1. This is achieved by doing three things:| L. Pereira
One of the long standing tasks in Lwan is to implement HTTP/2. I've been postponing it since before it was fully standardized, and followed a lot of public discussions that turned SPDY into HTTP/2. I had a few false starts, but never really started the work. One of the first obstacles wasn't even HTTP/2 itself -- which requires substantially more commitment than HTTP/1.1 for a proof-of-concept implementation -- but that most HTTP/2 clients require an encrypted connection, and Lwan never suppo...| L. Pereira
A few weekends ago, I decided to break my hiatus of recreational programming and play a bit with Serenity OS. What I decided to play with was the SoundPlayer application, to avoid working on the kind of stuff that I'm usually drawn to – and learn a few things in the process.| L. Pereira
| L. Pereira
| L. Pereira
A common pattern you see in programs are predicates such as is_action_allowed(), or should_perform_action(), taking a constant value, often from an enumerated type, and returning a boolean value. A straightforward way to implement such predicates is to write a function like so:| L. Pereira
A while back I opened an online form so that people could ask me anonymous questions, and posted it on Twitter. Then I forgot about it – until today, when I was cleaning up my online docs, and saw quite a few questions there, waiting to be answered. Oops!| L. Pereira
| L. Pereira
| L. Pereira
Right after the BUILD conference, Microsoft released the source code for the first version of GW-BASIC for the MS-DOS under the MIT license. Not only this is an improved version of the very first product that kickstarted the company, it's also the base for my first programming language, the MSX BASIC.| L. Pereira
| L. Pereira
A few years back, I wrote a tiny JSON library for the Zephyr OS; it focused mostly in things that are important for an embedded real-time operating system: code size, type-safety, and predictability (both for memory and CPU time usage). It was never tuned to ace performance benchmarks: the other constraints were far more important driver for its design decisions.| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
Around five years ago, I wrote a blog post that went though the life-cycle of a HTTP request, as seen by my toy web server, Lwan. It was a surprisingly popular article, not only raising visibility for my toy project, but also generating some discussions on link aggregator web sites and personal emails. (You can read the blog post if you haven’t already or need some refreshing.)| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
One of the decisions I took early on while writing Lwan was to only support Linux, and think about portability later; this decision was influenced by the way the OpenBSD project approaches portability.| L. Pereira
| L. Pereira
| L. Pereira
Talking about uncommon programming tricks the other day, the subject of switching on strings in C appeared on the table.| L. Pereira
| L. Pereira
My laptop is a 6-year old ThinkPad X220. Although it's almost falling apart from years of constant abuse, I don't see myself replacing it anytime soon: it's easy to repair, has a great keyboard, and is a very dependable machine.| L. Pereira
There are many libraries out there to parse JSON files. It might be a futile attempt, then, to write yet another one. However, when you're working on a RTOS where memory is golden, and the alternatives don't look that great, you got to do something about it.| L. Pereira
I’m not one to jump on each and every bandwagon I see. Sometimes that’s a good decision, sometimes it’s better to just wait and see where they go before taking any action.| L. Pereira
A pretty common mistake that happens when programming things in C is to allocate less memory than necessary to hold a structure:| L. Pereira
I've been thinking for a while on how to reduce the overhead in Lwan's string buffer, when the strings are small. There are a number of ways of accomplishing this.| L. Pereira
When learning a new programming language, I tend to write two things with it: a language interpreter (usually a FORTH-like language or Brainfuck if I'm feeling lazy), and a HTTP server. Sometimes, just as a challenge or a way to quench my boredom, I do this even though I've been working with a particular language for some time, as is the case with C.| L. Pereira
There are various ways to convert integers to their string representation. These conversions are rarely a bottleneck, but they often show up while profiling certain applications. For instance, they're very common in Lwan while building the response headers.| L. Pereira
One of the things that bothers me when I'm writing software is that I never get things right the first time. It takes me quite a few iterations to achieve a good result -- be it performance, memory usage, or a good architecture. Getting things to a "good enough" state is also very frequent as projects need to move forward; however, written code often ends up in sort of a low priority refactoring thread inside my head. Sometimes this thread is able to produce a thing or two, and I'm able to re...| L. Pereira
When I wrote about lwan's templating engine on a blog post last year, I purposedly ommitted the fact that it didn't support sequences. Took me almost a year, but I've finally implemented it this week. (Lwan is usually a low priority weekend project. Maybe that should do as an excuse for my laziness.)| L. Pereira
There are some functions in the standard C library that takes a function pointer to be used as a callback later on. Examples include atexit() and signal(). However, these functions can't receive an arbitrary pointer (which could hold some important program state) in addition to the function pointer, so you're left with pesky global variables:| L. Pereira
Generating textual output is a lot easier with templates than it is with handcrafted functions. And it is a lot easier in languages such as Python, where things like introspection are easy and cheap. But that doesn’t necessarily mean we can’t do that in C if we know where to look.| L. Pereira
I’ve attended this year’s FISL, both as a booth attendee (at ProFUSION’s booth, demonstrating a few of our end-user-visible projects), and as a speaker for my old FINF project.| L. Pereira
Previously, I’ve improved file serving performance in lwan by dramatially cutting down on the number of system calls performed to serve a file. However, for small files (< 16KiB), the throughput drop from the hello handler (which merely responds “Hello, World!”) was significant, since lwan was still performing system calls to open, obtain the size, and close the file.| L. Pereira
Writing asynchronous I/O code in C is kind of tedious, and often leads to a callback hell. But it doesn’t have to be this way; if you have a main loop, it’s quite simple to use coroutines and write code in a soothing, old school, synchronous way.| L. Pereira
I’ve been working at ProFUSION on a project called EasyUI for the past few months. This library is based on Google’s V8 JavaScript engine and the Enlightenment Foundation Libraries and aims to diminish the hurdle in writing native applications for the forthcoming Tizen platform.| L. Pereira
When I first wrote lwan, file serving was not a primary goal. I’ve added this capability later, never giving much thought to the number of system calls required to serve one file. As a result, static file serving was quite slow compared to “hello world” requests. Bored one day, I’ve decided to speed this as much as I could.| L. Pereira
Golang has a lot of nice features – and one I found pretty interesting is called deferred statements. This can be implemented in C++ pretty easily through RAII, but in C we’re pretty much out of luck. Or are we?| L. Pereira
Tries are very useful data structures if you need to perform longest subprefix matching. Unfortunately, simple implementations uses a lot of memory, which is often solved by collapsing common prefixes in a single node (like a Radix tree). However, this adds to the implementation complexity, which is something I like to avoid.| L. Pereira
C’s switch statement is very powerful. However, it can’t be used with strings, only with constant integral types. This is understandable, since strings in C are merely arrays – they’re not first-class citizens.| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
| L. Pereira
This picture is Copyright © 2007 L. Pereira. Please do not use this photo without permission.| tia.mat.br