..
	Copyright (c) 2011-2016 Varnish Software AS
	SPDX-License-Identifier: BSD-2-Clause
	See LICENSE file for full text of license

.. _phk_thetoolsweworkwith:

======================
The Tools We Work With
======================

"Only amateurs were limited by their tools" is an old wisdom, and
the world is littered with art and architecture that very much
proves this point.

But as amazing as the Aquaeduct of Segovia is, tools are the reason
why it looks nowhere near as fantastic as the Sydney Opera House.

Concrete has been known since antiquity, but steel-reinforced
concrete and massive numerical calculations of stress-distribution,
is the tools that makes the difference between using concrete as a
filler material between stones, and as gravity-defying curved but
perfectly safe load-bearing wall.

My tool for writing Vinyl Cache is the C-language which in many ways
is unique amongst all of the computer programming languages for
having no ambitions.

The C language was invented as a portable assembler language, it
doesn't do objects and garbage-collection, it does numbers and
pointers, just like your CPU.

Compared to the high ambitions, then as now, of new programming
languages, that was almost ridiculous unambitious.  Other people
were trying to make their programming languages provably correct,
or safe for multiprogramming and quite an effort went into using
natural languages as programming languages.

But C was written to write programs, not to research computer science
and that's exactly what made it useful and popular.

Unfortunately C fell in bad company over the years, and the reason
for this outburst is that I just browsed the latest draft from the
ISO-C standardisation working-group 14.

I won't claim that it is enough to make grown men cry, but it
certainly was enough to make me angry.

Let me give you an example of their utter silliness:

The book which defined the C language had a list of reserved
identifiers, all of them lower-case words.  The UNIX libraries
defined a lot of functions, all of them lower-case words.

When compiled, the assembler saw all of these words prefixed
with an underscore, which made it easy to mix assembler and
C code.

All the macros for the C-preprocessor on the other hand, were
UPPERCASE, making them easy to spot.

Which meant that if you mixed upper and lower case, in your
identifiers, you were safe: That wouldn't collide with anything.

First the ISO-C standards people got confused about the leading
underscore, and I'll leave you guessing as to what the current
text actually means:

	All identifiers that begin with an underscore and either
	an uppercase letter or another underscore are always reserved
	for any use.

Feel free to guess, there's more such on pdf page 200 of the draft.

Next, they broke the upper/lower rule, by adding special keywords
in mixed case, probably because they thought it looked nicer::

	_Atomic, _Bool, _Noreturn &c

Then, presumably, somebody pointed out that this looked ugly::

	void _Noreturn foo(int bar);

So they have come up with a #include file called <stdnoreturn.h>
so that instead you can write::

	#include <nostdreturn.h>
	void noreturn foo(int bar);

The <nostdreturn.h> file according to the standard shall have
exactly this content::

	#define noreturn _Noreturn

Are you crying or laughing yet ?   You should be.

Another thing brought by the new draft is an entirely new thread
API, which is incompatible with the POSIX 'pthread' API which have
been used for about 20 years now.

If they had improved on the shortcomings of the pthreads, I would
have cheered them on, because there are some very annoying mistakes
in pthreads.

But they didn't, in fact, as far as I can tell, the C1X draft's
threads are worse than the 20 years older pthreads in all relevant
aspects.

For instance, neither pthreads nor C1X-threads offer a "assert I'm
holding this mutex locked" facility.  I will posit that you cannot
successfully develop real-world threaded programs and APIs without
that, or without wasting a lot of time debugging silly mistakes.

If you look in the Vinyl Cache source code, which uses pthreads, you
will see that I have wrapped pthread mutexes in my own little
data structure, to be able to do those asserts, and to get some
usable statistics on lock-contention.

Another example where C1X did not improve on pthreads at all, was
in timed sleeps, where you say "get me this lock, but give up if
it takes longer than X time".

The way both pthreads and C1X threads do this, is you specify a UTC
wall clock time you want to sleep until.

The only problem with that is that UTC wall clock time is not
continuous when implemented on a computer, and it may not even be
monotonously increasing, since NTPD or other timesync facilities may
step the clock backwards, particularly in the first minutes after
boot.

If the practice of saying "get me this lock before 16:00Z" was
widespread, I could see the point, but I have actually never seen
that in any source code.  What I have seen are wrappers that take
the general shape of::

	int
	get_lock_timed(lock, timeout)
	{
		while (timeout > 0) {
			t0 = time();
			i = get_lock_before(lock, t + timeout));
			if (i == WASLOCKED)
				return (i);
			t1 = time();
			timeout -= (t1 - t0);
		}
		return (TIMEDOUT);
	}

Because it's not like the call is actually guaranteed to return at
16:00Z if you ask it to, you are only promised it will not return
later than that, so you have to wrap the call in a loop.

Whoever defined the select(2) and poll(2) system calls knew better
than the POSIX and ISO-C group-think:  They specified a maximum
duration for the call, because then it doesn't matter what time
it is, only how long time has transpired.

Ohh, and setting the stack-size for a new thread ?
That is apparently "too dangerous" so there is no argument in the
C1X API for doing so, a clear step backwards from pthreads.

But guess what:  Thread stacks are like T-shirts:  There is no "one
size fits all."

I have no idea what the "danger" they perceived were, my best
guess is that feared it might make the API useful ?

This single idiocy will single-handedly doom the C1X thread API
to uselessness.

Now, don't get me wrong:  There are lot of ways to improve the C
language that would make sense:  Bitmaps, defined structure packing
(think: communication protocol packets), big/little endian variables
(data sharing), sensible handling of linked lists etc.

As ugly as it is, even the printf()/scanf() format strings could
be improved, by offering a sensible plugin mechanism, which the
compiler can understand and use to issue warnings.

Heck, even a simple basic object facility would be good addition,
now that C++ have become this huge bloated monster language.

But none of that is apparently as important as <stdnoreturn.h>
and a new, crippled and therefore useless thread API.

The neat thing about the C language, and the one feature that made
it so popular, is that not even an ISO-C working group can prevent
you from implementing all these things using macros and other tricks.

But it would be better to have them in the language, so the compiler
could issue sensible warnings and programmers won't have to write
monsters like::

    #define VTAILQ_INSERT_BEFORE(listelm, elm, field) do {              \
        (elm)->field.vtqe_prev = (listelm)->field.vtqe_prev;            \
        VTAILQ_NEXT((elm), field) = (listelm);                          \
        *(listelm)->field.vtqe_prev = (elm);                            \
        (listelm)->field.vtqe_prev = &VTAILQ_NEXT((elm), field);        \
    } while (0)

To put an element on a linked list.

I could go on like this, but it would rapidly become boring for
both you and me, because the current C1X draft is 701 pages, and
it contains not a single explanatory example if how to use any of
the verbiage in practice.

Compare this with The C Programming Language, a book of 274 pages
which in addition to define the C language, taught people how to
program through well-thought-out examples.

From where I sit, ISO WG14 are destroying the C language I use and love.

Poul-Henning, 2011-12-20
