// Stress concurrent malloc/free (fix: the __heapLock semaphore mutex).  The
// parent and a forked child both hammer the SHARED heap -- each repeatedly
// malloc()s a block, fills it with a thread-unique pattern, holds it briefly (to
// invite preemption), verifies the pattern survived, and free()s it.  If the
// free-list critical section were not serialized, the two threads' interleaved
// malloc/free could hand the same block to both (or corrupt the list), so a
// pattern check would fail or the walk would crash.  Both loops completing with
// intact patterns shows the heap is concurrency-safe.
//
//   0x025082  AAAA  parent's alloc loop finished with every pattern intact
//   0x025084  CCCC  child's  alloc loop finished with every pattern intact
//   0x025086  E0DD  parent reaped the child
#include <stdint.h>

extern int   fork(void *subr);
extern int   wait(int *status);
extern __attribute__((noreturn)) void _exit(int status);
extern void *malloc(unsigned long n);
extern void  free(void *p);

#define M(a)   (*(volatile uint16_t *)(a))
#define ITERS  120


static uint16_t allocLoop(uint16_t tag) {
    volatile uint16_t *p;
    uint16_t           ok;
    int                i;
    int                j;

    ok = 1;
    for (i = 0; i < ITERS; i++) {
        p = (volatile uint16_t *)malloc(32);
        if (p == 0) {
            ok = 0;
            break;
        }
        for (j = 0; j < 16; j++) {
            p[j] = (uint16_t)(tag + j);
        }
        for (volatile int s = 0; s < 40; s++) {   // hold the block; invite a task swap
        }
        for (j = 0; j < 16; j++) {
            if (p[j] != (uint16_t)(tag + j)) {
                ok = 0;
            }
        }
        free((void *)p);
    }
    return ok;
}


static void child(void) {
    uint16_t ok;
    ok = allocLoop(0xC000);
    M(0x025084UL) = ok ? 0xCCCC : 0xDEAD;
    _exit(0);
}


int main(void) {
    uint16_t ok;
    int      st;

    M(0x025082UL) = 0xDEAD;
    M(0x025084UL) = 0xDEAD;
    M(0x025086UL) = 0xDEAD;

    fork((void *)child);
    ok = allocLoop(0xA000);                // parent hammers the heap concurrently
    M(0x025082UL) = ok ? 0xAAAA : 0xDEAD;

    wait(&st);
    M(0x025086UL) = 0xE0DD;
    for (volatile unsigned long j = 0; j < 300000UL; j++) {
    }
    return 0;
}
