Die letzten beiden Wochen habe ich nichts gebloggt, weil ich an einem kleinen Projekt geschrieben habe, das nun endlich fertig ist: Mein Reisebericht Von Kairo nach Khartoum über die Sudan-Reise.
Der Bericht ist eine hoffentlich amüsante und interessante Zusammenstellung von Erlebnissen; ich habe mich bemüht, auch Leuten, die noch nicht in Afrika gereist sind, zu vermitteln, wie das Leben dort abläuft.
Falls ihr's lesen wollt, plant ein bisschen Zeit ein: Es sind über 150 Fotos und ca. 40 DIN A4-Seiten Text.
I'm back from Sudan! – After six weeks of travelling in the desert, mostly taking cheap sleeping options and uncomfortable local transport it is a huge relief to have these certain luxury items again: Water from the tap (which you can drink!), a hot shower, a washing machine and a nice bed.
I wrote a travel diary and will use excerpts to write up a travelog with some photos from the journey. (This will take some days, naturally.) Already I tried stitching together a panorama image of Marawi, taken in the first morning light from the top of Jebel Barkal near Karima. It's a very typical pattern which you can see anywhere along the Nile: a few hundred meters of fields, then the main village, a tarmac road – built by the Chinese, mostly – and then: hundreds of kilometers of desert.
It is shivery-cold here in Berlin; already I miss Khartoum's every-day-above-40°C weather.
I'm so excited! Tomorrow afternoon, together with a good friend of mine I'll board a plane to Cairo, Egypt. There, we'll try to acquire visas to enter Sudan. Essentially, we will travel up the river Nile from Cairo via Aswan, Wadi Halfa, and Atbara to Khartoum. If we have time, we'll also visit Port Sudan. In total, we have six weeks of time on our hands.
I hope I'm prepared well: I've been learning a bit of Arabic at university for the past two semesters; also, I've been reading the Sudan Tribune the past few months to stay up to date about the situation there. – Other than that, it's the usual stuff you should bring: insect repellent, anti-malaria tablets, water purifier, sunblocker, a good book and a (paper) notebook. Oh, and they don't have ATMs in Sudan, so it's all cash. Better hide it well. (Correction: There are no ATMs for international CCs like Master, Visa oder AmEx. For the local banks, there are quite a few.)
I had to cut down on my initial travel plans, which would have led from Cairo to Dar es Salaam (via Khartoum, Juba, Kampala), crossing five countries in total. This is not feasible any more, however, due to the high tension and violence in Southern Sudan (especially in the Abyei region). – On the upside, it'll be a rather relaxed journey now!
In Khartoum it's 36°C right now... – See you in April!
Ein Buch, das man sich wirklich nicht entgehen lassen sollte, ist
Thinking, fast and slow von Nobelpreisträger Daniel Kahneman.
Es ist sicherlich kein sehr mitreißendes Buch, aber auch nicht allzu
trocken oder komplex. Thema des Buches sind die zwei Akteure System
I und System II – die Intuition, die zwar schnell, dafür aber
ungenau arbeitet und leicht zu täuschen ist, und das, was wir
"angestrengtes Nachdenken" nennen.
Im Wesentlichen geht es darum, was für Mechnismen gewissen für uns typischen Denkmustern zugrund liegen, wie wir sie analysieren können, und was für Fehlinformationen sie uns glaubhaft machen können. Als wissenschaftliche Grundlage dienen dafür Gedankenexperimente, die großteils auch an Gruppen von Probanden getestet werden. (Jeweils gegen monetäre Entschädigung, häufig ist die Höhe der Entschädigung auch Grundlage des Experiments; wer finanziert sowas eigentlich? Und warum mache ich nie bei solchen Studien mit, wo man durch Beantworten einiger weniger Fragen ein paar Dutzend Euro erhalten kann? –)
Kahneman erklärt anhand einiger simpler kognitiver Illusionen, denen wir tagtäglich erliegen und die uns als scheinbar rationale Wesen objektiv völlig irrationale Handlungen unternehmen lassen, wie wir diese Illusionen a) erkennen können und teilweise auch b) dagegen vorgehen können.
Das Buch hat übrigens einen guten Index, so dass ich auch die äußerst passende Zusammenfassung aus dem Nachwort wiederfinden konnte:
The way to block errors that originate in System 1 [intuition] is simple in principle: recognize the signs that you are in a cognitive minefield, slow down, and ask for reinforcement from System 2 [careful thinking, as in: doing the math, considering statistics]. This is how you will proceed when you next encounder the Müller-Lyer illusion. When you see lines with fins pointing in different directions, you will recognize the situation as one in which you should not trust your impression of length. Unfortunately, this sensible procedure is least likely to be applied when it is needed most. We would all like to have a warning bell that rings loudly whenever we are about to make a serious error, but no such bell is available, and cognitive illusions are generally more difficult to recognize than perceptual illusions. (p. 417)
Im Nachwort räumt Kahneman übrigens mal eben so mit der Chicago
School
auf, die ja wesentlich auf der Illusion eines "rationalen Menschen"
aufbaut: The economists of the Chicago school do not face
that problem [whether to protect people from themselves], because
rational agents do not make mistakes. For adherents of this school,
freedom is free of charge.
(p. 412) – –
Etwas leichtere Kost war Philip Roths Nemesis. Im Sommer 1944 geht es ums Überleben: Für die einen, weil sie in den Krieg ziehen müssen, für die anderen, weil sie zu jung sind, und sich zu Hause mit einer Polioepidemie konfrontiert sehen. Auch wenn der Protagonist diesmal nicht krebskrank in der Midlife-Crisis steckt, gelingt es Roth doch leider nicht, mal einen Roman zu schreiben, in dem es nicht um Tod, Verfall und Bedauern über das eigene Leben geht. Nichts also, womit ich mich identifizieren kann. – Viel eher kam ich dagegen mit Charles Bukowskis autobiographischem Character Chinaski in Das Liebesleben der Hyäne zurecht: Ein herrliches Buch, das ich an einem Abend gelesen habe. Hoffentlich bin ich mit 50 auch noch so gut drauf!
Mal wieder zwei nicht zu Ende gelesene Bücher, die mich nicht vom Hocker gehauen haben: Thomas Pakenham: Der kauernde Löwe, eine monumentale, aber doch etwas schwerfällige Biographie der Eroberung und Kolonialisierung der Mitte des afrikanischen Kontinents (also im Wesentlichen auch die Suche nach der Quelle des Nil) – Anne Michaels: Wintergewölbe, ein Roman über den Ab- und Wiederaufbau des Abu-Simbel-Tempels. Die Abschnitte über die forcierte Umsiedlung der Nubier (und das Pendant in Kanada) ist spannend und ergreifend, aber alles pseudo-bedeutungsschwere dazwischen langweilt nach den ersten drei Seiten, leider.
Al Jazeera's documentary about the Bahrain protests, Shouting in the Dark, has received a prestigeous award. The documentary is really worth watching.
I found the insidious practices of the Bahraini prince – and the Arab league's suport – extremely unnerving.
Ich vermeide es größtenteils, über Politik zu schreiben. Das liegt im wesentlichen daran, dass es einfach sehr viele Leute gibt, deren Tagesgeschäft das ist und die folglich darin um einige Größenordnungen besser sind als ich. Außerdem ist es so, dass mich die Beschäftigung mit Politik fast ausnahmslos wütend macht: Täglicher Politik-Nachrichten-Konsum ist bestens dazu geeignet, den Glauben an Fortschritt in unserer Gesellschaft zunichte zu machen.
Aktueller Anlass ist natürlich die Einigung vierer von fünf im
Bundestag vertretenen Parteien auf Gauck als neuen
Bundespräsidenten.
Man bemüht sich dort noch nicht einmal, diesem Gauck irgendwelche
Qualitäten, die ihn als Bundespräsidenten auszeichnen würden,
zuzusprechen: Merkel sagte, mit Gauck verbinde sie vor allem die
gemeinsame Vergangenheit in der DDR. Für Gauck habe sich der Weg von
der Kirche in die Politik von fast alleine ergeben. Ihn zeichne aus,
ein "wahrer Demokratielehrer" geworden zu sein.
– Ja,
Demokratielehrer schön und gut. Aber Aufgabe des Bundespräsidenten
sollte es ja nicht sein, Demokratie zu lehren. Seine Aufgabe sollte es
vor allem auch sein, den Fokus auf Probleme im Land und im politischen
Diskurs zu lenken. Das kann man von Gauck wohl eher weniger erwarten.
Im wesentlichen scheint ein schlagendes Argument zu sein, dass sich viele Deutschen Gauck als Präsidenten wünschen. Das klingt auch vernünftig, bis man die Hintergründe recherchiert. Kaliber "Guttenberg ist so nett", sag ich nur.
Ein Pastor soll Präsident in Deutschland werden. – Pastoren: Das sind diejenigen, die professionell, das heißt um ihr täglich Brot zu verdienen, Tag für Tag, Woche für Woche Unwahrheiten predigen. Das sind diejenigen Menschen, die die evangelische Kirche repräsentieren – und somit im Grunde ihres Wesens gegen Fortschritt und Selbstverantwortlichkeit sind. (Man darf sich wohlgemerkt nicht von der Tatsache blenden lassen, dass auch Gutes aus diesen Kreisen kommt!) – – Wenn wir eines in diesem Land nicht gebrauchen können, dann einen zahnlosen, anti-sozialen, christlichen Bundespräsidenten.
Auch wenn man Fefes Ratschläge vielleicht nicht immer erst nehmen sollte: Die Nominierung Georg Schramms wäre in der Tat ein Geniestreich der Piraten – gewesen. Ich habe heute zwei Stunden lang alte TV-Mitschnitte von Schramm geschaut – die nota bene alle in öffentlich-rechtlichen Kanälen liefen, das hat mich doch positiv überrascht! – und da ist wirklich mal ein Mann, der mit der Faust auf den Tisch haut, ein Loblied auf den Zorn singt und wirklicht etwas zu sagen hat.
Update: Sag ich doch, andere können das besser. So zum Beispiel Deniz Yücel
in seinem Replik auf die Kritik
Lobos, der dessen Kolumne kritisierte:
Der Holocaust, meint er [Gauck], ist eine Ersatzreligion der Gottlosen. Damit stellt
er sich in die Tradition von Leuten, die ein Leben und Denken ohne Gott für
unvorstellbar halten und den Nationalsozialismus gerne für ein Produkt der
Gottlosigkeit halten, anstatt darin auch das in Ideologie wie Praxis
modernisierte und radikalisierte Ergebnis des christlichen Antijudaismus zu
erkennen.
I just wrote an exam for the course Technische Informatik III which was about operating systems and network communication. In the exercises throughout the semster, we had to program in C a lot. Naturally, in the exam was one task about interpreting what a C program does.
It was really simple: Listening on a UDP socket and print incoming packets
along with source address and port. The program looked somewhat like this (from
what I remember; also some things were done in a not so clever way on the exercise
sheet, and they had obfuscated the variable names to a non-descriptive
a, b, etc.):
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <error.h>
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in listen, incoming;
socklen_t incoming_len;
char buf[1024];
int len; /* of received data */
/* listen on 0.0.0.0:5000 */
listen.sin_family = AF_INET;
listen.sin_addr.s_addr = INADDR_ANY;
listen.sin_port = htons(5000);
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
perror("socket");
if(bind(sockfd, (struct sockaddr *) &listen, sizeof(listen)) == -1)
perror("bind");
while(1) {
len = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *) &incoming,
&incoming_len);
buf[len] = '\0';
printf("from %s:%d: \"%s\"\n", inet_ntoa(incoming.sin_addr),
ntohs(incoming.sin_port), buf);
}
}
I lol'd so hard when I saw this. It's a classic off-by-one error. (Can you spot it, too?)
If you want to store x bytes of data in a string, reserve x+1
bytes for the NULL termination character. Here, if you send a message
that is exactly 1024 bytes long (or longer, as it'll get truncated),
buf[len] will actually be the 1025th byte. Which might
just be anything.
And those guys want to teach network and filesystem programming – hilarious. :-D
In manchen Momenten hasse ich das Leben hier: Habe gerade eben den Zug in Dresden verpasst, und der nächste fährt erst in zwei Stunden. Der Gutschein der Deutschen Bahn, den ich vor ein paar Wochen per Post bekam und den ich nun einzulösen gedachte, ist nur für Fahrkarten gültig, deren Wert fünfzig Euro übersteigt (wohlgemerkt nach 50% BC-Rabatt) – hat man ja auch eher seltener, wenn's keine ganz große Reise ist.
Und so sitze ich am Hauptbahnhof bei frostigen Graden. Na immerhin macht es sich bezahlt, dass ich UMTS eingerichtet habe – das funktioniert nämlich.
Wäre doch bloß Sommer, dann wär's sicher ganz angenehm hier.
Last weekend I toyed around a bit and tried to write a shared object
library that can be used via LD_PRELOAD to minimize the effect a
program has on the Linux filesystem
cache.
Basically the use case is that you have a productive system running, and you don't want your backup script to fill the filesystem cache with mostly useless information at night (files that were cached should stay cached). I didn't test whether this brings measurable improvements yet.
The coding was really fun and provided me with yet another insight how the simple concept of file descriptors in UNIX is just great. (GNU software is tough, though: I got stuck once, and found help on Stackoverflow, which I had never used before.)
Gute Vortragende – seien es Dozenten, Professoren oder einfach nur Leute, die etwas referieren oder präsentieren – zeichnen sich unter anderem dadurch aus, dass sie mit den Zuhörern interagieren, an den richtigen Stellen Pausen machen und weiterführende Fragen stellen, statt monoton zu reden. Man kann dieses "Fragen stellen" aber in zweierlei Hinsicht falsch bzw. kontraproduktiv einsetzen.
Zunächst sind Suggestivfragen nur teilweise angebracht. Fragen wie "Fällt Ihnen hieran etwas auf?", die bewirken sollen, dass das Publikum die Situation kritisch unter die Lupe nimmt und eventuelle Ungereimtheiten aufspürt, sind gut. Aber rhetorisch anmutende Fragen wie "Alles verstanden?", bei denen spürbar wird, dass ein Ja erwartet wird, sind meist nicht produktiv: Die wenigsten werden sich melden, falls sie etwas nicht verstanden haben, und der Vortragende wiegt sich in falscher Sicherheit. Eine gute Alternative ist: "Gibt es Fragen bis hierher?", und eine anschließende kleine Besinnungspause.
In meinen Augen wirklich desaströs ist eine zu lose, offene, aber zugleich extrem erwartungsvolle Fragetaktik. "Wie können wir X erreichen?", ohne dass das Auditorium auch nur ansatzweise weiß, wie das Problem angegangen werden kann. Dann macht sich Verwirrung breit, und spätere Fragen, die möglicherweise sehr einfach zu beantworten sind, werden möglicherweise gar nicht oder zumindest nur sehr zögerlich beantwortet, weil das Publikum meint, die Fragestellung missverstanden zu haben, genau weil die Lösung auf der Hand liegt. – Das lähmt die Interaktion nachhaltig.
Zwei solcher Fragen, die eine kaum zu beantworten, die nachfolgende trivial, seien hier als Beispiel angeführt:
– Was haben wir nun für ein Problem bei der kanonischen Wahl der Basis des Tangentialraumes? (Gesuchte Antwort: Weil M nicht in einem umgebenden Raum betrachtet werden kann, muss TpM mit Hilfe von Äquivalenzklassen der Differentiale von Kurven, die in M durch p verlaufen, untersucht werden.)
– Welche Struktur hat TpM dann? (Gesuchte Antwort: Vektorraumstruktur.)
In letzter Zeit mache ich mehrmals pro Woche selbst Pizza. Das schmeckt nicht nur besser und ist viel billiger als Fertigpizza, es macht auch einfach Spaß und hat etwas meditatives.
Ich mache einmal die Woche Teig aus einem Würfel Hefe, ca. 700g Mehl und 0.35L Wasser – der reicht für drei große Pizzen. (Den Teig eine Stunde gehen lassen, ab dann aber im Kühlschrank abgedeckt aufbewahren!)
Lecker!
Ich habe eben versucht, meinen altes Notebook auf Ebay einzustellen.
Schließlich und endlich hat es dann auch
geklappt.
Nicht, dass das einfach war: Anscheinend kann man den Ebay Richt Text
Editor nicht mit Firefox benutzen. Zumindest ich kann das nicht.
Deswegen konnte ich keine Artikelbeschreibung einstellen.
Mangels Alternativen habe ich dann Windows XP in einer KVM gebootet,
und das Angebot mit dem Internet Explorer erstellt. Der funktioniert
aber auch nur teilweise: Das Tutorial über die neue Art und Weise, wie
eBay Geld überträgt, musste ich durch"klicken", indem ich oben in der
URL die pageNr-Parameter hochgezählt habe. Die "Weiter"-Buttons
waren leider nicht sichtbar, außer auf der letzten Seite.
Ich habe lange nicht mehr eine so inkompetent aufgebaute und unübersichtliche Seite wie eBay benutzt. Ein pures Wunder, wie das Leute tagtäglich benutzen können.
Merken die Leute nicht, dass es benutzbare und unbenutzbare Webseiten gibt? Gibt eBay kein Geld für Usability-Tester aus?! – Unbegreiflich für mich.
I'm currently shredding my old X41's hard drive, because I want to sell it (if you are interested, contact me). I'm overwriting it with zeros, ten passes:
$ shred -vfz -n 10 /dev/sda
Luckily, the disk was fully encrypted all the time. So it's just a precaution.
About ten years ago, I began using Vim. Since about eight years ago, I have been using Vim for every email, every piece of code, literally every text I write. Today, I want to write a short text about how I came to use Vim and what I like about it.
I don't really remember when I first used Vim. It must have been around the time when I was programming PHP a lot. I had access to a "real" computer at home – running Windows XP – in 2002 for the first time; before that, I could only use older Macintoshs. It's typical for first-time Vi users to stumble into believing – by hear-say, I guess – that it is indeed a really superior editor, until they try it out the first time and can't even save, because they don't know how to. That were my first experiences too, probably.
Anyhow, at some point in time I ditched PHP Zend Studio for SciTE. Later, I got to know Vim (i.e., by reading a tutorial about it and actually understanding it) and was instantly hooked. Probably, the guys over at #html.de talked me into it. Ironically, I used Vim before I ever used a UNIX-like operating system.
In my Vim learning curve, I identify seven important advances:
:echoerr a
message.
Today, I configure all programs to use Vim key bindings, especially
for horizontal and vertical navigation. It's the first thing to do.
I only use the arrow keys for Mplayer seeking.:help text-objects, if you
don't know about them.Steps 1–5 happened in the first two years. The text object only came with more recent Vim development, and I'm not quite sure when I adopted them. Learning the US layout was around 2006, maybe.
When I switched to using Debian in 2004, using Vim for all tasks already felt natural. Of course, at that point I finally came to understand Vim not merely as a text editor, but as a philosophy. And that is what fascinates me to this day: The Vi way of editing text is much more than a set of clever key bindings. It's a language.
In a way, I'm really professional at using Vim. If I think of the
tasks I do, I suspect there are very few superfluous keys I press
during editing. I have acquired a really good intuition of how to skip
to a particular line, to a particular function parameter or a certain
word in a sentence. (I use [H], [M], [L] for global on-screen
navigation a lot, and I heavily use the [f], [t], [F] and [T] jump
commands.) Just as you don't actually think about the letters you type
when you become a good typist, I don't think about what command keys I
press in Normal mode. I just press them, and the cursor magically
moves around to where my eyes rest. This is good.
On the other hand, I am just using core Vim features, most of which are already found in original Vi implementations. My really conservative .vimrc change history shows that I pretty much settled my editing habits. – But: I have never used a third-party plugin before. Strange as it may sound, I never felt the urge to do so. Command-T certainly looks like it could be of use; however, I usually start a new Vim instance and go with the Z Shell completion, which I suspect to be superior in more than one way, to find the file(s). – Thus I must acknowledge that there might be vast possibilities yet do discover. (Oh, and while confessing, there's another big one: I have never used Emacs. All I know about it is hear-say.)
For keyboard enthusiasts, there are two quirks with Vim: It mainly
relies on Escape for mode switches, and the keys for many
combinations are aligned for QWERTY layouts. There's just no way
around it: while [c] and [d] are mnemonic for cut and delete, [h],
[j], [k], [l] simply aren't. There's no way justify their use when
switching to Dvorak, and that's why I didn't (switch). I also once
tried mapping [j][j] to Escape, or using the Caps Lock key as Escape
replacement; I can't really stick to using it. (I also stick to
calling vim on the command line instead of a shorter alias. It is
the fourth most command I type, after sudo, git, and man.)
For me, text editing is equal to using Vim. I feel like a four-year old moving a mouse when I'm forced to use another editor on other people's computers. And because text editing is really clumsy with regular text editors, I no longer wonder why people don't really bother to correct errors: the effort is just not worth it.
If I had to sum up the difference between Vim and other editors in one sentence, it is this: While other editors are great for creating text, Vim is also great at manipulating text. And text manipulation, for most programmers and authors, is what it's all about.
:wq
Gerade mal zweistellige View-Zahlen? Das wundert mich. – Ich embedde das mal direkt, vielleicht hilft das...
Was so liegen geblieben ist:
Bei mir läuft die Königsmische auf Repeat.
I've had weird race conditions when using vlock together with s2ram. It
appears suspend to ram wants to switch
VTs, while
vlock hooks into the switch requests and explicitly disables them. So some of
the time, the machine would not suspend, while at other times, vlock wouldn't
be able to acquire the VT.
To solve this, I wrote a simple vlock plugin, which simply clears the lock
mechanism, writes mem to /sys/power/state and later reinstates the locking
mechanism. This plugin is called after all and new. Thus, the screen will
be locked properly before suspending.
Here's my suspend.c:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* Include this header file to make sure the types of the dependencies
* and hooks are correct. */
#include "vlock_plugin.h"
#include "../src/console_switch.h"
const char *succeeds[] = { "all", "new", NULL };
const char *depends[] = { "all", "new", NULL };
bool vlock_start(void __attribute__ ((__unused__)) **ctx_ptr)
{
int fd;
unlock_console_switch();
if((fd = open("/sys/power/state", O_WRONLY)) != -1) {
if(write(fd, "mem", 3) == -1)
perror("suspend: write");
close(fd);
}
lock_console_switch();
return true;
}
Simply paste it to the vlock modules folder, make suspend.so and copy it to
/usr/lib/vlock/modules. I now invoke it like this:
env VLOCK_PLUGINS="all new suspend" vlock
Are you fucking kidding me? You reintroduce broken behaviour that possibly has devastating security consequences and and make it the default?! Yeah I agree the "usual" X server locking approach is not the best way to do it – but to knowingly smash the security of people's computers on a grand scale... that's priceless.
(My locking solution is env USER=feh vlock -a -n, again.)
Update: Why it happened
Today I wrote a rather cool Z-Shell completion function: It will
present all words that are found in the current tmux pane in a zsh
completion menu. That means you can actually complete words from the
output of commands that you just executed. (In a way it's a little
bit like the keeper
function,
without the overhead of remembering to call keeper in the first place.)
The code below defines two keybindings:
176.9.247.89
somewhere in the pane, try typing .9 and hitting Ctrl-X twice.
It'll complete to that IP address.Here's the code:
_tmux_pane_words() {
local expl
local -a w
if [[ -z "$TMUX_PANE" ]]; then
_message "not running inside tmux!"
return 1
fi
w=( ${(u)=$(tmux capture-pane \; show-buffer \; delete-buffer)} )
_wanted values expl 'words from current tmux pane' compadd -a w
}
zle -C tmux-pane-words-prefix complete-word _generic
zle -C tmux-pane-words-anywhere complete-word _generic
bindkey '^Xt' tmux-pane-words-prefix
bindkey '^X^X' tmux-pane-words-anywhere
zstyle ':completion:tmux-pane-words-(prefix|anywhere):*' completer _tmux_pane_words
zstyle ':completion:tmux-pane-words-(prefix|anywhere):*' ignore-line current
zstyle ':completion:tmux-pane-words-anywhere:*' matcher-list 'b:=* m:{A-Za-z}={a-zA-Z}'
How does it work? _tmux_pane_words will just capture the current
pane's contents (capture-pane), print out the buffer that
contains it (show-buffer) and then delete it again
(delete-buffer). – The rest of the magic happens via Zsh's
excellent completion mechanisms.
See it in action (after typing spm^X^X):

Today I played around with POSIX threads a little. In an assignment, we have to implement a very, very simple webserver that does asynchronous I/O. Since it should perform well, I thought I'd not only serialize I/O, but also parallelize it.
So there's a boss that just accepts new inbound connections and appends the fds to a queue:
clientfd = accept(sockfd, (struct sockaddr *) &client, &client_len);
if(clientfd == -1)
error("accept");
new_request(clientfd);
The new_request function in turn appends it to a queue (of size
TODOS = 64), and emits a cond_new signal for possibly waiting
workers:
pthread_mutex_lock(&mutex);
while((todo_end + 1) % TODOS == todo_begin) {
fprintf(stderr, "[master] Queue is completely filled; waiting\n");
pthread_cond_wait(&cond_ready, &mutex);
}
fprintf(stderr, "[master] adding socket %d at position %d (begin=%d)\n",
clientfd, todo_end, todo_begin);
todo[todo_end] = clientfd;
todo_end = (todo_end + 1) % TODOS;
pthread_cond_signal(&cond_new);
pthread_mutex_unlock(&mutex);
The workers (there being 8) will just emit a cond_ready, possibly
wait until a cond_new is signalled, and then extract the first
client fd from the queue. After that, a simple function involving some
reads and writes will handle the communication on that fd.
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond_ready);
while(todo_end == todo_begin)
pthread_cond_wait(&cond_new, &mutex);
clientfd = todo[todo_begin];
todo_begin = (todo_begin + 1) % TODOS;
pthread_mutex_unlock(&mutex);
// handle communication on clientfd
(Full source is here: webserver.c.)
Now this works pretty well and is fairly easy. I'm not very experienced with threads, though, and run into problems when I do massive parallel requests.
If I run ab, the Apache Benchmark tool with 10,000 requests, 1,000
concurrent, on the webserver it'll go up to 9000-something requests and
then lock up.
$ ab -n 10000 -c 1000 http://localhost:8080/index.html
...
Completed 8000 requests
Completed 9000 requests
apr_poll: The timeout specified has expired (70007)
Total of 9808 requests completed
The webserver is blocked; its last line of output reads like this:
[master] Queue is completely filled; waiting
If I attach strace while in this blocking state, I get this:
$ strace -fp `pidof ./webserver`
Process 21090 attached with 9 threads - interrupt to quit
[pid 21099] recvfrom(32, <unfinished ...>
[pid 21098] recvfrom(23, <unfinished ...>
[pid 21097] recvfrom(31, <unfinished ...>
[pid 21095] recvfrom(35, <unfinished ...>
[pid 21094] recvfrom(34, <unfinished ...>
[pid 21093] recvfrom(33, <unfinished ...>
[pid 21092] recvfrom(26, <unfinished ...>
[pid 21091] recvfrom(24, <unfinished ...>
[pid 21090] futex(0x6024e4, FUTEX_WAIT_PRIVATE, 55883, NULL
So the children seem to be starving on unfinished recv calls, while
the master thread waits for any children to work away the queue. (With
a queue size of 1024 and 200 workers I couldn't reproduce the
situation.)
How can one counteract this? Specify a timeout? Spawn workers on
demand? Set the listen() backlog argument to a low value? – or
is it all Apache Benchmark's fault? *confused*
Ich habe unter der Woche Bernd Ulrichs Streitschrift Wofür Deutschland Krieg
führen darf. Und muss. vom Oktober 2011 gelesen. Das Buch war für mich unter
mehreren Aspekten interessant. Einerseits beleuchtet es die
Hintergründe der Kriege, die ich damals als Kind noch nicht
mitbekommen habe – den Namen UÇK kannte ich zwar aus den
Nachrichten, wusste aber damit nichts zu verbinden – und
bietet so eine gute Perspektive auf die jüngere Deutsche Geschichte,
gerade auch in Hinblick auf die Auswirkungen der Wiedervereinigung auf
die geopolitische Sicherheitslage Europas und der Welt, sowie das
politische Selbstbewusstsein Deutschlands. Andererseits meldet sich
hier aus der Generation meiner Eltern ein Kriegsdienstverweigerer und
ehemaliger Mitarbeiter des Fraktionsvorstandes der Grünen im Deutschen
Bundestag zu Wort, der mittlerweile stellvertretender Chefredaktuer
und Leiter des Politik-Ressorts der Zeit ist.
Das ganze ist flüssig zu lesen, aber natürlich kontrovers – und das soll es ja auch sein. Zunächst muss gesagt werden, dass das Buch eine Reihe interessanter Einsichten enthält, die auch sehr treffend ausformuliert sind. Über die Tatsache, dass sich in der deutschen Bevölkerung nur sehr schwierig eine stabile Mehrheit für einen Einsatz der Bundeswehr finden lässt, bemerkt er ganz richtig (S. 53):
Hinzu kommt ein ganz profaner Umstand. In Deutschland finden unablässig irgendwelche Wahlen statt, weshalb eine kriegführende Bundesregierung einem andauernden Plebiszit ausgesetzt ist, das sie nur überstehen kann, solange andere als die militärischen Fragen wahlentscheidend sind.
Und weiter:
Die Regierung wird infolgedessen dazu tendieren, die Fragen von Krieg und Frieden möglichst nicht zu thematisieren, ja, ihre Thematisierung aktiv zu verhindern.
Eine weitere interessante Beobachtung stellt Ulrich über die "spezielle Verbindung" zwischen Deutschland und Israel an (S. 73):
In der wachsenden Distanz zu Israel und in die zunehmende Skepsis gegen Militäreinsätze hinein bringt nun die Merkel-Doktrin Deutschland näher an einen Militäreinsatz für Israel. Hier liegt eine enorme latente Spannung.
Schaut man auf das Inhaltsverzeichnis, so kann man das Buch in einige wesentliche Thesen zusammenfassen:
Meine Generation, also die zur Zeit des Niedergangs der DDR oder nach dem Mauerfall Geborenen, sind in meinen Augen sehr pazifistisch eingestellt, und das ist gut so. Rundheraus würde ich sagen: Krieg ist immer falsch.
Leider stimmt das nicht. Ja, wenn man an all die Kriege denkt, die Amerika so geführt hat im Südosten Asiens, oder wie die Kriege in Afghanistan und dem Irak laufen: das ist abgrundtief falsch. – Andererseits muss man sich immer wieder den Ruandischen Genozid vor Augen halten, und die damalige Passivität der UN. Dadurch, dass westliche Mächte nicht eingegriffen haben, obwohl sie ziemlich gut wussten, dass ein riesiger Völkermord passierte, das ist unverantwortlich. – Wenn man sagt "Krieg ist in keinem Fall tragbar", dann öffnet man dem Kulturrelativismus Tür und Tor. Profan ausgedrückt, sagt man: "Lass die Anderen doch mit sich selbst klarkommen. Wenn sie sich abschlachten, dann ist das nicht mein Problem, und nicht einmal notwendigerweise falsch." – eine solche Einstellung ist sehr, sehr gefährlich. Von daher ist für den Pazifisten die Fragestellung, ob es überhaupt legitime Kriege gibt, eine sehr viel schwierigere, als sie auf den ersten Blick scheint.
Im Nachhinein kann man möglicherweise sagen, dass der Einsatz der Bundeswehr als Teil des NATO-Bündnisses in Libyen gerechtfertigt gewesen wäre. Der Einsatz ist mittlerweile beendet, und der Aufbau des Landes kann beginnen. Wenn ein Präsident die Luftwaffe gegen das eigene Volk einsetzt, dann sollte es schwer sein, wegzuschauen. – Natürlich muss man sich überlegen, wer denn die Machtposition Gaddafis über Jahrzehnte gefestigt hat. Aber man kann und darf die Frage nach militärischer Intervention nicht mit einer antiimperialistischen Floskel à la "hätten wir nicht X gemacht ... wäre nicht Y passiert" abtun. Dort sterben Leute.
Ich tue mich auch schwer in der Frage, zumal ich von einer anderen Prämisse ausgehe, was die Situation zugegebenermaßen leichter macht: Ich empfinde nichts für das Staatenkonstrukt Deutschland. Deutsche Kultur, insbesondere die deutsche Sprache und Literatur, sowie klassische Musik bedeutet mir etwas – das geht aber über Staatengrenzen hinaus. Der Großteil von Deutschland – das heißt, alles außerhalb von Hamburg und Berlin – bedeutet mir nichts, ganz einfach nichts. Ich habe da schließlich nie gelebt. Aber ohne die Grundlage von konstruierten Staaten, die gemeinsam agieren, entfällt natürlich die Notwendigkeit zur Verantwortung gegenüber anderen Staaten – es bleibt die Verantwortung von Menschen gegenüber anderen Menschen, und dort sind die Menschenrechte ein ziemlich allgemein akzeptierter Konsens.
Zusammenfassend lässt sich sagen, dass das Buch einige spannende Einsichten, auch in das Wirken von Presse und Politik, bereit hält. Und es ist beeindruckend zu sehen, wie ein ehemaliger überzeugter pazifistischer Aktivist heute Kriege zu legitimieren versucht.
It is generally accepted as an almost universal truth that mutt sucks, but is the MUA that sucks less than all others. While people use either Vim or Emacs and fight about it, I hardly see any people fight about whether mutt is good or bad. There is, to my knowledge, no alternative worth mentioning.
Mutt dates back well into the mid-nineties. As you might imagine, with lots of contributors over the course of almost two decades, the code quality is rather messy.
When development had stalled for quite a while in the mid-2000's, a fork was attempted. While mutt-ng was quite popular for a while, most changes were incorporated back into mainline mutt at some point. (Ironically, the latest article in the mutt-ng development blog is from October 2006 and is titled "mutt-ng isn't dead!"). The development of main mutt gained some momentum again, triggered in large parts by the contributions of late Rocco Rutte.
I remember two big features that the original mutt authors just wouldn't integrate into mainline: The headercache patch and the sidebar patch. About the former I can't say anything, but lately I've been fixing the Sidebar patch in various places. (We use mutt at work and rely heavily on e-mail communication, so we'd like a bug-free user agent, naturally.)
When all the mutt forking went about five years ago, I didn't know much about it. Retrospectively, I see the people did a hell of a job. Long before mutt-ng was forked, Sven told me he and Mika met in Graz for several weeks to sift and sort through the availbale patches, intending to do a "super patch".
Mutt's code quality is arguably rather messy.
On top of that, the Sidebar patch tries to make it even worse. Imagine this: mutt draws a mail from position (line=x,char=0) to the end of the line. Now the sidebar patch will introduce a left "margin", such that the sidebar can be drawn there. Thus, all code parts where a line is started from the leftmost character has to be rewritten to check if the sidebar is active and possibly start drawing at (line=x,char=20).
The sidebar code quality is a fringe case of bad code. Really, it sucks. However, there's no real way to "do it right", since original mutt never planned for a sidebar.
Who maintains the sidebar patch? – Not sure. There's a version at thomer.com, but he says:
July 20, 2006 I quit. Sadly, there seems to be no desire to absorb the sidebar patch into the main source tree.
The most up-to-date version is found at Lunar Linux. Last update is from mid-2009.
Debian offers a mutt-patched
package that includes the
sidebar patch, albeit in a different version than usually found 'round
the net. In short, this patch is a mess, too.
But since I made all the fixes, I decided to contact the package's maintainer, Antonio Radici. He promptly responded and said he'd happily fix all the issues, so I started by opening two bug reports. Nothing has happened since.
The patches run quite stable for my colleagues, so I think it's best to release them. Maybe someone else can use them. Please note that I have absolutely no interest in taking over any Sidebar patch maintainance. ;-)
For some of the patches I provide annotations. They all feature quite descriptive commit messages, and apply cleanly on top of the Debian mutt repository's master branch.
The first four patches are not by me, they are just the corresponding
patches from the debian/patches/ directory applied to have a
starting point.
The first few patches fix rather trivial bugs.
Now come the performance critical patches. They are the real reason I was assigned the task to repair the sidebar:
This patch fixes a huge speed penalty. Previously, the sidebar would count the mails (and thus read through the whole mbox) every time that mtime > atime! This is just an incredible oversight by the developer and must have burned hundreds of millions of CPU cycles.
This introduces a member `sb_last_checked' to the BUFFY struct. It
will be set by `mh_buffy_update', `buffy_maildir_update' and
`buffy_mbox_update' when they count all the mails.
Mboxes only: `buffy_mbox_update' will not be run unless the
condition "sb_last_checked > mtime of the file" holds. This solves
a huge performance penalty you obtain with big mailboxes. The
`mx_open_mailbox' call with the M_PEEK flag will *reset* mtime and
atime to the values from before. Thus, you cannot rely on "mtime >
atime" to check whether or not to count new mail.
Also, don't count mail if the sidebar is not active:
Then, I removed a lot of cruft and simply stupid design. Just consider one of the functions I removed:
-static int quick_log10(int n)
-{
- char string[32];
- sprintf(string, "%d", n);
- return strlen(string);
-}
That is just insane.
Now, customizing the sidebar format is simple, straight-forward and mutt-like:
sidebar_format
Format string for the sidebar. The sequences `%N', `%F' and
`%S' will be replaced by the number of new or flagged messages
or the total size of the mailbox. `%B' will be replaced with
the name of the mailbox. The `%!' sequence will be expanded to
`!' if there is one flagged message; to `!!' if there are two
flagged messages; and to `n!' for n flagged messages, n>2.
While investigating mutt's performance, one thing struck me: To decode a mail (eg. from Base64), mutt will create a temporary file and print the contents into it, later reading them back. This also happens for evaluating filters that determine coloring. For example,
color index black green '~b Julius'
will highlight mail containg my name in the body in bright green (this is tremendously useful). However, for displaying a message in the index, it will be decoded to a temporary file and later read back. This is just insane, and clearly a sign that the mutt authors wouldn't bother with dynamic memory allocation.
By chance I found a glib-only function fmemopen(),
"fmemopen, open_memstream, open_wmemstream - open memory as stream".
From the commit message:
When searching the header or body for strings and the
`thorough_search' option is set, a temp file was created, parsed,
and then unlinked again. This is now done in memory using glibc's
open_memstream() and fmemopen() if they are available.
This makes mutt respond much more rapidly.
Finally, there are some patches that fix various other issues, see commit message for details.
There you go. I appreciate any comments or further improvements.
Update 1: The original author contacted me. He told me he's written most of the code in a single sitting late at night. ;-)
Update 2: The 16th patch will make mutt crash when you compile it with -D_FORTIFY_SOURCE=2. There's a fix:
0020-use-PATH_MAX-instead-of-_POSIX_PATH_MAX-when-realpat.patch (thanks, Jakob!)