static CFProxy[] ExecutePacCFRunLoopSourceBlocking(CreatePACCFRunLoopSource factory, out NSError outError)
        {
            var runLoop = CFRunLoop.Current;

            outError = null;

            // build a struct that will have all the needed info for the callback
            var pacCbData = new PACProxyCallbackData();

            pacCbData.CFRunLoopPtr = runLoop.Handle;
            var pacDataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pacCbData));

            try {
                Marshal.StructureToPtr(pacCbData, pacDataPtr, false);

                var clientContext = new CFStreamClientContext();
                clientContext.Info = pacDataPtr;

                using (var loopSource = new CFRunLoopSource(factory(ExecutePacCallback, ref clientContext)))
                    using (var mode = new NSString("Xamarin.iOS.Proxy")) {
                        runLoop.AddSource(loopSource, mode);
                        runLoop.RunInMode(mode, double.MaxValue, false);
                        runLoop.RemoveSource(loopSource, mode);
                    }
                pacCbData = (PACProxyCallbackData)Marshal.PtrToStructure(pacDataPtr, typeof(PACProxyCallbackData));
                // get data from the struct
                outError = pacCbData.Error;
                return(pacCbData.ProxyList);
            } finally {
                if (pacCbData.ProxyListPtr != IntPtr.Zero)
                {
                    CFObject.CFRelease(pacCbData.ProxyListPtr);
                }
                if (pacCbData.ErrorPtr != IntPtr.Zero)
                {
                    NSObject.DangerousRelease(pacCbData.ErrorPtr);
                }
                Marshal.FreeHGlobal(pacDataPtr);
            }
        }
        static async Task <(CFProxy[] proxies, NSError error)> ExecutePacCFRunLoopSourceAsync(CreatePACCFRunLoopSource factory, CancellationToken cancellationToken)
        {
            CFProxy[] proxies  = null;
            NSError   outError = null;

            if (cancellationToken.IsCancellationRequested)
            {
                throw new OperationCanceledException("Operation was cancelled.");
            }

            await Task.Run(() => {
                // we need the runloop of THIS thread, so it is important to get it in the correct context
                var runLoop = CFRunLoop.Current;

                // build a struct that will have all the needed info for the callback
                var pacCbData          = new PACProxyCallbackData();
                pacCbData.CFRunLoopPtr = runLoop.Handle;
                var pacDataPtr         = Marshal.AllocHGlobal(Marshal.SizeOf(pacCbData));
                try {
                    Marshal.StructureToPtr(pacCbData, pacDataPtr, false);

                    var clientContext  = new CFStreamClientContext();
                    clientContext.Info = pacDataPtr;

                    using (var loopSource = new CFRunLoopSource(factory(ExecutePacCallback, ref clientContext)))
                        using (var mode = new NSString("Xamarin.iOS.Proxy")) {
                            if (cancellationToken.IsCancellationRequested)
                            {
                                throw new OperationCanceledException("Operation was cancelled.");
                            }

                            cancellationToken.Register(() => {
                                //if user cancels, we invalidte the source, stop the runloop and remove the source
                                loopSource.Invalidate();
                                runLoop.RemoveSource(loopSource, mode);
                                runLoop.Stop();
                            });
                            runLoop.AddSource(loopSource, mode);
                            // blocks until stop is called, will be done in the cb set previously
                            runLoop.RunInMode(mode, double.MaxValue, false);
                            // does not raise an error if source is not longer present, so no need to worry
                            runLoop.RemoveSource(loopSource, mode);
                        }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        throw new OperationCanceledException("Operation was cancelled.");
                    }

                    pacCbData = (PACProxyCallbackData)Marshal.PtrToStructure(pacDataPtr, typeof(PACProxyCallbackData));
                    // get data from the struct
                    proxies  = pacCbData.ProxyList;
                    outError = pacCbData.Error;
                } finally {
                    // clean resources
                    if (pacCbData.ProxyListPtr != IntPtr.Zero)
                    {
                        CFObject.CFRelease(pacCbData.ProxyListPtr);
                    }
                    if (pacCbData.ErrorPtr != IntPtr.Zero)
                    {
                        NSObject.DangerousRelease(pacCbData.ErrorPtr);
                    }
                    Marshal.FreeHGlobal(pacDataPtr);
                }
            }, cancellationToken).ConfigureAwait(false);

            if (cancellationToken.IsCancellationRequested)
            {
                throw new OperationCanceledException("Operation was cancelled.");
            }
            return(proxies : proxies, error : outError);
        }