Передо мной стоит очень сложная задача. Что довольно легко описать, но сложно реализовать, и я действительно не знаю, как это сделать. Может быть, кто-то знает более простой способ:
Я хочу сохранить параметры (стек и регистры) вызова функции в кучу, а после этого восстановить эти параметры в другом потоке.
Предположим, следующая функция:
int worker(int p1, int p2, ...) // variadic
{
return enq(); // will pack the parameters and return a Job structure
... // some heavy work that must be executed by another thread
}
Моя отправная точка - две структуры, первая содержит текущий кадр стека
struct StackFrame
{
struct StackFrame *next;
void *returnAddr;
};
А вторая содержит сохраненные параметры и точку возврата рабочего
struct Job
{
void *registers[];
size_t regCount;
void *stackFrame;
size_t frameSize;
void *workerAddr;
};
Теперь функция enq()
будет упаковывать рабочие параметры и ставить в очередь задание, используя пул потоков (уже работающий). Я предвидел что-то вроде этого:
Job* enq()
{
// get the caller stackFrame
register struct StackFrame *fp __builtin_frame_address(1);
// save the stack parameters of the caller to the heap,
Job *job = new Job;
job->frameSize = frame->next - frame;
job->frameContent = malloc (job->frameSize);
memcpy (job->stackContent, frame, job->frameSize );
job->workerAddr = frame.workerAddr // to where the worker Thread will jump
// !! I'm stuck here !!
// copy all the registers to memory (ideally only the used as parameters)
job.registers = ... // in i32 there was an instruction called PUSHA, but not on i64
return job // real, threadPool.push(job)
}
Теперь, на рабочей стороне, функция deq()
выполнит обратную операцию enq()
, что-то вроде этого:
void deq(Job *job)
{
// real, Job *job = threadPool.pop()
// restore the registers parameters
POPA(job->registers, job->regCount) // just like (i32 POPA)
// restore the stack frame.
push(job->frameContent, job->frameSize)
// execute the worker
call(job->workerAddr);
// mark the Job as done
}
In на стороне клиента, я хочу вызвать эту функцию так же, как:
Job* promise = worker(1, 2, "a variadic param");
wait(promise); // or wait(promise, callback)
Функция enq()
должна упаковать параметры вызывающей стороны в структуру Job изнутри рабочей функции.
The wait()
функция не является реальной проблемой, и она здесь, чтобы показать, как все это должно работать.
Это все, что у меня есть.
Знаете ли вы, как решить любой из этих пропущенных шагов и помочь мне немного приблизиться к моим намерениям? Или даже лучше, более простой и высокоуровневый способ сделать это?
Я использую G CC 9.2.1 в Ubuntu 19 64 бит.