From 953d7892b9cac26eee9cb509baafd2f043aa7c0f Mon Sep 17 00:00:00 2001 From: Vincent Parrett Date: Wed, 15 Apr 2020 15:33:17 +1000 Subject: [PATCH] Initial commit --- .gitattributes | 13 + .gitignore | 39 ++ Delphinus.Info.json | 9 + Delphinus.Install.json | 18 + LICENSE.txt | 202 +++++++++++ README.md | 3 + Source/VSoft.CancellationToken.Impl.pas | 105 ++++++ Source/VSoft.CancellationToken.pas | 163 +++++++++ Tests/CancellationtokenTests.dpr | 70 ++++ Tests/CancellationtokenTests.dproj | 449 ++++++++++++++++++++++++ Tests/VSoft.CancellationToken.Tests.pas | 124 +++++++ VSoft.CancellationToken.dspec | 91 +++++ 12 files changed, 1286 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Delphinus.Info.json create mode 100644 Delphinus.Install.json create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 Source/VSoft.CancellationToken.Impl.pas create mode 100644 Source/VSoft.CancellationToken.pas create mode 100644 Tests/CancellationtokenTests.dpr create mode 100644 Tests/CancellationtokenTests.dproj create mode 100644 Tests/VSoft.CancellationToken.Tests.pas create mode 100644 VSoft.CancellationToken.dspec diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f321c9d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text eol=crlf + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. + +# Declare files that will always have CRLF line endings on checkout. + +# Denote all files that are truly binary and should not be modified. +*.exe binary +*.res binary +*.dres binary +*.ico binary \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec0dc38 --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +# Compiled source # +################### +*.dcu +*.obj +*.exe +*.bpl +*.bpi +*.dcp +*.rsm +*.stat +*.map + +# Backup files # +################### +*.~* + +# IDE Files # +################### +*.dproj.local +*.groupproj.local +*.identcache +*.dsk +*.tvsconfig +*.otares +*.drc +*.rc +*.res +*.dres + +# Output Folders # +################### +/Win32 +/Win64 +/OSX32 +__history +/Tests/Win32 +/Tests/Win64 +/Tests/OSX32 +/Tests/__history diff --git a/Delphinus.Info.json b/Delphinus.Info.json new file mode 100644 index 0000000..b716d9d --- /dev/null +++ b/Delphinus.Info.json @@ -0,0 +1,9 @@ +{ + "id": "{D0EB6133-A828-49FE-BD6B-90CB09A39847}", + "license_type": "Apache-2.0", + "license_file": "LICENSE.txt", + "platforms": "Win32;Win64", + "package_compiler_min": 22, + "compiler_min": 22, + "first_version": "v0.0.1" +} diff --git a/Delphinus.Install.json b/Delphinus.Install.json new file mode 100644 index 0000000..1fa53a8 --- /dev/null +++ b/Delphinus.Install.json @@ -0,0 +1,18 @@ +{ + "search_pathes": + [ + { + "pathes": ".\\Source", + "platforms": "Win32;Win64" + } + ], + + "source_folders": + [ + { + "folder": ".", + "recursive": true, + "filter": "*.*" + } + ] +} \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..aa70669 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# VSoft.CancellationToken + +This is a simple library for Delphi that provides a CancellationTokenSource and CancellationToken much like those in .NET diff --git a/Source/VSoft.CancellationToken.Impl.pas b/Source/VSoft.CancellationToken.Impl.pas new file mode 100644 index 0000000..bbb5c83 --- /dev/null +++ b/Source/VSoft.CancellationToken.Impl.pas @@ -0,0 +1,105 @@ +{***************************************************************************} +{ } +{ VSoft.CancellationToken - Enables cooperative cancellation } +{ between threads } +{ } +{ Copyright � 2020 Vincent Parrett and contributors } +{ } +{ vincent@finalbuilder.com } +{ https://www.finalbuilder.com } +{ } +{ } +{***************************************************************************} +{ } +{ Licensed under the Apache License, Version 2.0 (the "License"); } +{ you may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ } +{ http://www.apache.org/licenses/LICENSE-2.0 } +{ } +{ Unless required by applicable law or agreed to in writing, software } +{ distributed under the License is distributed on an "AS IS" BASIS, } +{ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. } +{ See the License for the specific language governing permissions and } +{ limitations under the License. } +{ } +{***************************************************************************} + + +unit VSoft.CancellationToken.Impl; + +interface + +uses + System.SyncObjs, + VSoft.CancellationToken; + +type + TCancellationToken = class(TCancellationTokenBase, ICancellationToken, ICancellationTokenManage) + private + FEvent : TEvent; + FIsCancelled : boolean; + protected + {$IFDEF MSWINDOWS} + function GetHandle: THandle;virtual; + {$ELSE} + function GetEvent : TEvent;virtual; + {$ENDIF} + function IsCancelled: boolean;virtual; + procedure Cancel;virtual; + procedure Reset;virtual; + public + constructor Create;override; + destructor Destroy;override; + end; + + +implementation + +{ TCancellationToken } + +procedure TCancellationToken.Cancel; +begin + FIsCancelled := true; + FEvent.SetEvent; +end; + +constructor TCancellationToken.Create; +begin + FEvent := TEvent.Create(nil, true, false,''); + FIsCancelled := false; +end; + +destructor TCancellationToken.Destroy; +begin + FEvent.SetEvent;// in case anything is waiting on this + FEvent.Free; + inherited; +end; + +{$IFDEF MSWINDOWS} +function TCancellationToken.GetHandle: THandle; +begin + result := FEvent.Handle; +end; +{$ELSE} +function TCancellationToken.GetEvent : TEvent; +begin + result := FEvent; +end; +{$ENDIF} + +function TCancellationToken.IsCancelled: boolean; +begin + result := FIsCancelled; +end; + +procedure TCancellationToken.Reset; +begin + FEvent.ResetEvent; + FIsCancelled := false; + +end; + + +end. diff --git a/Source/VSoft.CancellationToken.pas b/Source/VSoft.CancellationToken.pas new file mode 100644 index 0000000..bc5e896 --- /dev/null +++ b/Source/VSoft.CancellationToken.pas @@ -0,0 +1,163 @@ +{***************************************************************************} +{ } +{ VSoft.CancellationToken - Enables cooperative cancellation } +{ between threads } +{ } +{ Copyright � 2020 Vincent Parrett and contributors } +{ } +{ vincent@finalbuilder.com } +{ https://www.finalbuilder.com } +{ } +{ } +{***************************************************************************} +{ } +{ Licensed under the Apache License, Version 2.0 (the "License"); } +{ you may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ } +{ http://www.apache.org/licenses/LICENSE-2.0 } +{ } +{ Unless required by applicable law or agreed to in writing, software } +{ distributed under the License is distributed on an "AS IS" BASIS, } +{ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. } +{ See the License for the specific language governing permissions and } +{ limitations under the License. } +{ } +{***************************************************************************} + +unit VSoft.CancellationToken; + +interface + +uses + System.SyncObjs; + +type + /// ICancellationToken is passed to async methods + /// so that they can determin if the caller has + /// cancelled. + ICancellationToken = interface + ['{481A7D4C-60D2-4AE5-AE14-F2298E89B638}'] + {$IFDEF MSWINDOWS} + function GetHandle: THandle; + {$ELSE} + function GetEvent : TEvent; + {$ENDIF} + function IsCancelled: boolean; + + {$IFDEF MSWINDOWS} + //Note : do not call SetEvent on this handle + //as it will result in IsSignalled prop + //returning incorrect results. + property Handle: THandle read GetHandle; + {$ELSE} + property Event : TEvent read GetEvent; + {$ENDIF} + + end; + + //ICancellationToken implementations must also implement this interface! + ICancellationTokenManage = interface(ICancellationToken) + ['{D3472D4F-0155-4DDA-80F8-01F44516952A}'] + procedure Reset; + procedure Cancel; + end; + + /// This should be created by calling functions and a reference + /// stored where it will not go out of scope. + /// Pass the Token to methods. + ICancellationTokenSource = interface + ['{4B7627AE-E8CE-4857-90D7-3C6D5B8A4F9F}'] + procedure Reset; + procedure Cancel; + function Token : ICancellationToken; + end; + + TCancellationTokenBase = class(TInterfacedObject) + public + constructor Create;virtual;abstract; + end; + + TCancellationTokenClass = class of TCancellationTokenBase; + + TCancellationTokenSourceFactory = class + private + class var + FTokenClass : TCancellationTokenClass; + private + class constructor Create; + public + class procedure RegisterTokenClass(const value : TCancellationTokenClass); + class function Create : ICancellationTokenSource; + end; + + + +implementation + +uses + System.SysUtils, + VSoft.CancellationToken.Impl; + +type + TCancellationTokenSource = class(TInterfacedObject, ICancellationTokenSource ) + private + FToken : ICancellationTokenManage; + protected + procedure Reset; + procedure Cancel; + function Token : ICancellationToken; + public + constructor Create(const token : ICancellationTokenManage); + end; + + +{ TCancellationTokenSourceFactory } + +class function TCancellationTokenSourceFactory.Create: ICancellationTokenSource; +var + token : IInterface; + theToken : ICancellationTokenManage; +begin + token := TCancellationTokenSourceFactory.FTokenClass.Create as ICancellationTokenManage; + if not Supports(token, ICancellationToken) then + raise Exception.Create('Registered Token class does not impleemt required interface ICancellationToken'); + if not Supports(token, ICancellationTokenManage,theToken) then + raise Exception.Create('Registered Token class does not impleemt required interface ICancellationTokenManage'); + result := TCancellationTokenSource.Create(theToken); +end; + +class constructor TCancellationTokenSourceFactory.Create; +begin + TCancellationTokenSourceFactory.FTokenClass := TCancellationToken; +end; + +class procedure TCancellationTokenSourceFactory.RegisterTokenClass(const value: TCancellationTokenClass); +begin + TCancellationTokenSourceFactory.FTokenClass := value; +end; + +{ TCancellationTokenSource } + +procedure TCancellationTokenSource.Cancel; +begin + FToken.Cancel; +end; + +constructor TCancellationTokenSource.Create(const token: ICancellationTokenManage); +begin + FToken := token; +end; + +procedure TCancellationTokenSource.Reset; +begin + FToken.Reset; +end; + +function TCancellationTokenSource.Token: ICancellationToken; +begin + result := FToken; +end; + + +end. diff --git a/Tests/CancellationtokenTests.dpr b/Tests/CancellationtokenTests.dpr new file mode 100644 index 0000000..3498d42 --- /dev/null +++ b/Tests/CancellationtokenTests.dpr @@ -0,0 +1,70 @@ +program CancellationtokenTests; + +{$IFNDEF TESTINSIGHT} +{$APPTYPE CONSOLE} +{$ENDIF} +{$STRONGLINKTYPES ON} +uses + System.SysUtils, + {$IFDEF TESTINSIGHT} + TestInsight.DUnitX, + {$ELSE} + DUnitX.Loggers.Console, + DUnitX.Loggers.Xml.NUnit, + {$ENDIF } + DUnitX.TestFramework, + VSoft.CancellationToken.Tests in 'VSoft.CancellationToken.Tests.pas', + VSoft.CancellationToken in '..\Source\VSoft.CancellationToken.pas', + VSoft.CancellationToken.Impl in '..\Source\VSoft.CancellationToken.Impl.pas'; + +{$IFNDEF TESTINSIGHT} +var + runner: ITestRunner; + results: IRunResults; + logger: ITestLogger; + nunitLogger : ITestLogger; +{$ENDIF} +begin +{$IFDEF TESTINSIGHT} + TestInsight.DUnitX.RunRegisteredTests; +{$ELSE} + try + //Check command line options, will exit if invalid + TDUnitX.CheckCommandLine; + //Create the test runner + runner := TDUnitX.CreateRunner; + //Tell the runner to use RTTI to find Fixtures + runner.UseRTTI := True; + //When true, Assertions must be made during tests; + runner.FailsOnNoAsserts := False; + + //tell the runner how we will log things + //Log to the console window if desired + if TDUnitX.Options.ConsoleMode <> TDunitXConsoleMode.Off then + begin + logger := TDUnitXConsoleLogger.Create(TDUnitX.Options.ConsoleMode = TDunitXConsoleMode.Quiet); + runner.AddLogger(logger); + end; + //Generate an NUnit compatible XML File + nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile); + runner.AddLogger(nunitLogger); + + //Run tests + results := runner.Execute; + if not results.AllPassed then + System.ExitCode := EXIT_ERRORS; + + {$IFNDEF CI} + //We don't want this happening when running under CI. + if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then + begin + System.Write('Done.. press key to quit.'); + System.Readln; + end; + {$ENDIF} + except + on E: Exception do + System.Writeln(E.ClassName, ': ', E.Message); + end; +{$ENDIF} +end. diff --git a/Tests/CancellationtokenTests.dproj b/Tests/CancellationtokenTests.dproj new file mode 100644 index 0000000..2042a52 --- /dev/null +++ b/Tests/CancellationtokenTests.dproj @@ -0,0 +1,449 @@ + + + {FD9A4D8C-A46A-434A-B313-5102D5AE4014} + 16.1 + None + CancellationtokenTests.dpr + True + Debug + Win32 + 1 + Console + + + XE7 + $(APPDATA)\.dpm\packages + $(DPMCache)\$(DPMCompiler)\$(Platform) + $(DPM)\VSoft.DUnitX\0.1.0\src; + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + 3081 + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + None + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\delphi_PROJECTICNS.icns + $(DPMSearch);$(DCC_UnitSearchPath) + CancellationtokenTests + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + fmx;rtl;dbrtl;DbxClientDriver;xmlrtl;DbxCommonDriver;soaprtl;CustomIPTransport;fmxase;CloudService;inet;fmxobj;fmxdae;$(DCC_UsePackage) + + + None + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + madBasic_;NxGridRun_dxe7;FBMiscComponents;rdp;dwWin7Controls;fmx;rtl;dbrtl;DbxClientDriver;FixInsight_XE7;RaizeComponentsVcl;FBDreamRuntime;ChromeTabs_R;madDisAsm_;xmlrtl;DbxCommonDriver;lmdrtinspector;vclimg;lmdrtdesign;SpTBXLib_d21;NxCommonDsgn_dxe7;vclactnband;soaprtl;vcldb;FBFormDesigner;IndyProtocols210;VSPageR;NxCommonRun_dxe7;vclie;NxGrid6Run_dxe7;madExcept_;vcltouch;FrameViewerXE7;CustomIPTransport;VclSmp;NxGridDsgn_dxe7;fmxase;vcl;SynEdit_RXE7;CloudService;KWizardR;inet;fmxobj;FBSynEditHighlighters;vclx;lmdrtdocking;lmdrtrtlx;NxStandard6Run_dxe7;fmxdae;IndySystem210;IndyCore210;JSDialogPack;tb2k;VirtualTreesR;lmdrtl;adortl;NxLayout6Run_dxe7;$(DCC_UsePackage) + 1033 + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + NxGridRun_dxe7;fmx;rtl;dbrtl;DbxClientDriver;RaizeComponentsVcl;xmlrtl;DbxCommonDriver;lmdrtinspector;vclimg;lmdrtdesign;NxCommonDsgn_dxe7;vclactnband;soaprtl;vcldb;NxCommonRun_dxe7;vclie;NxGrid6Run_dxe7;vcltouch;CustomIPTransport;VclSmp;NxGridDsgn_dxe7;fmxase;vcl;CloudService;inet;fmxobj;vclx;lmdrtdocking;lmdrtrtlx;NxStandard6Run_dxe7;fmxdae;VirtualTreesR;lmdrtl;adortl;NxLayout6Run_dxe7;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + None + 1033 + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + Delphi.Personality.12 + Console + + + + CancellationtokenTests.dpr + + + IP Abstraction Indy Implementation Design Time + + + + + + CancellationtokenTests.exe + true + + + + + true + + + true + + + + + 1 + .dylib + + + 0 + .bpl + + + 1 + .dylib + + + 1 + .dylib + + + + + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + res\drawable-normal + 1 + + + + + library\lib\x86 + 1 + + + + + 1 + + + 1 + + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-xhdpi + 1 + + + + + 1 + + + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + library\lib\mips + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 0 + + + + + 1 + .framework + + + 0 + + + + + res\drawable-small + 1 + + + + + + 1 + + + Contents\MacOS + 0 + + + + + classes + 1 + + + + + + 1 + + + 1 + + + + + res\drawable + 1 + + + + + Contents\Resources + 1 + + + + + + 1 + + + 1 + + + + + 1 + + + library\lib\armeabi-v7a + 1 + + + 0 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + res\drawable-large + 1 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + 1 + + + + + res\drawable-ldpi + 1 + + + + + res\values + 1 + + + + + 1 + + + 1 + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + + + 1 + + + + + + + + + + + False + True + False + + + 12 + + + + + + + + diff --git a/Tests/VSoft.CancellationToken.Tests.pas b/Tests/VSoft.CancellationToken.Tests.pas new file mode 100644 index 0000000..ec60520 --- /dev/null +++ b/Tests/VSoft.CancellationToken.Tests.pas @@ -0,0 +1,124 @@ +unit VSoft.CancellationToken.Tests; + +interface + +uses + DUnitX.TestFramework, + VSoft.CancellationToken; + +type + [TestFixture] + TCancellationTokenTests = class + private + FTokenSource : ICancellationTokenSource; + + public + + [SetupFixture] + procedure SetupFixture; + + [TeardownFixture] + procedure TeardownFixture; + + [Test] + procedure TestCancel; + + [Test] + procedure TestCancelUsingHandle; + + end; + +implementation + +uses + System.Classes, + System.SyncObjs, + WinApi.Windows; + + +{ TCancellationTokenTests } + +procedure TCancellationTokenTests.SetupFixture; +begin + FTokenSource := TCancellationTokenSourceFactory.Create; +end; + +procedure TCancellationTokenTests.TeardownFixture; +begin + FTokenSource := nil; +end; + +procedure TCancellationTokenTests.TestCancel; +var + token : ICancellationToken; + cancelled : boolean; +begin + FTokenSource.Reset; + cancelled := false; + token := FTokenSource.Token; + TThread.CreateAnonymousThread( + procedure + var + ltoken : ICancellationToken; + begin + lToken := token; + while not lToken.IsCancelled do + begin + Sleep(1); + cancelled := lToken.IsCancelled; + end; + end).Start; +// testThread.Start; + TThread.Sleep(100); + FTokenSource.Cancel; + TThread.Sleep(50); + Assert.IsTrue(cancelled); +end; + + +procedure TCancellationTokenTests.TestCancelUsingHandle; +var + token : ICancellationToken; + cancelled : boolean; +begin + FTokenSource.Reset; + cancelled := false; + token := FTokenSource.Token; + TThread.CreateAnonymousThread( + procedure + var + res : integer; + ltoken : ICancellationToken; + event : TEvent; + handles : array[0..1] of THandle; + begin + lToken := token; + event := TEvent.Create(nil,false, false,''); + handles[0] := lToken.Handle; + handles[1] := event.Handle; + try + while true do + begin + res := WaitForMultipleObjects(2, @handles, false, 2000); + if res = WAIT_OBJECT_0 then + begin + //token was cancelled + cancelled := true; + exit; + end; + end; + + finally + event.Free; + end; + end).Start; + TThread.Sleep(100); + FTokenSource.Cancel; + TThread.Sleep(50); + Assert.IsTrue(cancelled); +end; + +initialization + TDUnitX.RegisterTestFixture(TCancellationTokenTests); + +end. diff --git a/VSoft.CancellationToken.dspec b/VSoft.CancellationToken.dspec new file mode 100644 index 0000000..4cbd3b1 --- /dev/null +++ b/VSoft.CancellationToken.dspec @@ -0,0 +1,91 @@ +{ + "metadata": { + "id": "VSoft.CancellationToken", + "version": "0.0.1", + "description": "Enables cooperative cancellation between threads", + "authors": "Vincent Parrett", + "projectUrl": "/~https://github.com/VSoftTechnologies/VSoft.CancellationToken", + "license": "Apache-2.0", + "copyright": "Vincent Parrett and contributors", + "tags": "cancellation async threads" + }, + "targetPlatforms": [ + { + "compiler": "XE2", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "XE3", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "XE4", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "XE5", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "XE6", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "XE7", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "XE8", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "10.0", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "10.1", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "10.2", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "10.3", + "platforms": "Win32, Win64", + "template": "default" + }, + { + "compiler": "10.4", + "platforms": "Win32, Win64", + "template": "default" + } + ], + "templates": [ + { + "name": "default", + "source": [ + { + "src": "source\\*.pas", + "flatten": true, + "dest": "src" + } + ], + "searchPaths": [ + { + "path": "src" + } + ] + } + ] +}