// args.c — pasar argumentos a un hilo y recibir su resultado.
//
// Uso: ./args <N> <hilos>
// Suma 1 + 2 + ... + N repartiendo el rango entre los hilos. Cada hilo
// recibe un struct con su rango y devuelve un struct (en el heap) con su suma.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int  id;
    long from, to;      // rango [from, to] que suma este hilo
} task_t;

typedef struct {
    long sum;
} result_t;

static void *sum_range(void *arg) {
    task_t *t = arg;                    // void * -> puntero al tipo real
    result_t *r = malloc(sizeof(*r));   // en el heap: sobrevive al hilo
    if (r == NULL)
        return NULL;
    r->sum = 0;
    for (long i = t->from; i <= t->to; i++)
        r->sum += i;
    printf("hilo %d: [%ld, %ld] -> %ld\n", t->id, t->from, t->to, r->sum);
    return r;                           // NUNCA la dirección de una variable local
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "uso: args <N> <hilos>\n");
        return 1;
    }
    long N = atol(argv[1]);
    int n = atoi(argv[2]);
    if (N < 1 || n < 1 || n > 16) {
        fprintf(stderr, "N >= 1, hilos entre 1 y 16\n");
        return 1;
    }

    pthread_t th[16];
    task_t tasks[16];                   // un struct por hilo: no reutilizar uno solo
    long chunk = N / n;
    for (int i = 0; i < n; i++) {
        tasks[i].id = i;
        tasks[i].from = i * chunk + 1;
        tasks[i].to = (i == n - 1) ? N : (i + 1) * chunk;
        if (pthread_create(&th[i], NULL, sum_range, &tasks[i]) != 0) {
            fprintf(stderr, "pthread_create falló\n");
            return 1;
        }
    }

    long total = 0;
    for (int i = 0; i < n; i++) {
        void *ret;
        pthread_join(th[i], &ret);      // ret recibe lo que retornó el hilo
        result_t *r = ret;
        if (r != NULL) {
            total += r->sum;
            free(r);                    // lo reservó el hilo; lo libera main
        }
    }
    printf("total = %ld   (N(N+1)/2 = %ld)\n", total, N * (N + 1) / 2);
    return 0;
}
