John Tracid
John Tracid

Reputation: 4046

Why EAGAIN in pthread_key_create happens?

Sometimes when I try to create key with pthread_key_create I'm getting EAGAIN error code. Is it possible to know exactly why?

Documentation says:

The system lacked the necessary resources to create another thread-specific data key, or the system-imposed limit on the total number of keys per process [PTHREAD_KEYS_MAX] would be exceeded.

How to check if it was a limit for keys? Maybe some king of monitor tool to check how many keys already opened in system and how many still could be used?

One important thing about our code: we use fork() and have multiple processes running. And each process could have multiple threads.

I found that we don't have independent limit for thread keys when we use fork(). Here is little example.

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

size_t create_keys(pthread_key_t *keys, size_t number_of_keys)
{
    size_t counter = 0;
    for (size_t i = 0; i < number_of_keys; i++)
    {
        int e = pthread_key_create(keys + i, NULL);
        if (e)
        {
            printf("ERROR (%d): index: %ld, pthread_key_create (%d)\n", getpid(), i, e);
            break;
        }
        counter++;
    }

    return counter;
}

int main(int argc, char const *argv[])
{
    printf("maximim number of thread keys: %ld\n", sysconf(_SC_THREAD_KEYS_MAX));

    printf("process id: %d\n", getpid());

    const size_t number_of_keys = 1024;

    pthread_key_t keys_1[number_of_keys];
    memset(keys_1, 0, number_of_keys * sizeof(pthread_key_t));

    printf("INFO (%d): number of active keys: %ld\n", getpid(), create_keys(keys_1, number_of_keys));

    pid_t p = fork();
    if (p == 0)
    {
        printf("process id: %d\n", getpid());

        pthread_key_t keys_2[number_of_keys];
        memset(keys_2, 0, number_of_keys * sizeof(pthread_key_t));

        printf("INFO (%d): number of active keys: %ld\n", getpid(), create_keys(keys_2, number_of_keys));
    }

    return 0;
}

When I run this example on Ubuntu 16.04 I see that child process can not create any new thread key if I use same number of keys as limit (1024). But if I use 512 keys for parent and child processes I can run it without error.

Upvotes: 0

Views: 837

Answers (2)

Fred
Fred

Reputation: 11

As you know, fork() traditionally works by copying the process in memory and then continuing execution from the same point within each copy as parent and child. This is what the return code of fork() indicates.

In order to perform fork(), the internals of the process must be duplicated. Memory, stack, open files, and probably thread local storage keys. Each system is different in its implementation of fork(). Some systems allow you to customise the areas of the process that get copied (see Linux clone(2) interface). However, the concept remains the same.

So, on to your example code: if you allocate 1024 keys in the parent, every child process inherits a full key table and has no spare keys to work with, resulting in the errors. If you allocate only 512 keys in the parent, then every child inherits a half-empty keys table and has 512 spare keys to play with, hence no errors arise.

Upvotes: 1

ceving
ceving

Reputation: 23824

Maximum value:

#include <unistd.h>
#include <stdio.h>

int main ()
{
  printf ("%ld\n", sysconf(_SC_THREAD_KEYS_MAX));
  return 0;
}

Consider using pthread_key_delete.

Upvotes: 0

Related Questions