5

I want to maintain a list of all running threads with some additional information about each thread. In this answer mentioned that it is possible to provide my own version of pthread_create and to link program with it. It is also important that I want to call original pthread_create in the end of my override version of it.

Could someone explain in details how it could be done and/or provide some code example?

Community
  • 1
  • 1
eupp
  • 535
  • 3
  • 13
  • 1
    Why do you need to redefine `pthread_create()`? It takes an argument precisely to pass *addition information* if you will. – Iharob Al Asimi Jan 17 '16 at 16:16
  • So create a structure for the additional information, initialize it either in the thread function or before/after calling `pthread_create`. – Some programmer dude Jan 17 '16 at 16:19
  • I want to redefine pthread_create because all additional information should be "invisible" for users of my library. I.e. user create a new thread through usual pthread_create but some additional work are performed behid the scene. Of course it is simplier to provide my own api for threads (and that is how it works by now) but then users should modify their sources and replace every pthread_* function with my api. That's something I try to avoid. – eupp Jan 17 '16 at 16:30
  • Instead of "replacing" the function at program load-time or at link-time, why not simply create a new function that you call which does all this "invisibly"? Always go with *simple* solutions if you can. You can add as many wrapper functions on top of any API as you would like, and doing it inside the actual code through simple function calls to your custom function just makes it simples. Worst case, declare a macro `pthread_create` which causes all code to call your wrapper function instead. Still simpler than a link- or load-time hack. – Some programmer dude Jan 17 '16 at 16:41
  • How to make pthread_create() to log addition info? for example, say I need to count all the threads getting created and the thread ids in a variable like a struct. – hago Mar 01 '22 at 20:38

2 Answers2

5

You can lookup the symbol for the original pthread_create-function by calling:

pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create");

The wrapper would then look like:

#include <dlfcn.h>

int (*pthread_create_orig)(pthread_t *, const pthread_attr_t *, void *(*) (void *), void *);

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg) {
       if (!pthread_create_orig)
           pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create");
       return pthread_create_orig(thread, attr, start, arg);
}

Compile this as a shared library and preload it when starting your executable.

Explanation: Usually, the first argument of dlsym() is a handle to a library opened with dlopen(). The special handle RTLD_NEXT is used to search the next occurrence of that symbol, i.e. the one which would not be linked by default. This is then the symbol in libpthread, not the one in your preloaded library.

Ctx
  • 18,090
  • 24
  • 36
  • 51
3

If you really want to replace the function you can compile your own shared library with pthread_create function, from within you can dynamically load and call original phtread_create function.

Library code pthread.c:

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

int (*original_pthread_create)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) = NULL;

void load_original_pthread_create() {
    void *handle = dlopen("libpthread-2.15.so", RTLD_LAZY);
    char *err = dlerror();
    if (err) {
        printf("%s\n", err);
    }
    original_pthread_create = dlsym(handle, "pthread_create");
    err = dlerror();
    if (err) {
        printf("%s\n", err);
    }
}
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) {
    if (original_pthread_create == NULL) {
        load_original_pthread_create();
    }
    printf("I am creating thread from my pthread_create\n");
    return original_pthread_create(thread, attr, start_routine, arg);
}

Compilation: gcc pthread.c -o libmypthread.so -shared -fpic -ldl

Usage: LD_PRELOAD=./libmypthread.so some_program_using_pthread_create

some_program_using_pthread_create should work as usual, but with each pthread_create function call it should print additional line.

Note: place correct name of your pthread library in dlopen function.

nsilent22
  • 2,763
  • 10
  • 14
  • What is the purpose of this function void load_original_pthread_create()? What is original_pthread_create? Is that a pointer to a function? – hago Mar 02 '22 at 15:39