[Linux] [C / C ++] Obtenez tid (id du thread) / Wrap pthread_create pour obtenir le tid du thread enfant

À des fins de débogage, il y avait un cas où je voulais savoir à partir de quel thread le pthread a été créé. Nous avons étudié comment obtenir tid et comment obtenir tid du thread enfant créé par pthread_create. Fondamentalement, on suppose que LD_PRELOAD est utilisé par la méthode suivante.

Remplacez printf plus tard par LD_PRELOAD --Qiita

utiliser gettid

Il semble que gettid ne peut être utilisé que via syscall sous Linux. Faites comme suit.

#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>

pid_t gettid(void) {
    return syscall(SYS_gettid);
}

Si vous voulez obtenir le tid d'un thread enfant de pthread (wrapping pthread_create)

Ce serait plus facile si vous pouviez obtenir la tid du thread enfant directement à partir de pthread_t, mais en gros, il semble que vous ne puissiez pas l'obtenir directement (il semble possible d'obtenir la tid par la force si vous obtenez la définition de la structure pthread de la glibc). (Non utilisé cette fois), encapsulation de pthread_create, remplacement de la cible d'appel du thread, et obtention du tid avec gettid () écrit ci-dessus.

Exemple de montage de crochet


extern "C" {
​
struct pthread_args {
	void* (*f)(void*);
	void* args;
};
​
void* thread_wrap(void* args) {
	//Tid de sortie
	printf("%s : tid => %d\n", __func__, gettid());
	//Appeler la fonction d'origine à partir de la structure enregistrée
	auto p = (struct pthread_args*)args;
	auto ret = p->f(p->args);
	delete p;
	return ret;
}
​
void* thread_excute(void* args) {
	printf("%s : tid => %d\n", __func__, gettid());
	return NULL;
}
​
// pthread_Envelopper créer
int pthread_create(pthread_t *__newthread, const pthread_attr_t *__attr,
		void *(*__start_routine) (void *), void *__arg) {
	using pthread_create_t =
		int (*)(pthread_t *, const pthread_attr_t *, void *(*) (void *), void *);
	static thread_local pthread_create_t real_pthread_create = nullptr;
	if (!real_pthread_create) {
		// create cache
		real_pthread_create
			 = reinterpret_cast<pthread_create_t>(dlsym(RTLD_NEXT, __func__));
		assert(real_pthread_create);
	}
​
	//Enregistrer le pointeur de la fonction d'origine et les arguments dans la structure une fois
	struct pthread_args* p  = new(std::nothrow) struct pthread_args();
	p->f = __start_routine;
	p->args = __arg;

	//Appelez la fonction de remplacement et passez la structure de sauvegarde comme argument
	auto ret = real_pthread_create(__newthread, __attr, &thread_wrap, (void*)p);
​
	return ret;
}

} // extern "C"

Échantillon d'exécution

tid_test.cpp


#include <stdio.h>
#include <assert.h>
#include <string.h>
​
#include <pthread.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/syscall.h>
​
#include <new>
​
// hook
extern "C" {
​
pid_t gettid(void) {
	return syscall(SYS_gettid);
}
​
struct pthread_args {
	void* (*f)(void*);
	void* args;
};
​
void* thread_wrap(void* args) {
	printf("%s : tid => %d\n", __func__, gettid());
	auto p = (struct pthread_args*)args;
	auto ret = p->f(p->args);
	delete p;
	return ret;
}
​
void* thread_excute(void* args) {
	printf("%s : tid => %d\n", __func__, gettid());
	return NULL;
}
​
int pthread_create(pthread_t *__newthread, const pthread_attr_t *__attr,
		void *(*__start_routine) (void *), void *__arg) {
	using pthread_create_t =
		int (*)(pthread_t *, const pthread_attr_t *, void *(*) (void *), void *);
	static thread_local pthread_create_t real_pthread_create = nullptr;
	if (!real_pthread_create) {
		// create cache
		real_pthread_create
			 = reinterpret_cast<pthread_create_t>(dlsym(RTLD_NEXT, __func__));
		assert(real_pthread_create);
	}
​
	Dl_info info;
	dladdr(__builtin_return_address(0), &info);
	printf("%s : __builtin_return_address => %p\n", __func__, __builtin_return_address(0));
	printf("%s : Dl_info.dli_fname => %s\n", __func__, info.dli_fname);
	printf("%s : Dl_info.dli_fbase => %p\n", __func__, info.dli_fbase);
	printf("%s : Dl_info.dli_sname => %s\n", __func__, info.dli_sname);
	printf("%s : Dl_info.dli_saddr => %p\n", __func__, info.dli_saddr);
	printf("%s : tid => %d\n", __func__, gettid());
​
	struct pthread_args* p  = new(std::nothrow) struct pthread_args();
	p->f = __start_routine;
	p->args = __arg;
​
	auto ret = real_pthread_create(__newthread, __attr, &thread_wrap, (void*)p);
​
	return ret;
}
​
}
​
// main
​
int main(int argc, char const* argv[])
{
	pthread_t thread_handler_;
​
	puts("begin : pthread_create");
	pthread_create(&thread_handler_, NULL, &thread_excute, NULL);
	puts("end   : pthread_create");
​
	pthread_join(thread_handler_, NULL);
	
	return 0;
}

Construire et produire des résultats


$ g++ -std=c++11 tid_test.cpp -ldl -pthread -rdynamic
$ ./a.out
begin : pthread_create
pthread_create : __builtin_return_address => 0x400f40
pthread_create : Dl_info.dli_fname => ./a.out
pthread_create : Dl_info.dli_fbase => 0x400000
pthread_create : Dl_info.dli_sname => main
pthread_create : Dl_info.dli_saddr => 0x400f0c
pthread_create : tid => 4303
end   : pthread_create
thread_wrap : tid => 4304
thread_excute : tid => 4304

Maintenant, nous avons le tid pour le parent et l'enfant.

Relation

Remplacez printf plus tard par LD_PRELOAD --Qiita Appelez la fonction d'origine à partir de la fonction remplacée par LD_PRELOAD --Qiita [Linux] [C / C ++] Comment obtenir la valeur d'adresse de retour d'une fonction et le nom de fonction de l'appelant --Qiita

référence

Get Thread ID-Volatile Note

Recommended Posts

[Linux] [C / C ++] Obtenez tid (id du thread) / Wrap pthread_create pour obtenir le tid du thread enfant
[Linux] [C / C ++] Résumé de la façon d'obtenir pid, ppid, tid
[Linux] [C] Obtenir le temps CPU par processus / thread
[Langage C] [Linux] Récupère la valeur de la variable d'environnement
[Linux] [C / C ++] Comment obtenir la valeur d'adresse de retour d'une fonction et le nom de fonction de l'appelant
Obtenir l'ID de thread avec python
[Linux] [C / C ++] Mémo de vérification d'opération des variables locales fork, thread et thread
[Linux] Une commande pour obtenir une liste des commandes exécutées dans le passé