![]() |
|
#2
|
|||
|
|||
|
Another interesting function is execute_sync with MFF_NOWAIT which is needed when a thread doing work may need to be interrupted to prevent deadlock.
Code:
THREAD_SAFE inline int execute_sync(exec_request_t &req, int reqf) { return callui(ui_execute_sync, &req, reqf).i; }
Code:
THREAD_SAFE inline bool cancel_exec_request(int req_id) To deal with this, the best I could come up with was using both a semaphore to track the exec request completion, along with a termination flag and a mutex around that to prevent race conditions: Global (hopefully stored somewhere referenceable from a singular global object): Code:
bool exiting = false; int uiExecutingTask = -1; qmutex_t qm = qmutex_create(); Code:
{ //must be a locked unit otherwise race condition can occur
qmutex_locker_t lock(qm);
exiting = true;
if (uiExecutingTask != -1) {
cancel_exec_request(uiExecutingTask);
}
}
Code:
struct execFunctor : public exec_request_t
{
std::function<void()> fun;
qsemaphore_t finishSem;
execFunctor(std::function<void()> f, qsemaphore_t qs) : fun(f), finishSem(qs) {}
virtual ~execFunctor(void) override {}
/// Callback to be executed.
/// If this function raises an exception, execute_sync() never returns.
virtual int idaapi execute(void)
{
fun();
qsem_post(finishSem);
return 0;
}
};
void executeOnMainThread(std::function<void()> fun)
{
qsemaphore_t finishSem = qsem_create(nullptr, 0);
execFunctor* ef = new execFunctor(fun, finishSem);
{ //must be a locked unit otherwise race condition can occur
qmutex_locker_t lock(qm);
if (exiting) return;
uiExecutingTask = execute_sync(*ef, MFF_NOWAIT);
}
while (!qsem_wait(finishSem, 50)) {
if (exiting) {
uiExecutingTask = -1;
qsem_free(finishSem);
return;
}
}
uiExecutingTask = -1;
qsem_free(finishSem);
delete ef;
Now you can just wrap any code into a lambda as an argument to std::function<void()> to bind it and very easily execute anything on the main thread taking into account data thread safety issues if any. This allows for cancellable long running operations. Another area of concern is process creation using Code:
launch_process_params_t procInf;
...
PROCESS_INFORMATION pi{};
procInf.info = π
void* p = launch_process(procInf, &errbuf);
Code:
if (pi.hThread != INVALID_HANDLE_VALUE) CloseHandle(pi.hThread); Any uses of q functions with a create such as qthread_create must always have a matching free e.g. qthread_free and in this case should always have a qthread_join as well. Although qthread_kill is possible, it is a temporary workaround for deeper architectural issues or an emergency as the side effects nearly always outweigh the benefits and it could destabilize the IDA process. Again all of these things were discovered, and not mentioned in any documentation. |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Need some tips on in memory patching of a .Net dll | Sailor_EDA | General Discussion | 4 | 05-30-2011 22:27 |
| new tricks of armadillo | LaBBa | General Discussion | 4 | 01-30-2004 18:17 |
| tips? | NE1 | General Discussion | 3 | 08-27-2002 03:45 |