Используйте макросы для замены всех глобальных переменных следующим образом:
#define global1 ctx->global1
#define global2 ctx->global2
...
Затем добавьте аргумент struct context *ctx
для каждой функции.
В качестве альтернативы, добавьте _Thread_local
(или __thread
со старыми версиями gcc) к каждой глобальной переменной, затем запустите каждый "экземпляр" в своем собственном потоке, чтобы у него, естественно, были свои собственные копии глобальных переменных, доступных для него.