def await_future(future): """ This is effectively a technique I use to get around completely blocking IDA's mainthread while waiting for a threaded result that may need to make use of the execute_sync operators. Waiting for a 'future' thread result to come through via this function lets other execute_sync actions to slip through (at least Read, Fast). """ interval = 0.02 # the interval which we wait for a response # run until the the future arrives while True: # block for a brief period to see if the future completes try: return future.get(timeout=interval) # # the future timed out, so perhaps it is blocked on a request # to the mainthread. flush the requests now and try again # except Queue.Empty as e: pass logger.debug("Awaiting future...") # # if we are executing (well, blocking) as the main thread, we need # to flush the event loop so IDA does not hang # if idaapi.is_main_thread(): flush_ida_sync_requests()
def flush_ida_sync_requests(): """ Flush all execute_sync requests. NOTE: This MUST be called from the IDA Mainthread to be effective. """ if not idaapi.is_main_thread(): return False # this will trigger/flush the IDA UI loop qta = QtCore.QCoreApplication.instance() qta.processEvents() # done return True
def await_lock(lock): """ Attempt to acquire a lock without blocking the IDA mainthread. See await_future() for more details. """ elapsed = 0 # total time elapsed waiting for the lock interval = 0.02 # the interval (in seconds) between acquire attempts timeout = 60.0 # the total time allotted to acquiring the lock end_time = time.time() + timeout # wait until the the lock is available while time.time() < end_time: # # attempt to acquire the given lock without blocking (via 'False'). # if we succesfully aquire the lock, then we can return (success) # if lock.acquire(False): logger.debug("Acquired lock!") return # # the lock is not available yet. we need to sleep so we don't choke # the cpu, and try to acquire the lock again next time through... # logger.debug("Awaiting lock...") time.sleep(interval) # # if we are executing (well, blocking) as the main thread, we need # to flush the event loop so IDA does not hang # if idaapi.is_main_thread(): flush_ida_sync_requests() # # we spent 60 seconds trying to acquire the lock, but never got it... # to avoid hanging IDA indefinitely (or worse), we abort via signal # raise RuntimeError("Failed to acquire lock after %f seconds!" % timeout)
def wrapper(*args, **kwargs): output = [None] # # this inline function definition is technically what will execute # in the context of the main thread. we use this thunk to capture # any output the function may want to return to the user. # def thunk(): output[0] = function(*args, **kwargs) return 1 # already in the target (main) thread, execute thunk now if idaapi.is_main_thread(): thunk() # send the synchronization request to IDA else: idaapi.execute_sync(thunk, sync_flags) # return the output of the synchronized function return output[0]
def wrapper(*args, **kwargs): assert idaapi.is_main_thread() return f(*args, **kwargs)
def wrapper(*args, **kwargs): ff = functools.partial(f, *args, **kwargs) if idaapi.is_main_thread(): return ff() else: return idaapi.execute_sync(ff, idaapi.MFF_READ)