Оптимизация

Как указано выше, шаг 5 может быть оптимизирован следующим образом:

Во-первых, в реальности нам не нужно тестировать строку на существование каждый раз. Единственный случай, когда строка может не существовать — это сразу после создания ключа, то есть если мы не создали ключ только что, мы знаем, что строка существует.
Во-вторых, мы всегда освобождаем и перераспределяем память для строки. Вместо этого мы бы могли проверять длину строки и, если новая строка такой же длины или короче, мы бы просто могли перезаписать строку без дополнительных расходов на вызовы free() и strdup(). Просто такая возможность не представлялась чем-то необходим на время написания, но вы можете принять ее во внимание, если ваш код модифицирует строку довольно часто — ведь вызовы free() и strdup() могут потребовать выделение дополнительной памяти от системы.
Функция tfp_init()

Просто для справки, вот как реализована функция tfp_init(), которая используется во время инициализации библиотеки:

static pthread_key_t tfp_key;

static void
tfp_key_destroy (void *value)
{
tfp_signature_block_t *tfpblk;

tfpblk = (tfp_signature_block_t *) value;
if (tfpblk -> string) {
free (tfpblk -> string);
}
free (value);
pthread_setspecific (tfp_key, NULL);
}

static void
tfp_init (void)
{
pthread_key_create (&tfp_key, &tfp_key_destroy);
}
Это стандартное поведение POSIX функции pthread_once() — tfp_init() выполняет создание ключа (который хранится в глобальной переменной tfp_key) и связывает функцию деструктора tfp_key_destroy() с потоком для того чтобы локальные данные потока освобождались при его завершении.

tfp_read_raw_block() и tfp_write_raw_block() почти идентичны по своей функциональности tfp_mark(). Вот как выглядит tfp_write_raw_block() с некоторыми комментариями:

int
tfp_write_raw_block (char *ptr, int offset, int nbytes)
{
tfp_signature_block_t *tfpblk;

// обеспечить создание ключа (только один раз)
pthread_once (&tfp_oc, tfp_init);

if (offset < 0 || (offset + nbytes) >= TFP_RAW_BLOCK_LENGTH) {
return (EINVAL);
}

if ((tfpblk = pthread_getspecific (tfp_key)) == NULL) {
tfpblk = calloc (1, sizeof (*tfpblk));
if (tfpblk == NULL) {
return (errno);
}
memcpy (tfpblk, TFP_SIGNATURE_STRING, TFP_SIGNATURE_LENGTH);
pthread_setspecific (tfp_key, tfpblk);
}

memcpy (tfpblk -> raw_block + offset, ptr, nbytes);

time (&tfpblk -> t);
return (0);
}
Как вы можете убедиться, она почти идентична по реализации tfp_mark(). Единственное различие состоит в том, что блок двоичных данных имеет фиксированный размер, так что нам не нужно распределять и освобождать при каждом вызове — мы создаем его один раз. Так же, чтобы сделать код более универсальным, мы позволяем пользователю производить запись блока данных произвольной длины начиная с любой позиции. Для этого в самом начале функции проводится проверка на лимиты и memcpy() копирует в нужное место заданное количество байт.