|
| 1 | + |
| 2 | +import ./types |
| 3 | +import ../../../pyerrors/rterr |
| 4 | +import std/lists |
| 5 | +import std/locks |
| 6 | +import std/macros |
| 7 | + |
| 8 | +template mytoAny[T](x: T): Any = |
| 9 | + bind toAny |
| 10 | + var tx = x |
| 11 | + toAny(tx) |
| 12 | +
|
| 13 | +proc nodeToAny(n: NimNode): NimNode = newCall(bindSym"mytoAny", n) |
| 14 | +
|
| 15 | +proc callVarargImpl(call, arg1, vargs: NimNode): NimNode = |
| 16 | + # NIM-BUG: vargs will become Sym of nil when doc |
| 17 | + expectKind vargs, nnkBracket |
| 18 | + result = newCall(call, arg1) |
| 19 | + for i in vargs: |
| 20 | + result.add i.nodeToAny |
| 21 | +
|
| 22 | +macro callVararg(call, arg1, vargs: typed) = |
| 23 | + callVarargImpl(call, arg1, vargs) |
| 24 | +
|
| 25 | +macro callWithExtraVararg(call, arg1, vargs: typed, extra: Any) = |
| 26 | + result = callVarargImpl(call, arg1, vargs) |
| 27 | + result.add extra |
| 28 | +
|
| 29 | +template initHookList(): SinglyLinkedList[HookEntry] = initSinglyLinkedList[HookEntry]() |
| 30 | +template toHookEntry(v: HookProc, userData: Any): HookEntry = (v, userData) |
| 31 | +
|
| 32 | +type |
| 33 | + PyRuntimeState = object |
| 34 | + audit_hooks*: tuple[ |
| 35 | + head: SinglyLinkedList[HookEntry], |
| 36 | + mutex: Lock, |
| 37 | + ] |
| 38 | + |
| 39 | +var runtime = PyRuntimeState( |
| 40 | + audit_hooks: ( |
| 41 | + head: initHookList(), |
| 42 | + mutex: Lock(), |
| 43 | + ) |
| 44 | +) |
| 45 | +runtime.audit_hooks.mutex.initLock() |
| 46 | + |
| 47 | +var interp = ( |
| 48 | + audit_hooks: newSeq[HookProc]() |
| 49 | +) |
| 50 | +proc PyDTrace_AUDIT_ENABLED(): bool = false ## Currently not implemented |
| 51 | +proc should_audit(): bool{.inline.} = |
| 52 | + not runtime.audit_hooks.head.head.isNil or |
| 53 | + interp.audit_hooks.len > 0 or |
| 54 | + PyDTrace_AUDIT_ENABLED() |
| 55 | +
|
| 56 | +template PySys_AuditImpl(event: string, args: untyped) = |
| 57 | + ## `PySys_Audit`/`sys_audit_tstate` EXT. CPython C-API |
| 58 | + bind runtime, callWithExtraVararg, callVararg, items |
| 59 | + for e in runtime.audit_hooks.head.items: |
| 60 | + callWithExtraVararg( |
| 61 | + e.hookCFunction, |
| 62 | + event, args, e.userData) |
| 63 | +
|
| 64 | + #[if dtrace: ...]# |
| 65 | + |
| 66 | + # Call interpreter hooks |
| 67 | + for hook in interp.audit_hooks: |
| 68 | + callVararg(hook, event, args) |
| 69 | + |
| 70 | +template PySys_Audit*(event: string, args: varargs[typed]) = |
| 71 | + bind PySys_AuditImpl |
| 72 | + PySys_AuditImpl(event, args) |
| 73 | + |
| 74 | +proc add_audit_hook_entry_unlocked(runtime: var PyRuntimeState, entry: HookEntry) = |
| 75 | + runtime.audit_hooks.head.append entry |
| 76 | + |
| 77 | +template auditAddAuditHook(exc){.dirty.} = |
| 78 | + ## `PySys_Audit` EXT. CPython C-API |
| 79 | + try: |
| 80 | + PySys_Audit("sys.addaudithook") |
| 81 | + except exc: |
| 82 | + # We do not report errors derived from exc |
| 83 | + discard |
| 84 | + |
| 85 | +proc PySys_AddAuditHook*(hook: HookProc, userData = default Any) = |
| 86 | + ## `PySys_Audit` EXT. CPython C-API |
| 87 | + auditAddAuditHook RuntimeError |
| 88 | + |
| 89 | + withLock runtime.audit_hooks.mutex: |
| 90 | + add_audit_hook_entry_unlocked(runtime, hook.toHookEntry userData) |
| 91 | + |
| 92 | + |
| 93 | +proc addaudithook*(hook: HookProc) = |
| 94 | + auditAddAuditHook CatchableError |
| 95 | + interp.audit_hooks.add hook |
| 96 | + |
| 97 | +template audit*(event: string, args: varargs[typed]) = |
| 98 | + bind should_audit, PySys_AuditImpl |
| 99 | + if should_audit(): |
| 100 | + PySys_AuditImpl(event, args) |
| 101 | + |
| 102 | +const ClearAuditHooksName = "cpython._PySys_ClearAuditHooks" |
| 103 | +proc PySys_ClearAuditHooks() = |
| 104 | + # TODO: after config.verbose |
| 105 | + #if config.verbose: PySys_WriteStderr("# clear sys.audit hooks\n") |
| 106 | + try: PySys_Audit(ClearAuditHooksName) |
| 107 | + except Exception: discard |
| 108 | + |
| 109 | +when (NimMajor, NimMinor, NimPatch) >= (2, 1, 1): |
| 110 | + ## XXX: FIXED-NIM-BUG: though nimAllowNonVarDestructor is defined at least since 2.0.6, |
| 111 | + ## it still cannot be compiled till abour 2.1.1 |
| 112 | + proc `=destroy`*(self: PyRuntimeState) = PySys_ClearAuditHooks() |
| 113 | +else: |
| 114 | + proc `=destroy`*(self: var PyRuntimeState) = PySys_ClearAuditHooks() |
| 115 | + |
| 116 | +when isMainModule: |
| 117 | + addaudithook do (event: string, _: varargs[Any]): |
| 118 | + assert event == ClearAuditHooksName |
0 commit comments