D. Hooking into OmniThreadLibrary

The OtlHooks unit allows your code to hook into internal OmniThreadLibrary processes. Currently you can register notification methods which are called when a thread is created/destroyed, a pool is created/destroyed, or an unhandled exception ‘escapes’ from a task.

Exception notifications

Exception filter allows your code to be notified when an unhandled exception in a task occurs. You can also prevent exception from being stored in the IOmniTask.FatalException property.

1 type
2   TExceptionFilterProc = procedure(var e: Exception; var continueProcessing: boolean);
3   TExceptionFilterMeth = procedure(var e: Exception; var continueProcessing: boolean) 
4                          of object;
6 procedure RegisterExceptionFilter(filterProc: TExceptionFilterProc); overload;
7 procedure RegisterExceptionFilter(filterMethod: TExceptionFilterMeth); overload;
8 procedure UnregisterExceptionFilter(filterProc: TExceptionFilterProc); overload;
9 procedure UnregisterExceptionFilter(filterMethod: TExceptionFilterMeth); overload;

Call RegisterExceptionFilter to register a custom exception filter. Call UnregisterExceptionFilter to remove custom exception filter.

Exception filter can use application-specific logging code to log detailed information about application state. It can also free the exception object e and set it to nil, which will prevent this exception to be stored in the FatalException property.

If the filter sets continueProcessing to false, further custom exception filters won’t be called. Filters are always called in the order in which they were registered.

Thread notifications

Thread notifications allow your code to be notified when a thread is created or destroyed inside the OmniThreadLibrary. This allows OmniThreadLibrary to cooperate with application-specific exception-logging code.

 1 type
 2   TThreadNotificationType = (tntCreate, tntDestroy);
 3   TThreadNotificationProc = procedure(notifyType: TThreadNotificationType;
 4                               const threadName: string);
 5   TThreadNotificationMeth = procedure(notifyType: TThreadNotificationType;
 6                               const threadName: string) of object;
 8 procedure RegisterThreadNotification(notifyProc: TThreadNotificationProc); overload;
 9 procedure RegisterThreadNotification(notifyMethod: TThreadNotificationMeth); overload;
10 procedure UnregisterThreadNotification(notifyProc: TThreadNotificationProc); overload;
11 procedure UnregisterThreadNotification(notifyMethod: TThreadNotificationMeth); overload;

Call RegisterThreadNotification to register a thread notification method. Call UnregisterThreadNotification to unregister such method.

Notification method is always called in the context of the thread being created/destroyed.

For example, the following code fragment registers/unregisters OmniThreadLibrary threads with an application-specific thread logger.

 1 procedure OtlThreadNotify(notifyType: TThreadNotificationType; const threadName: string);
 2 var
 3   name: string;
 4 begin
 5   case notifyType of
 6     tntCreate:
 7       begin
 8         if threadName <> '' then
 9           name := threadName
10         else
11           name := 'unnamed OTL thread';
12         LoggerRegisterThread(name);
13       end;
14     tntDestroy:
15       LoggerUnregisterThread;
16     else
17       raise Exception.Create('OtlThreadNotify: Unexpected notification type');
18   end;
19 end;
21 OtlHooks.RegisterThreadNotification(OtlThreadNotify);

Pool notifications

Pool notifications allow your code to be notified when a thread pool is being created or destroyed. This allows the application to modifiy pool parameters on the fly.

 1 type
 2   TPoolNotificationType = (pntCreate, pntDestroy);
 3   TPoolNotificationProc = procedure(notifyType: TPoolNotificationType;
 4                             const pool: IOmniThreadPool);
 5   TPoolNotificationMeth = procedure(notifyType: TPoolNotificationType;
 6                             const pool: IOmniThreadPool) of object;
 8 procedure RegisterPoolNotification(notifyProc: TPoolNotificationProc); overload;
 9 procedure RegisterPoolNotification(notifyMethod: TPoolNotificationMeth); overload;
10 procedure UnregisterPoolNotification(notifyProc: TPoolNotificationProc); overload;
11 procedure UnregisterPoolNotification(notifyMethod: TPoolNotificationMeth); overload;

Call RegisterPoolNotification to register a pool notification method. Call UnregisterPoolNotification to unregister such method.

You can, for example, use pool notification mechanism to set Asy_OnUnhandledWorkerException property whenever a thread pool is created.

 1 procedure OtlPoolNotify(notifyType: TPoolNotificationType; const pool: IOmniThreadPool);
 2 begin
 3   case notifyType of
 4     pntCreate:  pool.Asy_OnUnhandledWorkerException := Asy_LogUnhandledOtlWorkerException;
 5     pntDestroy: pool.Asy_OnUnhandledWorkerException := nil;
 6     else        raise Exception.Create('OtlPoolNotify: Unexpected notification type');
 7   end;
 8 end;
10 OtlHooks.RegisterPoolNotification(OtlPoolNotify);