// stacks.c — cada hilo tiene su propia pila; el resto se comparte.
//
// Uso: ./stacks [hilos]
// Cada hilo anota la dirección de una variable local suya. Todos esperan en
// una barrera, así están vivos a la vez (si no, la biblioteca podría reutilizar
// la misma pila). Al final, main imprime las direcciones en orden.
// Todos tienen el mismo pid (un proceso), pero cada uno su propio tid.
#define _GNU_SOURCE        // para gettid()
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define MAXT 16

static int global = 0;              // segmento de datos: uno solo por proceso
static void *local_addr[MAXT];      // dónde quedó la variable local de cada hilo
static pid_t thread_pid[MAXT];
static pid_t thread_tid[MAXT];      // id del hilo para el kernel (Linux)
static pthread_barrier_t barrier;

static void *worker(void *arg) {
    long id = (long)arg;
    int local = (int)id;            // en la pila de ESTE hilo
    local_addr[id] = &local;
    thread_pid[id] = getpid();
    thread_tid[id] = gettid();
    pthread_barrier_wait(&barrier); // nadie termina hasta que todos anotaron
    return NULL;
}

int main(int argc, char *argv[]) {
    int n = (argc > 1) ? atoi(argv[1]) : 3;
    if (n < 1 || n > MAXT)
        n = 3;
    int *heap = malloc(sizeof(int));
    int local = 0;

    printf("global       %p\n", (void *)&global);
    printf("heap         %p\n", (void *)heap);
    printf("main  local  %p   pid %d  tid %d\n", (void *)&local, getpid(), gettid());

    pthread_barrier_init(&barrier, NULL, n);
    pthread_t th[MAXT];
    for (long i = 0; i < n; i++)
        pthread_create(&th[i], NULL, worker, (void *)i);
    for (int i = 0; i < n; i++)
        pthread_join(th[i], NULL);

    for (int i = 0; i < n; i++) {
        printf("hilo %d local  %p   pid %d  tid %d", i, local_addr[i],
               thread_pid[i], thread_tid[i]);
        if (i > 0) {
            long d = labs((char *)local_addr[i - 1] - (char *)local_addr[i]);
            printf("   (a %ld KiB del hilo %d)", d / 1024, i - 1);
        }
        printf("\n");
    }
    pthread_barrier_destroy(&barrier);
    free(heap);
    return 0;
}
