It's fairly easy to create threads in NASM using pthreads, but setting the affinity mask is another matter. It turned out to be unnecessary to reproduce the opaque types to use in assembly language, which would be very difficult.
Instead, I compiled the C program to an object file, and linked that object file with the NASM object file to produce the final executable. The main() function in C got a different name because it's not to be compiled to an .exe, and that function name is referenced with an "extern" in the NASM program. Here's the final C code:
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
extern void * Test_fn();
int thread_create_in_C() {
int numberOfProcessors = sysconf(_SC_NPROCESSORS_ONLN);
if (numberOfProcessors >= 2){ // e.g. virtual cores
numberOfProcessors = numberOfProcessors / 2; }
printf("Number of processors: %d
", numberOfProcessors);
pthread_t threads[numberOfProcessors];
pthread_attr_t attr;
cpu_set_t cpus;
pthread_attr_init(&attr);
for (int i = 0; i < numberOfProcessors; i++) {
CPU_ZERO(&cpus);
CPU_SET(i, &cpus);
printf("Core created %d
", i);
pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
pthread_create(&threads[i], &attr, Test_fn, NULL);
}
for (int i = 0; i < numberOfProcessors; i++) {
pthread_join(threads[i], NULL);
printf("Core joined %d
", i);
}
return numberOfProcessors;
}
In the NASM code, we have an "extern thread_create_in_C" directive with the other externs, to reference the C code, and in the C code we have extern void * Test_fn(); to reference the NASM function to be called by each thread.
We call the C program at the appropriate point in the NASM program with:
call thread_create_in_C wrt ..plt
My suggestion to anyone who needs to set affinity masks for threads in assembly language is to use a C program like the one above instead of trying to replicate it in assembly. But for simple thread creation without affinity masks, the pthreads library is all you need.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…