Skip to content

Programs that use large amounts of thread-local storage can cause dav1d's thread creation to fail

The following program uses a large amount of thread-local storage and creates a thread with a custom stack size:

#include <pthread.h>
#include <stdio.h>

void *tile_task(void *const data) {
  printf("Calling tile_task\n");
  return NULL;
}

int main(int argc, char *argv[]) {
  static volatile __thread char x[8340480];
  (void)x;

  pthread_attr_t thread_attr;
  if (pthread_attr_init(&thread_attr)) {
    printf("Failed in pthread_attr_init!\n");
    return -1;
  }

  // Change this to something small (e.g., 1024 * 1024) to make it fail.
  int res = pthread_attr_setstacksize(&thread_attr, 8192 * 1024);
  if (res != 0) {
    printf("pthread_attr_setstacksize returns %d.\n", res);
    return -1;
  }

  pthread_t thread;
  res = pthread_create(&thread, &thread_attr, tile_task, NULL);
  if (res != 0) {
    printf("pthread_create returns %d.\n", res);
    return -1;
  }

  printf("Succeed!\n");
}

Compiling and running this (cc file.c -pthread && ./a.out) works on my x86_64 Linux system with glibc. But if you change the value passed to pthread_attr_setstacksize() to something smaller (e.g., 1024 * 1024, which dav1d currently uses), then pthread_create() will fail (with EINVAL) (note that pthread_attr_setstacksize() still succeeds).

This is an issue that was found in a real program that used some large thread-local storage, causing all of dav1d's pthread_create() calls to fail.

@gramner found the old upstream glibc issue (https://sourceware.org/bugzilla/show_bug.cgi?id=11787). This is a glibc-specific issue where glibc subtracts the thread-local storage from the stack size, rather than adding the two together. The workaround people seem to use (including Rust) is to use glibc's private __pthread_get_minstack() function to get the minimum stack size, and then add the desired stack size to that (e.g., __pthread_get_minstack(&thread_attr) + 1024 * 1024). It's probably best to use dlsym to get the function (which is also what Rust does).

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information