├── .clang-format
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── build
├── msvc
│ ├── build.default.props
│ ├── task.sln
│ ├── task.vcxproj
│ └── test
│ │ ├── all.vcxproj
│ │ └── task.vcxproj
├── ninja
│ ├── android.py
│ ├── clang.py
│ ├── codesign.py
│ ├── gcc.py
│ ├── generator.py
│ ├── msvc.py
│ ├── platform.py
│ ├── plist.py
│ ├── syntax.py
│ ├── toolchain.py
│ ├── version.py
│ ├── vslocate.py
│ └── xcode.py
└── task.sublime-project
├── configure.py
├── task
├── build.h
├── executor.c
├── executor.h
├── fiber.c
├── fiber.h
├── hashstrings.h
├── hashstrings.txt
├── scheduler.c
├── scheduler.h
├── task.c
├── task.h
├── types.h
└── version.c
└── test
├── all
├── android
│ ├── AndroidManifest.xml
│ ├── drawable-hdpi
│ │ └── icon.png
│ ├── drawable-ldpi
│ │ └── icon.png
│ ├── drawable-mdpi
│ │ └── icon.png
│ ├── drawable-xhdpi
│ │ └── icon.png
│ ├── drawable-xxhdpi
│ │ └── icon.png
│ ├── drawable-xxxhdpi
│ │ └── icon.png
│ ├── java
│ │ └── com
│ │ │ └── maniccoder
│ │ │ └── task
│ │ │ └── test
│ │ │ └── TestActivity.java
│ ├── layout
│ │ └── main.xml
│ └── values
│ │ └── strings.xml
├── ios
│ ├── Images.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── icon_100.png
│ │ │ ├── icon_114.png
│ │ │ ├── icon_120.png
│ │ │ ├── icon_144.png
│ │ │ ├── icon_152.png
│ │ │ ├── icon_180.png
│ │ │ ├── icon_29-1.png
│ │ │ ├── icon_29.png
│ │ │ ├── icon_40.png
│ │ │ ├── icon_50.png
│ │ │ ├── icon_57.png
│ │ │ ├── icon_58-1.png
│ │ │ ├── icon_58.png
│ │ │ ├── icon_72.png
│ │ │ ├── icon_76.png
│ │ │ ├── icon_80-1.png
│ │ │ └── icon_80.png
│ │ └── LaunchImage.launchimage
│ │ │ ├── Contents.json
│ │ │ ├── launch_1024_748.png
│ │ │ ├── launch_1024_768.png
│ │ │ ├── launch_1536_2008.png
│ │ │ ├── launch_1536_2048.png
│ │ │ ├── launch_2048_1496.png
│ │ │ ├── launch_2048_1536.png
│ │ │ ├── launch_320_480.png
│ │ │ ├── launch_640_1136.png
│ │ │ ├── launch_640_960.png
│ │ │ ├── launch_768_1004.png
│ │ │ └── launch_768_1024.png
│ ├── test-all.plist
│ ├── test-all.xib
│ ├── viewcontroller.h
│ └── viewcontroller.m
├── main.c
└── tizen
│ ├── res
│ └── tizenapp.png
│ └── tizen-manifest.xml
└── task
└── main.c
/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: Google
2 | AlignAfterOpenBracket: Align
3 | AlignConsecutiveAssignments: 'false'
4 | AlignConsecutiveDeclarations: 'false'
5 | AlignOperands: 'true'
6 | AlignTrailingComments: 'true'
7 | AllowAllParametersOfDeclarationOnNextLine: 'false'
8 | AllowShortBlocksOnASingleLine: 'false'
9 | AllowShortCaseLabelsOnASingleLine: 'false'
10 | AllowShortFunctionsOnASingleLine: None
11 | AllowShortIfStatementsOnASingleLine: 'false'
12 | AllowShortLoopsOnASingleLine: 'false'
13 | AlwaysBreakAfterDefinitionReturnType: TopLevel
14 | AlwaysBreakAfterReturnType: TopLevel
15 | AlwaysBreakBeforeMultilineStrings: 'true'
16 | AlwaysBreakTemplateDeclarations: 'true'
17 | BinPackArguments: 'true'
18 | BinPackParameters: 'true'
19 | BreakBeforeBinaryOperators: None
20 | BreakBeforeBraces: Attach
21 | BreakBeforeTernaryOperators: 'false'
22 | ColumnLimit: '120'
23 | ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
24 | DerivePointerAlignment: 'false'
25 | ExperimentalAutoDetectBinPacking: 'false'
26 | IndentCaseLabels: 'true'
27 | IndentWidth: '4'
28 | IndentWrappedFunctionNames: 'false'
29 | KeepEmptyLinesAtTheStartOfBlocks: 'false'
30 | MaxEmptyLinesToKeep: '1'
31 | NamespaceIndentation: None
32 | ObjCSpaceAfterProperty: 'true'
33 | ObjCSpaceBeforeProtocolList: 'true'
34 | PointerAlignment: Left
35 | SortIncludes: 'false'
36 | SpaceAfterCStyleCast: 'false'
37 | SpaceAfterTemplateKeyword: 'true'
38 | SpaceBeforeAssignmentOperators: 'true'
39 | SpaceBeforeParens: ControlStatements
40 | SpaceInEmptyParentheses: 'false'
41 | SpacesInAngles: 'false'
42 | SpacesInCStyleCastParentheses: 'false'
43 | SpacesInContainerLiterals: 'false'
44 | SpacesInParentheses: 'false'
45 | SpacesInSquareBrackets: 'false'
46 | TabWidth: '4'
47 | UseTab: ForIndentation
48 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Never mangle resource blob files
5 | *.blob -text
6 |
7 | # Custom for Visual Studio
8 | *.cs diff=csharp
9 | *.sln merge=union
10 | *.csproj merge=union
11 | *.vbproj merge=union
12 | *.fsproj merge=union
13 | *.dbproj merge=union
14 |
15 | # Standard to msysgit
16 | *.doc diff=astextplain
17 | *.DOC diff=astextplain
18 | *.docx diff=astextplain
19 | *.DOCX diff=astextplain
20 | *.dot diff=astextplain
21 | *.DOT diff=astextplain
22 | *.pdf diff=astextplain
23 | *.PDF diff=astextplain
24 | *.rtf diff=astextplain
25 | *.RTF diff=astextplain
26 |
27 | # Ignore build scripts in language stats
28 | build/* linguist-vendored
29 | configure.py linguist-vendored=true
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pydevproject
2 | .project
3 | .metadata
4 | .gitconfig
5 | bin/
6 | tmp/
7 | *.tmp
8 | *.bak
9 | *.swp
10 | *~.nib
11 | local.properties
12 | .classpath
13 | .settings/
14 | .loadpath
15 | .ninja*
16 | build.ninja
17 |
18 | # Generated version
19 | version.c
20 |
21 | # External tool builders
22 | .externalToolBuilders/
23 |
24 | # Locally stored "Eclipse launch configurations"
25 | *.launch
26 |
27 | # CDT-specific
28 | .cproject
29 |
30 | # PDT-specific
31 | .buildpath
32 |
33 | #Android local build files
34 | build/android/assets
35 | build/android/libs
36 |
37 | #Xcode build
38 | build/xcode/foundation/build
39 |
40 | #Doxygen generated
41 | doc/html
42 |
43 | #Coverity scan
44 | cov-int/
45 | cov-int.*
46 |
47 | #################
48 | ## Visual Studio
49 | #################
50 |
51 | ## Ignore Visual Studio temporary files, build results, and
52 | ## files generated by popular Visual Studio add-ons.
53 |
54 | # User-specific files
55 | *.suo
56 | *.user
57 | *.sln.docstates
58 | **/.vs
59 |
60 | # Build results
61 | [Dd]ebug/
62 | [Rr]elease/
63 | [Pp]rofile/
64 | [Dd]eploy/
65 | *_i.c
66 | *_p.c
67 | *.ilk
68 | *.meta
69 | *.obj
70 | *.pch
71 | *.pchi
72 | *.pdb
73 | *.pgc
74 | *.pgd
75 | *.rsp
76 | *.sbr
77 | *.tlb
78 | *.tli
79 | *.tlh
80 | *.tmp
81 | *.vspscc
82 | .builds
83 | *.dotCover
84 | *.lastbuildstate
85 | *.unsuccessfulbuild
86 | *.opendb
87 | *.vc
88 | *.VC.db
89 | *.db-shm
90 | *.db-wal
91 |
92 | ## TODO: If you have NuGet Package Restore enabled, uncomment this
93 | #packages/
94 |
95 | # Visual C++ cache files
96 | ipch/
97 | *.aps
98 | *.ncb
99 | *.opensdf
100 | *.sdf
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 |
106 | # ReSharper is a .NET coding add-in
107 | _ReSharper*
108 |
109 | # Installshield output folder
110 | [Ee]xpress
111 |
112 | # DocProject is a documentation generator add-in
113 | DocProject/buildhelp/
114 | DocProject/Help/*.HxT
115 | DocProject/Help/*.HxC
116 | DocProject/Help/*.hhc
117 | DocProject/Help/*.hhk
118 | DocProject/Help/*.hhp
119 | DocProject/Help/Html2
120 | DocProject/Help/html
121 |
122 | # Click-Once directory
123 | publish
124 |
125 | # Others
126 | [Bb]in
127 | [Oo]bj
128 | sql
129 | TestResults
130 | *.Cache
131 | ClientBin
132 | stylecop.*
133 | ~$*
134 | *.dbmdl
135 | Generated_Code #added for RIA/Silverlight projects
136 |
137 | # Backup & report files from converting an old project file to a newer
138 | # Visual Studio version. Backup files are not needed, because we have git ;-)
139 | _UpgradeReport_Files/
140 | Backup*/
141 | UpgradeLog*.XML
142 |
143 |
144 | ############
145 | ## Windows
146 | ############
147 |
148 | # Windows image file caches
149 | Thumbs.db
150 |
151 | # Folder config file
152 | Desktop.ini
153 |
154 |
155 | #############
156 | ## Python
157 | #############
158 |
159 | *.py[co]
160 |
161 | # Packages
162 | *.egg
163 | *.egg-info
164 | dist
165 | eggs
166 | parts
167 | var
168 | sdist
169 | develop-eggs
170 | .installed.cfg
171 |
172 | # Installer logs
173 | pip-log.txt
174 |
175 | # Unit test / coverage reports
176 | .coverage
177 | .tox
178 |
179 | #Translations
180 | *.mo
181 |
182 | #Mr Developer
183 | .mr.developer.cfg
184 |
185 | # Mac crap
186 | .DS_Store
187 |
188 |
189 | ###############
190 | ## Generic
191 | ###############
192 |
193 | #Project builds
194 | lib/**
195 | bin/**
196 | dist/**
197 | libs/**
198 |
199 | #Log files
200 | *.log
201 | *.tlog
202 |
203 | #Scons build
204 | .sconsign.dblite
205 | build/scons/debug*
206 | build/scons/release*
207 | build/scons/profi*
208 | build/scons/deploy*
209 |
210 | #Backups
211 | *~
212 |
213 | #Object files
214 | *.o
215 |
216 | #XCode
217 | xcuserdata
218 | *.xccheckout
219 |
220 | #SublimeText local workspace
221 | *.sublime-workspace
222 |
223 | #Never store keystores in version control!
224 | *.keystore
225 |
226 | #Do not store local build prefs
227 | build.json
228 | codesign.json
229 | coveralls.json
230 | coverallsreport.json
231 | codecov.json
232 | codecovreport.json
233 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Task Library - Public Domain
2 |
3 | This library provides a cross-platform library in C11 providing
4 | task-based parallellism for projects based on our foundation library.
5 |
6 | The latest source code maintained by Mattias Jansson is always available at
7 |
8 | https://github.com/mjansson/task_lib
9 |
10 | The foundation library source code maintained by Mattias Jansson is always available at
11 |
12 | https://github.com/mjansson/foundation_lib
13 |
14 | This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 |
16 |
--------------------------------------------------------------------------------
/build/msvc/build.default.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Deploy
10 | x64
11 |
12 |
13 | Profile
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | $(Platform)\$(Configuration)\$(ProjectName)\
23 | Unicode
24 | Sequential
25 |
26 |
27 |
28 | v143
29 |
30 |
31 |
32 |
33 | true
34 | false
35 |
36 |
37 | $(SolutionDir)..\..\bin\windows\debug\x86-64\
38 |
39 |
40 | $(SolutionDir)..\..\lib\windows\debug\x86-64\
41 |
42 |
43 |
44 |
45 | false
46 | true
47 | true
48 |
49 |
50 | $(SolutionDir)..\..\bin\windows\release\x86-64\
51 |
52 |
53 | $(SolutionDir)..\..\lib\windows\release\x86-64\
54 |
55 |
56 |
57 |
58 | false
59 | true
60 | true
61 |
62 |
63 | $(SolutionDir)..\..\bin\windows\deploy\x86-64\
64 |
65 |
66 | $(SolutionDir)..\..\lib\windows\deploy\x86-64\
67 |
68 |
69 |
70 |
71 | false
72 | true
73 | true
74 |
75 |
76 | $(SolutionDir)..\..\bin\windows\profile\x86-64\
77 |
78 |
79 | $(SolutionDir)..\..\lib\windows\profile\x86-64\
80 |
81 |
82 |
83 |
84 | false
85 | true
86 | true
87 |
88 |
89 |
90 |
91 |
92 | Level3
93 | $(ProjectDir)..\..;%(AdditionalIncludeDirectories)
94 | ProgramDatabase
95 | false
96 | false
97 | true
98 | true
99 | true
100 | false
101 | Default
102 | MultiThreaded
103 | false
104 | false
105 | AdvancedVectorExtensions2
106 | Fast
107 | false
108 | false
109 | false
110 | false
111 | false
112 | true
113 | SSE3
114 | true
115 | true
116 | true
117 | false
118 | stdc17
119 |
120 |
121 | Windows
122 | true
123 |
124 |
125 |
126 |
127 | opengl32.lib;gdi32.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies)
128 |
129 |
130 |
131 |
132 | opengl32.lib;gdi32.lib;iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies)
133 |
134 |
135 |
136 |
137 | BUILD_DEBUG=1;%(PreprocessorDefinitions)
138 | Disabled
139 | false
140 | false
141 | false
142 |
143 |
144 | $(SolutionDir)..\..\lib\windows;$(SolutionDir)..\..\lib\windows\debug\x86-64
145 |
146 |
147 |
148 |
149 | BUILD_RELEASE=1;%(PreprocessorDefinitions)
150 | ..\..
151 | MaxSpeed
152 | AnySuitable
153 | Speed
154 | true
155 | true
156 | false
157 |
158 |
159 | true
160 | true
161 | $(SolutionDir)..\..\lib\windows;$(SolutionDir)..\..\lib\windows\release\x86-64
162 |
163 |
164 |
165 |
166 | $(ProjectDir)..\..
167 | BUILD_DEPLOY=1;%(PreprocessorDefinitions)
168 | ..\..
169 | Full
170 | AnySuitable
171 | Speed
172 | true
173 | true
174 | true
175 |
176 |
177 | true
178 | true
179 | $(SolutionDir)..\..\lib\windows;$(SolutionDir)..\..\lib\windows\deploy\x86-64
180 |
181 |
182 |
183 |
184 | $(ProjectDir)..\..
185 | BUILD_PROFILE=1;%(PreprocessorDefinitions)
186 | Full
187 | AnySuitable
188 | Speed
189 | true
190 | true
191 | true
192 |
193 |
194 | true
195 | true
196 | $(SolutionDir)..\..\lib\windows;$(SolutionDir)..\..\lib\windows\profile\x86-64
197 |
198 |
199 |
--------------------------------------------------------------------------------
/build/msvc/task.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31903.59
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "task", "task.vcxproj", "{74B0104C-EBE1-43AD-8C05-9BA418830A92}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0BE9971B-A7EB-4B33-868E-BEDD2EC639A1}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "all", "test\all.vcxproj", "{793D1E99-B0BF-40E4-A5C3-947CD328787B}"
11 | EndProject
12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "task", "test\task.vcxproj", "{8B1675E7-5B85-4389-926E-91177C2F0794}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|x64 = Debug|x64
17 | Deploy|x64 = Deploy|x64
18 | Profile|x64 = Profile|x64
19 | Release|x64 = Release|x64
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}.Debug|x64.ActiveCfg = Debug|x64
23 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}.Debug|x64.Build.0 = Debug|x64
24 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}.Deploy|x64.ActiveCfg = Deploy|x64
25 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}.Deploy|x64.Build.0 = Deploy|x64
26 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}.Profile|x64.ActiveCfg = Profile|x64
27 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}.Profile|x64.Build.0 = Profile|x64
28 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}.Release|x64.ActiveCfg = Release|x64
29 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}.Release|x64.Build.0 = Release|x64
30 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}.Debug|x64.ActiveCfg = Debug|x64
31 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}.Debug|x64.Build.0 = Debug|x64
32 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}.Deploy|x64.ActiveCfg = Deploy|x64
33 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}.Deploy|x64.Build.0 = Deploy|x64
34 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}.Profile|x64.ActiveCfg = Profile|x64
35 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}.Profile|x64.Build.0 = Profile|x64
36 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}.Release|x64.ActiveCfg = Release|x64
37 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}.Release|x64.Build.0 = Release|x64
38 | {8B1675E7-5B85-4389-926E-91177C2F0794}.Debug|x64.ActiveCfg = Debug|x64
39 | {8B1675E7-5B85-4389-926E-91177C2F0794}.Debug|x64.Build.0 = Debug|x64
40 | {8B1675E7-5B85-4389-926E-91177C2F0794}.Deploy|x64.ActiveCfg = Deploy|x64
41 | {8B1675E7-5B85-4389-926E-91177C2F0794}.Deploy|x64.Build.0 = Deploy|x64
42 | {8B1675E7-5B85-4389-926E-91177C2F0794}.Profile|x64.ActiveCfg = Profile|x64
43 | {8B1675E7-5B85-4389-926E-91177C2F0794}.Profile|x64.Build.0 = Profile|x64
44 | {8B1675E7-5B85-4389-926E-91177C2F0794}.Release|x64.ActiveCfg = Release|x64
45 | {8B1675E7-5B85-4389-926E-91177C2F0794}.Release|x64.Build.0 = Release|x64
46 | EndGlobalSection
47 | GlobalSection(SolutionProperties) = preSolution
48 | HideSolutionNode = FALSE
49 | EndGlobalSection
50 | GlobalSection(NestedProjects) = preSolution
51 | {793D1E99-B0BF-40E4-A5C3-947CD328787B} = {0BE9971B-A7EB-4B33-868E-BEDD2EC639A1}
52 | {8B1675E7-5B85-4389-926E-91177C2F0794} = {0BE9971B-A7EB-4B33-868E-BEDD2EC639A1}
53 | EndGlobalSection
54 | GlobalSection(ExtensibilityGlobals) = postSolution
55 | SolutionGuid = {A890CD63-E921-4CED-8598-54FEDE9DBB04}
56 | EndGlobalSection
57 | EndGlobal
58 |
--------------------------------------------------------------------------------
/build/msvc/task.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Win32Proj
5 | task
6 | 10.0
7 | StaticLibrary
8 | {74B0104C-EBE1-43AD-8C05-9BA418830A92}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | $(ProjectDir)..\..\..\foundation;$(ProjectDir)..\..\..\foundation_lib;%(AdditionalIncludeDirectories)
38 | TASK_COMPILE=1;%(PreprocessorDefinitions)
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/build/msvc/test/all.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Win32Proj
5 | task
6 | 10.0
7 | Application
8 | {793D1E99-B0BF-40E4-A5C3-947CD328787B}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | test-$(ProjectName)
21 |
22 |
23 |
24 |
25 |
26 |
27 | $(ProjectDir)..\..\..;$(ProjectDir)..\..\..\test;$(ProjectDir)..\..\..\..\foundation;$(ProjectDir)..\..\..\..\foundation_lib;$(ProjectDir)..\..\..\..\foundation\test;$(ProjectDir)..\..\..\..\foundation_lib\test;%(AdditionalIncludeDirectories)
28 |
29 |
30 | Console
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/build/msvc/test/task.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Win32Proj
5 | task
6 | 10.0
7 | Application
8 | {8B1675E7-5B85-4389-926E-91177C2F0794}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | test-$(ProjectName)
21 |
22 |
23 |
24 |
25 |
26 |
27 | {74b0104c-ebe1-43ad-8c05-9ba418830a92}
28 |
29 |
30 |
31 |
32 | $(ProjectDir)..\..\..;$(ProjectDir)..\..\..\test;$(ProjectDir)..\..\..\..\foundation;$(ProjectDir)..\..\..\..\foundation_lib;$(ProjectDir)..\..\..\..\foundation\test;$(ProjectDir)..\..\..\..\foundation_lib\test;%(AdditionalIncludeDirectories)
33 |
34 |
35 | Console
36 | test.lib;foundation.lib;%(AdditionalDependencies)
37 |
38 |
39 |
40 |
41 | $(ProjectDir)..\..\..\..\foundation_lib\lib\windows\debug\x86-64
42 | false
43 |
44 |
45 |
46 |
47 | $(ProjectDir)..\..\..\..\foundation_lib\lib\windows\release\x86-64
48 | false
49 |
50 |
51 |
52 |
53 | $(ProjectDir)..\..\..\..\foundation_lib\lib\windows\profile\x86-64
54 |
55 |
56 |
57 |
58 | $(ProjectDir)..\..\..\..\foundation_lib\lib\windows\deploy\x86-64
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/build/ninja/android.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Ninja toolchain abstraction for Android platform"""
4 |
5 | import os
6 | import subprocess
7 |
8 | import toolchain
9 |
10 | def make_target(toolchain, host, target):
11 | return Android(toolchain, host, target)
12 |
13 | class Android(object):
14 | def __init__(self, toolchain, host, target):
15 | self.host = host
16 |
17 | if host.is_windows():
18 | self.exe_suffix = '.exe'
19 | else:
20 | self.exe_suffix = ''
21 |
22 | self.javaccmd = toolchain.mkdircmd('$outpath') + ' && $javac -d $outpath -classpath $outpath -sourcepath $sourcepath -target 1.5 -bootclasspath $androidjar -g -source 1.5 -Xlint:-options $in'
23 | self.dexcmd = '$dex --dex --output $out $in'
24 | self.aaptcmd = toolchain.cdcmd('$apkbuildpath') + ' && $aapt p -f -m -M AndroidManifest.xml -F $apk -I $androidjar -S res --debug-mode --no-crunch -J gen $aaptflags'
25 | self.aaptdeploycmd = toolchain.cdcmd('$apkbuildpath') + ' && $aapt c -S res -C bin/res && $aapt p -f -m -M AndroidManifest.xml -F $apk -I $androidjar -S bin/res -S res -J gen $aaptflags'
26 | self.aaptaddcmd = toolchain.cdcmd('$apkbuildpath') + ' && ' + toolchain.copycmd('$apksource', '$apk' ) + ' && $aapt a $apk $apkaddfiles'
27 | self.zipcmd = '$zip -r -9 $out $in $implicitin'
28 | self.zipaligncmd = '$zipalign -f 4 $in $out'
29 | self.codesigncmd = 'build/ninja/codesign.py --target $target --prefs codesign.json --zipfile $in --config $config --jarsigner $jarsigner $out'
30 |
31 | if host.is_windows():
32 | self.codesigncmd = 'python ' + self.codesigncmd
33 |
34 | def initialize_toolchain(self):
35 | self.ndkpath = os.getenv('NDK_HOME', '')
36 | self.sdkpath = os.getenv('ANDROID_HOME', '')
37 | self.sysroot = ''
38 | self.platformversion = '21'
39 | self.gcc_toolchainversion = '4.9'
40 | self.javasdk = ''
41 |
42 | self.archname = dict()
43 | self.archname['x86'] = 'x86'
44 | self.archname['x86-64'] = 'x86_64'
45 | self.archname['arm6'] = 'arm'
46 | self.archname['arm7'] = 'arm'
47 | self.archname['arm64'] = 'arm64'
48 | self.archname['mips'] = 'mips'
49 | self.archname['mips64'] = 'mips64'
50 |
51 | self.archpath = dict()
52 | self.archpath['x86'] = 'x86'
53 | self.archpath['x86-64'] = 'x86-64'
54 | self.archpath['arm6'] = 'armeabi'
55 | self.archpath['arm7'] = 'armeabi-v7a'
56 | self.archpath['arm64'] = 'arm64-v8a'
57 | self.archpath['mips'] = 'mips'
58 | self.archpath['mips64'] = 'mips64'
59 |
60 | self.gcc_toolchainname = dict()
61 | self.gcc_toolchainname['x86'] = 'x86-' + self.gcc_toolchainversion
62 | self.gcc_toolchainname['x86-64'] = 'x86_64-' + self.gcc_toolchainversion
63 | self.gcc_toolchainname['arm6'] = 'arm-linux-androideabi-' + self.gcc_toolchainversion
64 | self.gcc_toolchainname['arm7'] = 'arm-linux-androideabi-' + self.gcc_toolchainversion
65 | self.gcc_toolchainname['arm64'] = 'aarch64-linux-android-' + self.gcc_toolchainversion
66 | self.gcc_toolchainname['mips'] = 'mipsel-linux-android-' + self.gcc_toolchainversion
67 | self.gcc_toolchainname['mips64'] = 'mips64el-linux-android-' + self.gcc_toolchainversion
68 |
69 | self.gcc_toolchainprefix = dict()
70 | self.gcc_toolchainprefix['x86'] = 'i686-linux-android-'
71 | self.gcc_toolchainprefix['x86-64'] = 'x86_64-linux-android-'
72 | self.gcc_toolchainprefix['arm6'] = 'arm-linux-androideabi-'
73 | self.gcc_toolchainprefix['arm7'] = 'arm-linux-androideabi-'
74 | self.gcc_toolchainprefix['arm64'] = 'aarch64-linux-android-'
75 | self.gcc_toolchainprefix['mips'] = 'mipsel-linux-android-'
76 | self.gcc_toolchainprefix['mips64'] = 'mips64el-linux-android-'
77 |
78 | if self.host.is_windows():
79 | if os.getenv('PROCESSOR_ARCHITECTURE', 'AMD64').find('64') != -1:
80 | self.hostarchname = 'windows-x86_64'
81 | else:
82 | self.hostarchname = 'windows-x86'
83 | elif self.host.is_linux():
84 | localarch = toolchain.check_output(['uname', '-m'])
85 | if localarch == 'x86_64':
86 | self.hostarchname = 'linux-x86_64'
87 | else:
88 | self.hostarchname = 'linux-x86'
89 | elif self.host.is_macos():
90 | self.hostarchname = 'darwin-x86_64'
91 |
92 | def build_toolchain(self):
93 | buildtools_path = os.path.join(self.sdkpath, 'build-tools')
94 | buildtools_list = [item for item in os.listdir(buildtools_path) if os.path.isdir(os.path.join(buildtools_path, item))]
95 | buildtools_list.sort(key = lambda s: map(int, s.split('-')[0].split('.')))
96 |
97 | self.buildtools_path = os.path.join(self.sdkpath, 'build-tools', buildtools_list[-1])
98 | self.android_jar = os.path.join(self.sdkpath, 'platforms', 'android-' + self.platformversion, 'android.jar')
99 |
100 | self.javac = 'javac'
101 | self.jarsigner = 'jarsigner'
102 | if self.javasdk != '':
103 | self.javac = os.path.join(self.javasdk, 'bin', self.javac)
104 | self.jarsigner = os.path.join(self.javasdk, 'bin', self.jarsigner)
105 | if self.host.is_windows():
106 | self.dex = os.path.join(self.buildtools_path, 'dx.bat')
107 | else:
108 | self.dex = os.path.join(self.buildtools_path, 'dx' + self.exe_suffix)
109 | if not os.path.isfile(self.dex):
110 | self.dex = os.path.join(self.sdkpath, 'tools', 'dx' + self.exe_suffix)
111 | self.aapt = os.path.join(self.buildtools_path, 'aapt' + self.exe_suffix)
112 | self.zipalign = os.path.join(self.buildtools_path, 'zipalign' + self.exe_suffix)
113 | if not os.path.isfile( self.zipalign ):
114 | self.zipalign = os.path.join(self.sdkpath, 'tools', 'zipalign' + self.exe_suffix)
115 |
116 | def parse_prefs(self, prefs):
117 | if 'android' in prefs:
118 | androidprefs = prefs['android']
119 | if 'ndkpath' in androidprefs:
120 | self.ndkpath = os.path.expanduser(androidprefs['ndkpath'])
121 | if 'sdkpath' in androidprefs:
122 | self.sdkpath = os.path.expanduser(androidprefs['sdkpath'])
123 | if 'platformversion' in androidprefs:
124 | self.platformversion = androidprefs['platformversion']
125 | if 'gccversion' in androidprefs:
126 | self.gcc_toolchainversion = androidprefs['gccversion']
127 | if 'javasdk' in androidprefs:
128 | self.javasdk = androidprefs['javasdk']
129 |
130 | def write_variables(self, writer):
131 | writer.variable('ndk', self.ndkpath)
132 | writer.variable('sdk', self.sdkpath)
133 | writer.variable('sysroot', self.sysroot)
134 | writer.variable('androidjar', self.android_jar )
135 | writer.variable('apkbuildpath', '')
136 | writer.variable('apk', '')
137 | writer.variable('apksource', '')
138 | writer.variable('apkaddfiles', '')
139 | writer.variable('javac', self.javac)
140 | writer.variable('dex', self.dex)
141 | writer.variable('aapt', self.aapt)
142 | writer.variable('zipalign', self.zipalign)
143 | writer.variable('jarsigner', self.jarsigner)
144 | writer.variable('aaptflags', '')
145 |
146 | def write_rules(self, writer):
147 | writer.rule('aapt', command = self.aaptcmd, description = 'AAPT $out')
148 | writer.rule('aaptdeploy', command = self.aaptdeploycmd, description = 'AAPT $out')
149 | writer.rule('aaptadd', command = self.aaptaddcmd, description = 'AAPT $out')
150 | writer.rule('javac', command = self.javaccmd, description = 'JAVAC $in')
151 | writer.rule('dex', command = self.dexcmd, description = 'DEX $out')
152 | writer.rule('zip', command = self.zipcmd, description = 'ZIP $out')
153 | writer.rule('zipalign', command = self.zipaligncmd, description = 'ZIPALIGN $out')
154 | writer.rule('codesign', command = self.codesigncmd, description = 'CODESIGN $out')
155 |
156 | def make_sysroot_path(self, arch):
157 | return os.path.join(self.ndkpath, 'platforms', 'android-' + self.platformversion, 'arch-' + self.archname[arch])
158 |
159 | def make_gcc_toolchain_path(self, arch):
160 | return os.path.join(self.ndkpath, 'toolchains', self.gcc_toolchainname[arch], 'prebuilt', self.hostarchname)
161 |
162 | def make_gcc_bin_path(self, arch):
163 | return os.path.join(self.make_gcc_toolchain_path(arch), 'bin', self.gcc_toolchainprefix[arch])
164 |
165 | def archname(self):
166 | return self.archname
167 |
168 | def archpath(self):
169 | return self.archpath
170 |
171 | def hostarchname(self):
172 | return self.hostarchname
173 |
174 | def apk(self, toolchain, writer, module, archbins, javasources, outpath, binname, basepath, config, implicit_deps, resources):
175 | buildpath = os.path.join('$buildpath', config, 'apk', binname)
176 | baseapkname = binname + ".base.apk"
177 | unsignedapkname = binname + ".unsigned.apk"
178 | unalignedapkname = binname + ".unaligned.apk"
179 | apkname = binname + ".apk"
180 | apkfiles = []
181 | libfiles = []
182 | locallibs = []
183 | resfiles = []
184 | manifestfile = []
185 |
186 | writer.comment('Make APK')
187 | for _, value in archbins.iteritems():
188 | for archbin in value:
189 | archpair = os.path.split(archbin)
190 | libname = archpair[1]
191 | arch = os.path.split(archpair[0])[1]
192 | locallibpath = os.path.join('lib', self.archpath[arch], libname)
193 | archpath = os.path.join(buildpath, locallibpath)
194 | locallibs += [locallibpath + ' ']
195 | libfiles += toolchain.copy(writer, archbin, archpath)
196 | for resource in resources:
197 | filename = os.path.split(resource)[1]
198 | if filename == 'AndroidManifest.xml':
199 | manifestfile = toolchain.copy(writer, os.path.join(basepath, module, resource), os.path.join(buildpath, 'AndroidManifest.xml'))
200 | else:
201 | restype = os.path.split(os.path.split(resource)[0])[1]
202 | if restype == 'asset':
203 | pass #todo: implement
204 | else:
205 | resfiles += toolchain.copy(writer, os.path.join(basepath, module, resource), os.path.join(buildpath, 'res', restype, filename))
206 |
207 | #Make directories
208 | gendir = toolchain.mkdir(writer, os.path.join(buildpath, 'gen'))
209 | bindir = toolchain.mkdir(writer, os.path.join(buildpath, 'bin'))
210 | binresdir = toolchain.mkdir(writer, os.path.join(buildpath, 'bin', 'res'), order_only = bindir)
211 | alldirs = gendir + bindir + binresdir
212 |
213 | aaptvars = [('apkbuildpath', buildpath), ('apk', baseapkname)]
214 | aaptout = os.path.join(buildpath, baseapkname)
215 | if config == 'deploy':
216 | baseapkfile = writer.build(aaptout, 'aaptdeploy', manifestfile, variables = aaptvars, implicit = manifestfile + resfiles, order_only = alldirs)
217 | else:
218 | baseapkfile = writer.build(aaptout, 'aapt', manifestfile, variables = aaptvars, implicit = manifestfile + resfiles, order_only = alldirs)
219 |
220 | #Compile java code
221 | javafiles = []
222 | localjava = []
223 | if javasources != []:
224 | #self.javaccmd = '$javac -d $outpath -classpath $outpath -sourcepath $sourcepath -target 1.5 -bootclasspath $androidjar -g -source 1.5 -Xlint:-options $in'
225 | #self.dexcmd = '$dex --dex --output $out $in'
226 | javasourcepath = '.'
227 | if self.host.is_windows():
228 | javasourcepath += ';'
229 | else:
230 | javasourcepath += ':'
231 | javasourcepath += os.path.join(buildpath, 'gen')
232 | classpath = os.path.join(buildpath, 'classes')
233 | javavars = [('outpath', classpath), ('sourcepath', javasourcepath)]
234 | javaclasses = writer.build(classpath, 'javac', javasources, variables = javavars, implicit = baseapkfile)
235 | localjava += ['classes.dex']
236 | javafiles += writer.build(os.path.join(buildpath, 'classes.dex'), 'dex', classpath)
237 |
238 | #Add native libraries and java classes to apk
239 | aaptvars = [('apkbuildpath', buildpath), ('apk', unsignedapkname), ('apksource', baseapkname), ('apkaddfiles', toolchain.paths_forward_slash(locallibs + localjava))]
240 | unsignedapkfile = writer.build(os.path.join(buildpath, unsignedapkname), 'aaptadd', baseapkfile, variables = aaptvars, implicit = libfiles + javafiles, order_only = alldirs)
241 |
242 | #Sign the APK
243 | codesignvars = [('config', config)]
244 | unalignedapkfile = writer.build(os.path.join(buildpath, unalignedapkname), 'codesign', unsignedapkfile, variables = codesignvars)
245 |
246 | #Run zipalign
247 | outfile = writer.build(os.path.join(outpath, config, apkname), 'zipalign', unalignedapkfile)
248 | return outfile
249 |
--------------------------------------------------------------------------------
/build/ninja/codesign.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Codesign utility"""
4 |
5 | import argparse
6 | import subprocess
7 | import os
8 | import time
9 | import shutil
10 | import json
11 |
12 | parser = argparse.ArgumentParser(description = 'Codesign utility for Ninja builds')
13 | parser.add_argument('file', type=str,
14 | help = 'Bundle/package to sign')
15 | parser.add_argument('--target', type=str,
16 | help = 'Target',
17 | choices = ['macos', 'ios', 'android'],
18 | default = '')
19 | parser.add_argument('--bundle', type=str,
20 | help = 'Bundle identifier (OSX/iOS)',
21 | default = '')
22 | parser.add_argument('--organisation', type=str,
23 | help = 'Organisation identifier (OSX/iOS)',
24 | default = '')
25 | parser.add_argument('--provisioning', type=str,
26 | help = 'Provisioning profile (OSX/iOS)',
27 | default = '')
28 | parser.add_argument('--builddir', type=str,
29 | help = 'Build directory (OSX/iOS)',
30 | default = '')
31 | parser.add_argument('--binname', type=str,
32 | help = 'Binary name (OSX/iOS)',
33 | default = '')
34 | parser.add_argument('--zipfile', type=str,
35 | help = 'Zip file (Android)',
36 | default = '')
37 | parser.add_argument('--tsacert', type=str,
38 | help = 'TSA cert (Android)',
39 | default = '')
40 | parser.add_argument('--tsa', type=str,
41 | help = 'TSA (Android)',
42 | default = '')
43 | parser.add_argument('--keystore', type=str,
44 | help = 'Keystore (Android)',
45 | default = '')
46 | parser.add_argument('--keystorepass', type=str,
47 | help = 'Keystore password (Android)',
48 | default = '')
49 | parser.add_argument('--keyalias', type=str,
50 | help = 'Key alias (Android)',
51 | default = '')
52 | parser.add_argument('--keypass', type=str,
53 | help = 'Key password (Android)',
54 | default = '')
55 | parser.add_argument('--jarsigner', type=str,
56 | help = 'JAR signer (Android)',
57 | default = 'jarsigner')
58 | parser.add_argument('--prefs', type=str,
59 | help = 'Preferences file',
60 | default = '')
61 | parser.add_argument('--config', type=str,
62 | help = 'Build configuration',
63 | default = '')
64 | parser.add_argument('--entitlements', type=str,
65 | help = 'Entitlements file',
66 | default = '')
67 | options = parser.parse_args()
68 |
69 | androidprefs = {}
70 | iosprefs = {}
71 | macosprefs = {}
72 |
73 |
74 | def parse_prefs( prefsfile ):
75 | global androidprefs
76 | global iosprefs
77 | global macosprefs
78 | if not os.path.isfile( prefsfile ):
79 | return
80 | file = open( prefsfile, 'r' )
81 | prefs = json.load( file )
82 | file.close()
83 | if 'android' in prefs:
84 | androidprefs = prefs['android']
85 | if 'ios' in prefs:
86 | iosprefs = prefs['ios']
87 | if 'macos' in prefs:
88 | macosprefs = prefs['macos']
89 |
90 |
91 | def codesign_ios():
92 | if not 'organisation' in iosprefs:
93 | iosprefs['organisation'] = options.organisation
94 | if not 'bundleidentifier' in iosprefs:
95 | iosprefs['bundleidentifier'] = options.bundle
96 | if not 'provisioning' in iosprefs:
97 | iosprefs['provisioning'] = options.provisioning
98 |
99 | sdkdir = subprocess.check_output( [ 'xcrun', '--sdk', 'iphoneos', '--show-sdk-path' ] ).decode().strip().splitlines()[-1]
100 | entitlements = os.path.join( sdkdir, 'Entitlements.plist' )
101 | plistpath = os.path.join( options.builddir, 'Entitlements.xcent' )
102 |
103 | platformpath = subprocess.check_output( [ 'xcrun', '--sdk', 'iphoneos', '--show-sdk-platform-path' ] ).decode().strip().splitlines()[-1]
104 | localpath = platformpath + "/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"
105 | plutil = "PATH=" + localpath + " " + subprocess.check_output( [ 'xcrun', '--sdk', 'iphoneos', '-f', 'plutil' ] ).decode().strip().splitlines()[-1]
106 |
107 | shutil.copyfile( entitlements, plistpath )
108 | os.system( plutil + ' -convert xml1 ' + plistpath )
109 |
110 | f = open( plistpath, 'r' )
111 | lines = [ line.strip( '\n\r' ) for line in f ]
112 | f.close()
113 |
114 | for i in range( 0, len( lines ) ):
115 | if lines[i].find( '$(AppIdentifierPrefix)' ) != -1:
116 | lines[i] = lines[i].replace( '$(AppIdentifierPrefix)', iosprefs['organisation'] + '.' )
117 | if lines[i].find( '$(CFBundleIdentifier)' ) != -1:
118 | lines[i] = lines[i].replace( '$(CFBundleIdentifier)', iosprefs['bundleidentifier'] )
119 | if lines[i].find( '$(binname)' ) != -1:
120 | lines[i] = lines[i].replace( '$(binname)', options.binname )
121 |
122 | with open( plistpath, 'w' ) as plist_file:
123 | for line in lines:
124 | if options.config != 'deploy' and line == '':
125 | plist_file.write( '\tget-task-allow\n' )
126 | plist_file.write( '\t\n' )
127 | plist_file.write( line + '\n' )
128 | plist_file.close()
129 |
130 | if os.path.isfile( os.path.join( options.file, '_CodeSignature', 'CodeResources' ) ):
131 | os.remove( os.path.join( options.file, '_CodeSignature', 'CodeResources' ) )
132 |
133 | os.system( '/usr/bin/codesign --force --sign "' + iosprefs['signature'] + '" --entitlements ' + plistpath + ' ' + options.file )
134 |
135 | if os.path.isfile( os.path.join( options.file, '_CodeSignature', 'CodeResources' ) ):
136 | os.utime( os.path.join( options.file, '_CodeSignature', 'CodeResources' ), None )
137 | os.utime( os.path.join( options.file, '_CodeSignature' ), None )
138 | os.utime( options.file, None )
139 |
140 |
141 | def codesign_macos():
142 | if not 'organisation' in macosprefs:
143 | macosprefs['organisation'] = options.organisation
144 | if not 'bundleidentifier' in macosprefs:
145 | macosprefs['bundleidentifier'] = options.bundle
146 | if not 'provisioning' in macosprefs:
147 | macosprefs['provisioning'] = options.provisioning
148 | if not 'entitlements' in macosprefs:
149 | macosprefs['entitlements'] = options.entitlements
150 |
151 | codesign_allocate = subprocess.check_output( [ 'xcrun', '--sdk', 'macosx', '-f', 'codesign_allocate' ] ).decode().strip().splitlines()[-1]
152 | sdkdir = subprocess.check_output( [ 'xcrun', '--sdk', 'macosx', '--show-sdk-path' ] ).decode().strip().splitlines()[-1]
153 | entitlements = os.path.join( sdkdir, 'Entitlements.plist' )
154 |
155 | if os.path.isfile( os.path.join( options.file, 'Contents', '_CodeSignature', 'CodeResources' ) ):
156 | os.remove( os.path.join( options.file, 'Contents', '_CodeSignature', 'CodeResources' ) )
157 |
158 | if 'signature' in macosprefs:
159 | command = 'export CODESIGN_ALLOCATE=' + codesign_allocate + '; /usr/bin/codesign --force --sign "' + macosprefs['signature'] + '" -o runtime '
160 | if ('entitlements' in macosprefs) and (macosprefs['entitlements'] != '') and (macosprefs['entitlements'] != 'none'):
161 | command = command + '--entitlements ' + macosprefs['entitlements'] + ' --generate-entitlement-der '
162 | command = command + options.file
163 | # print(command)
164 | os.system(command)
165 |
166 | if os.path.isfile( os.path.join( options.file, 'Contents', '_CodeSignature', 'CodeResources' ) ):
167 | os.utime( os.path.join( options.file, 'Contents', '_CodeSignature', 'CodeResources' ), None )
168 | os.utime( os.path.join( options.file, 'Contents', '_CodeSignature' ), None )
169 | os.utime( os.path.join( options.file, 'Contents' ), None )
170 | os.utime( options.file, None )
171 |
172 |
173 | def codesign_android():
174 | if not 'tsacert' in androidprefs:
175 | androidprefs['tsacert'] = options.tsacert
176 | if not 'tsa' in androidprefs:
177 | androidprefs['tsa'] = options.tsa
178 | if not 'keystore' in androidprefs:
179 | androidprefs['keystore'] = options.keystore
180 | if not 'keystorepass' in androidprefs:
181 | androidprefs['keystorepass'] = options.keystorepass
182 | if not 'keyalias' in androidprefs:
183 | androidprefs['keyalias'] = options.keyalias
184 | if not 'keypass' in androidprefs:
185 | androidprefs['keypass'] = options.keypass
186 | if not 'jarsigner' in androidprefs:
187 | androidprefs['jarsigner'] = options.jarsigner
188 |
189 | timestamp = ''
190 | if androidprefs['tsacert'] != '':
191 | timestamp = '-tsacert ' + androidprefs['tsacert']
192 | elif androidprefs['tsa'] != '':
193 | timestamp = '-tsa ' + androidprefs['tsa']
194 |
195 | proxy = ''
196 | if 'proxy' in androidprefs and androidprefs['proxy'] != '' and androidprefs['proxy'] != 'None':
197 | proxy = androidprefs['proxy']
198 | if proxy != '' and proxy != 'None':
199 | defstr = "-J-Dhttp.proxy"
200 | url = urlparse.urlparse(proxy)
201 | if url.scheme == 'https':
202 | defstr = "-J-Dhttps.proxy"
203 | host = url.netloc
204 | port = ''
205 | username = ''
206 | password = ''
207 | if '@' in host:
208 | username, host = host.split(':', 1)
209 | password, host = host.split('@', 1)
210 | if ':' in host:
211 | host, port = host.split(':', 1)
212 | proxy = defstr + "Host=" + host
213 | if port != '':
214 | proxy += " " + defstr + "Port=" + port
215 | if username != '':
216 | proxy += " " + defstr + "User=" + username
217 | if password != '':
218 | proxy += " " + defstr + "Password=" + password
219 |
220 | signcmd = androidprefs['jarsigner'] + ' ' + timestamp + ' -sigalg SHA1withRSA -digestalg SHA1 -keystore ' + androidprefs['keystore'] + ' -storepass ' + androidprefs['keystorepass'] + ' -keypass ' + androidprefs['keypass'] + ' -signedjar ' + options.file + ' ' + options.zipfile + ' ' + androidprefs['keyalias'] + ' ' + proxy
221 | os.system(signcmd)
222 |
223 |
224 | parse_prefs( options.prefs )
225 |
226 | if options.target == 'ios':
227 | codesign_ios()
228 | elif options.target == 'macos':
229 | codesign_macos()
230 | elif options.target == 'android':
231 | codesign_android()
232 |
--------------------------------------------------------------------------------
/build/ninja/gcc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Ninja toolchain abstraction for GCC compiler suite"""
4 |
5 | import os
6 |
7 | import toolchain
8 |
9 | class GCCToolchain(toolchain.Toolchain):
10 |
11 | def initialize(self, project, archs, configs, includepaths, dependlibs, libpaths, variables, subninja):
12 | #Local variable defaults
13 | self.toolchain = ''
14 | self.includepaths = []
15 | self.libpaths = libpaths
16 | self.ccompiler = os.environ.get('CC') or 'gcc'
17 | self.cxxcompiler = os.environ.get('CXX') or 'g++'
18 | self.archiver = os.environ.get('AR') or 'ar'
19 | self.linker = os.environ.get('CC') or 'gcc'
20 | self.cxxlinker = os.environ.get('CXX') or 'g++'
21 |
22 | #Command definitions
23 | self.cccmd = '$toolchain$cc -MMD -MT $out -MF $out.d $includepaths $moreincludepaths $cflags $carchflags $cconfigflags $cmoreflags $cenvflags -c $in -o $out'
24 | self.cxxcmd = '$toolchain$cxx -MMD -MT $out -MF $out.d $includepaths $moreincludepaths $cxxflags $carchflags $cconfigflags $cmoreflags $cxxenvflags -c $in -o $out'
25 | self.ccdeps = 'gcc'
26 | self.ccdepfile = '$out.d'
27 | self.arcmd = self.rmcmd('$out') + ' && $toolchain$ar crsD $ararchflags $arflags $arenvflags $out $in'
28 | self.linkcmd = '$toolchain$link $libpaths $configlibpaths $linkflags $linkarchflags $linkconfigflags $linkenvflags -o $out $in $libs $archlibs $oslibs'
29 |
30 | #Base flags
31 | self.cflags = ['-D' + project.upper() + '_COMPILE=1',
32 | '-funit-at-a-time', '-fstrict-aliasing',
33 | '-fno-math-errno','-ffinite-math-only', '-funsafe-math-optimizations',
34 | '-fno-trapping-math', '-ffast-math']
35 | self.cwarnflags = ['-Wextra', '-Wall', '-Werror']
36 | self.cmoreflags = []
37 | self.mflags = []
38 | self.arflags = []
39 | self.linkflags = []
40 | self.oslibs = []
41 |
42 | self.initialize_subninja(subninja)
43 | self.initialize_archs(archs)
44 | self.initialize_configs(configs)
45 | self.initialize_project(project)
46 | self.initialize_toolchain()
47 | self.initialize_depends(dependlibs)
48 |
49 | self.parse_default_variables(variables)
50 | self.read_build_prefs()
51 |
52 | if self.target.is_linux() or self.target.is_bsd() or self.target.is_raspberrypi() or self.target.is_sunos():
53 | self.cflags += ['-D_GNU_SOURCE=1']
54 | self.linkflags += ['-pthread']
55 | if self.target.is_linux() or self.target.is_raspberrypi():
56 | self.oslibs += ['dl']
57 | if self.target.is_raspberrypi():
58 | self.linkflags += ['-latomic']
59 | if self.target.is_bsd():
60 | self.oslibs += ['execinfo']
61 | if self.target.is_haiku():
62 | self.cflags += ['-D_GNU_SOURCE=1']
63 | self.linkflags += ['-lpthread']
64 |
65 | self.includepaths = self.prefix_includepaths((includepaths or []) + ['.'])
66 |
67 | if self.is_monolithic():
68 | self.cflags += ['-DBUILD_MONOLITHIC=1']
69 | if self.use_coverage():
70 | self.cflags += ['--coverage']
71 | self.linkflags += ['--coverage']
72 |
73 | if not 'nowarning' in variables or not variables['nowarning']:
74 | self.cflags += self.cwarnflags
75 | self.cxxflags = list(self.cflags)
76 |
77 | self.cflags += ['-std=c11']
78 | if self.target.is_macos() or self.target.is_ios():
79 | self.cxxflags += ['-std=c++14', '-stdlib=libc++']
80 | else:
81 | self.cxxflags += ['-std=gnu++14']
82 |
83 | #Overrides
84 | self.objext = '.o'
85 |
86 | #Builders
87 | self.builders['c'] = self.builder_cc
88 | self.builders['cc'] = self.builder_cxx
89 | self.builders['cpp'] = self.builder_cxx
90 | self.builders['lib'] = self.builder_lib
91 | self.builders['multilib'] = self.builder_multicopy
92 | self.builders['sharedlib'] = self.builder_sharedlib
93 | self.builders['multisharedlib'] = self.builder_multicopy
94 | self.builders['bin'] = self.builder_bin
95 | self.builders['multibin'] = self.builder_multicopy
96 |
97 | #Setup target platform
98 | self.build_target_toolchain(self.target)
99 |
100 | def name(self):
101 | return 'gcc'
102 |
103 | def parse_prefs(self, prefs):
104 | super(GCCToolchain, self).parse_prefs(prefs)
105 | if 'gcc' in prefs:
106 | gccprefs = prefs['gcc']
107 | if 'toolchain' in gccprefs:
108 | self.toolchain = gccprefs['toolchain']
109 | if os.path.split(self.toolchain)[1] != 'bin':
110 | self.toolchain = os.path.join(self.toolchain, 'bin')
111 |
112 | def write_variables(self, writer):
113 | super(GCCToolchain, self).write_variables(writer)
114 | writer.variable('toolchain', self.toolchain)
115 | writer.variable('cc', self.ccompiler)
116 | writer.variable('cxx', self.cxxcompiler)
117 | writer.variable('ar', self.archiver)
118 | writer.variable('link', self.linker)
119 | writer.variable('includepaths', self.make_includepaths(self.includepaths))
120 | writer.variable('moreincludepaths', '')
121 | writer.variable('cflags', self.cflags)
122 | writer.variable('cxxflags', self.cxxflags)
123 | writer.variable('carchflags', '')
124 | writer.variable('cconfigflags', '')
125 | writer.variable('cmoreflags', self.cmoreflags)
126 | writer.variable('cenvflags', (os.environ.get('CFLAGS') or '').split())
127 | writer.variable('cxxenvflags', (os.environ.get('CXXFLAGS') or '').split())
128 | writer.variable('arflags', self.arflags)
129 | writer.variable('ararchflags', '')
130 | writer.variable('arconfigflags', '')
131 | writer.variable('arenvflags', (os.environ.get('ARFLAGS') or '').split())
132 | writer.variable('linkflags', self.linkflags)
133 | writer.variable('linkarchflags', '')
134 | writer.variable('linkconfigflags', '')
135 | writer.variable('linkenvflags', (os.environ.get('LDFLAGS') or '').split())
136 | writer.variable('libs', '')
137 | writer.variable('libpaths', self.make_libpaths(self.libpaths))
138 | writer.variable('configlibpaths', '')
139 | writer.variable('archlibs', '')
140 | writer.variable('oslibs', self.make_libs(self.oslibs))
141 | writer.newline()
142 |
143 | def write_rules(self, writer):
144 | super(GCCToolchain, self).write_rules(writer)
145 | writer.rule('cc', command = self.cccmd, depfile = self.ccdepfile, deps = self.ccdeps, description = 'CC $in')
146 | writer.rule('cxx', command = self.cxxcmd, depfile = self.ccdepfile, deps = self.ccdeps, description = 'CXX $in')
147 | writer.rule('ar', command = self.arcmd, description = 'LIB $out')
148 | writer.rule('link', command = self.linkcmd, description = 'LINK $out')
149 | writer.rule('so', command = self.linkcmd, description = 'SO $out')
150 | writer.newline()
151 |
152 | def build_target_toolchain(self, target):
153 | if target.is_windows():
154 | self.build_windows_toolchain()
155 | if self.toolchain != '' and not self.toolchain.endswith('/') and not self.toolchain.endswith('\\'):
156 | self.toolchain += os.sep
157 |
158 | def build_windows_toolchain(self):
159 | self.cflags += ['-U__STRICT_ANSI__']
160 | self.oslibs = ['kernel32', 'user32', 'shell32', 'advapi32']
161 |
162 | def make_includepath(self, path):
163 | if os.path.isabs(path) or self.subninja == '':
164 | return self.path_escape(path)
165 | if path == '.':
166 | return self.path_escape(self.subninja)
167 | return self.path_escape(os.path.join(self.subninja, path))
168 |
169 | def make_includepaths(self, includepaths):
170 | if not includepaths is None:
171 | return ['-I' + self.make_includepath(path) for path in list(includepaths)]
172 | return []
173 |
174 | def make_libpath(self, path):
175 | return self.path_escape(path)
176 |
177 | def make_libpaths(self, libpaths):
178 | if not libpaths is None:
179 | return ['-L' + self.make_libpath(path) for path in libpaths]
180 | return []
181 |
182 | def make_targetarchflags(self, arch, targettype):
183 | flags = []
184 | if arch == 'x86':
185 | flags += ['-m32']
186 | elif arch == 'x86-64':
187 | flags += ['-m64']
188 | return flags
189 |
190 | def make_carchflags(self, arch, targettype):
191 | flags = []
192 | if targettype == 'sharedlib':
193 | flags += ['-DBUILD_DYNAMIC_LINK=1']
194 | if self.target.is_linux() or self.target.is_bsd() or self.target.is_sunos():
195 | flags += ['-fPIC']
196 | flags += self.make_targetarchflags(arch, targettype)
197 | return flags
198 |
199 | def make_cconfigflags(self, config, targettype):
200 | flags = []
201 | if config == 'debug':
202 | flags += ['-DBUILD_DEBUG=1', '-g']
203 | elif config == 'release':
204 | flags += ['-DBUILD_RELEASE=1', '-O3', '-g', '-funroll-loops']
205 | elif config == 'profile':
206 | flags += ['-DBUILD_PROFILE=1', '-O3', '-g', '-funroll-loops']
207 | elif config == 'deploy':
208 | flags += ['-DBUILD_DEPLOY=1', '-O3', '-g', '-funroll-loops']
209 | return flags
210 |
211 | def make_ararchflags(self, arch, targettype):
212 | flags = []
213 | return flags
214 |
215 | def make_arconfigflags(self, config, targettype):
216 | flags = []
217 | return flags
218 |
219 | def make_linkarchflags(self, arch, targettype):
220 | flags = []
221 | flags += self.make_targetarchflags(arch, targettype)
222 | return flags
223 |
224 | def make_linkconfigflags(self, config, targettype):
225 | flags = []
226 | if self.target.is_windows():
227 | if targettype == 'sharedlib':
228 | flags += ['-Xlinker', '/DLL']
229 | elif targettype == 'bin':
230 | flags += ['-Xlinker', '/SUBSYSTEM:CONSOLE']
231 | elif self.target.is_macos() or self.target.is_ios():
232 | if targettype == 'sharedlib' or targettype == 'multisharedlib':
233 | flags += ['-dynamiclib']
234 | else:
235 | if targettype == 'sharedlib':
236 | flags += ['-shared']
237 | return flags
238 |
239 | def make_libs(self, libs):
240 | if libs != None:
241 | return ['-l' + lib for lib in libs]
242 | return []
243 |
244 | def make_configlibpaths(self, config, arch, extralibpaths):
245 | libpaths = [
246 | self.libpath,
247 | os.path.join(self.libpath, arch),
248 | os.path.join(self.libpath, config),
249 | os.path.join(self.libpath, config, arch)
250 | ]
251 | if extralibpaths != None:
252 | libpaths += [os.path.join(libpath, self.libpath) for libpath in extralibpaths]
253 | libpaths += [os.path.join(libpath, self.libpath, arch) for libpath in extralibpaths]
254 | libpaths += [os.path.join(libpath, self.libpath, config) for libpath in extralibpaths]
255 | libpaths += [os.path.join(libpath, self.libpath, config, arch) for libpath in extralibpaths]
256 | return self.make_libpaths(libpaths)
257 |
258 | def cc_variables(self, config, arch, targettype, variables):
259 | localvariables = []
260 | if 'includepaths' in variables:
261 | moreincludepaths = self.make_includepaths(variables['includepaths'])
262 | if not moreincludepaths == []:
263 | localvariables += [('moreincludepaths', moreincludepaths)]
264 | carchflags = self.make_carchflags(arch, targettype)
265 | if carchflags != []:
266 | localvariables += [('carchflags', carchflags)]
267 | cconfigflags = self.make_cconfigflags(config, targettype)
268 | if cconfigflags != []:
269 | localvariables += [('cconfigflags', cconfigflags)]
270 | if 'defines' in variables:
271 | localvariables += [('cmoreflags', ['-D' + define for define in variables['defines']])]
272 | return localvariables
273 |
274 | def ar_variables(self, config, arch, targettype, variables):
275 | localvariables = []
276 | ararchflags = self.make_ararchflags(arch, targettype)
277 | if ararchflags != []:
278 | localvariables += [('ararchflags', ararchflags)]
279 | arconfigflags = self.make_arconfigflags(config, targettype)
280 | if arconfigflags != []:
281 | localvariables += [('arconfigflags', arconfigflags)]
282 | return localvariables
283 |
284 | def link_variables(self, config, arch, targettype, variables):
285 | localvariables = []
286 | linkarchflags = self.make_linkarchflags(arch, targettype)
287 | if linkarchflags != []:
288 | localvariables += [('linkarchflags', linkarchflags)]
289 | linkconfigflags = self.make_linkconfigflags(config, targettype)
290 | if linkconfigflags != []:
291 | localvariables += [('linkconfigflags', linkconfigflags)]
292 | if 'libs' in variables:
293 | libvar = self.make_libs(variables['libs'])
294 | if libvar != []:
295 | localvariables += [('libs', libvar)]
296 | libpaths = []
297 | if 'libpaths' in variables:
298 | libpaths = variables['libpaths']
299 | localvariables += [('configlibpaths', self.make_configlibpaths(config, arch, libpaths))]
300 |
301 | if 'runtime' in variables and variables['runtime'] == 'c++':
302 | localvariables += [('link', self.cxxlinker)]
303 |
304 | return localvariables
305 |
306 | def builder_cc(self, writer, config, arch, targettype, infile, outfile, variables):
307 | return writer.build(outfile, 'cc', infile, implicit = self.implicit_deps(config, variables), variables = self.cc_variables(config, arch, targettype, variables))
308 |
309 | def builder_cxx(self, writer, config, arch, targettype, infile, outfile, variables):
310 | return writer.build(outfile, 'cxx', infile, implicit = self.implicit_deps(config, variables), variables = self.cc_variables(config, arch, targettype, variables))
311 |
312 | def builder_lib(self, writer, config, arch, targettype, infiles, outfile, variables):
313 | return writer.build(outfile, 'ar', infiles, implicit = self.implicit_deps(config, variables), variables = self.ar_variables(config, arch, targettype, variables))
314 |
315 | def builder_sharedlib(self, writer, config, arch, targettype, infiles, outfile, variables):
316 | return writer.build(outfile, 'so', infiles, implicit = self.implicit_deps(config, variables), variables = self.link_variables(config, arch, targettype, variables))
317 |
318 | def builder_bin(self, writer, config, arch, targettype, infiles, outfile, variables):
319 | return writer.build(outfile, 'link', infiles, implicit = self.implicit_deps(config, variables), variables = self.link_variables(config, arch, targettype, variables))
320 |
321 | def create(host, target, toolchain):
322 | return GCCToolchain(host, target, toolchain)
323 |
--------------------------------------------------------------------------------
/build/ninja/generator.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Ninja build generator"""
4 |
5 | import argparse
6 | import os
7 | import pipes
8 | import sys
9 |
10 | import platform
11 | import toolchain
12 | import syntax
13 |
14 | class Generator(object):
15 | def __init__(self, project, includepaths = [], dependlibs = [], libpaths = [], variables = None):
16 | parser = argparse.ArgumentParser(description = 'Ninja build generator')
17 | parser.add_argument('-t', '--target',
18 | help = 'Target platform',
19 | choices = platform.supported_platforms())
20 | parser.add_argument('--host',
21 | help = 'Host platform',
22 | choices = platform.supported_platforms())
23 | parser.add_argument('--toolchain',
24 | help = 'Toolchain to use',
25 | choices = toolchain.supported_toolchains())
26 | parser.add_argument('-c', '--config', action = 'append',
27 | help = 'Build configuration',
28 | choices = ['debug', 'release', 'profile', 'deploy'],
29 | default = [])
30 | parser.add_argument('-a', '--arch', action = 'append',
31 | help = 'Add architecture',
32 | choices = toolchain.supported_architectures(),
33 | default = [])
34 | parser.add_argument('-i', '--includepath', action = 'append',
35 | help = 'Add include path',
36 | default = [])
37 | parser.add_argument('--monolithic', action='store_true',
38 | help = 'Build monolithic test suite',
39 | default = False)
40 | parser.add_argument('--coverage', action='store_true',
41 | help = 'Build with code coverage',
42 | default = False)
43 | parser.add_argument('--subninja', action='store',
44 | help = 'Build as subproject (exclude rules and pools) with the given subpath',
45 | default = '')
46 | parser.add_argument('--notests', action='store_true',
47 | help = 'Skip building the internal tests',
48 | default = False)
49 | parser.add_argument('--buildprefs', action='store',
50 | help = 'Read the given build preferences file',
51 | default = '')
52 | parser.add_argument('--updatebuild', action='store_true',
53 | help = 'Update submodule build scripts',
54 | default = '')
55 | parser.add_argument('--lto', action='store_true',
56 | help = 'Build with Link Time Optimization',
57 | default = False)
58 | options = parser.parse_args()
59 |
60 | self.project = project
61 | self.target = platform.Platform(options.target)
62 | self.host = platform.Platform(options.host)
63 | self.subninja = options.subninja
64 | self.notests = options.notests
65 | archs = options.arch
66 | configs = options.config
67 | if includepaths is None:
68 | includepaths = []
69 | if not options.includepath is None:
70 | includepaths += options.includepath
71 |
72 | buildfile = open('build.ninja', 'w')
73 | self.writer = syntax.Writer(buildfile)
74 |
75 | self.writer.variable('ninja_required_version', '1.3')
76 | self.writer.newline()
77 |
78 | self.writer.comment('configure.py arguments')
79 | self.writer.variable('configure_args', ' '.join(sys.argv[1:]))
80 | self.writer.newline()
81 |
82 | self.writer.comment('configure options')
83 | self.writer.variable('configure_target', self.target.platform)
84 | self.writer.variable('configure_host', self.host.platform)
85 |
86 | env_keys = set(['CC', 'AR', 'LINK', 'CFLAGS', 'ARFLAGS', 'LINKFLAGS'])
87 | configure_env = dict((key, os.environ[key]) for key in os.environ if key in env_keys)
88 | if configure_env:
89 | config_str = ' '.join([key + '=' + pipes.quote(configure_env[key]) for key in configure_env])
90 | self.writer.variable('configure_env', config_str + '$ ')
91 |
92 | if variables is None:
93 | variables = {}
94 | if not isinstance(variables, dict):
95 | variables = dict(variables)
96 |
97 | if options.monolithic:
98 | variables['monolithic'] = True
99 | if options.coverage:
100 | variables['coverage'] = True
101 | if options.lto:
102 | variables['lto'] = True
103 | if self.subninja != '':
104 | variables['internal_deps'] = True
105 |
106 | self.toolchain = toolchain.make_toolchain(self.host, self.target, options.toolchain)
107 | self.toolchain.buildprefs = options.buildprefs
108 | self.toolchain.initialize(project, archs, configs, includepaths, dependlibs, libpaths, variables, self.subninja)
109 |
110 | self.writer.variable('configure_toolchain', self.toolchain.name())
111 | self.writer.variable('configure_archs', archs)
112 | self.writer.variable('configure_configs', configs)
113 | self.writer.newline()
114 |
115 | self.toolchain.write_variables(self.writer)
116 | if self.subninja == '':
117 | self.toolchain.write_rules(self.writer)
118 |
119 | def target(self):
120 | return self.target
121 |
122 | def host(self):
123 | return self.host
124 |
125 | def toolchain(self):
126 | return self.toolchain
127 |
128 | def writer(self):
129 | return self.writer
130 |
131 | def is_subninja(self):
132 | return self.subninja != ''
133 |
134 | def skip_tests(self):
135 | return self.notests
136 |
137 | def lib(self, module, sources, libname = None, basepath = None, configs = None, includepaths = None, variables = None):
138 | return self.toolchain.lib(self.writer, module, sources, libname, basepath, configs, includepaths, variables)
139 |
140 | def sharedlib(self, module, sources, libname = None, basepath = None, configs = None, includepaths = None, libpaths = None, implicit_deps = None, dependlibs = None, libs = None, frameworks = None, variables = None):
141 | return self.toolchain.sharedlib(self.writer, module, sources, libname, basepath, configs, includepaths, libpaths, implicit_deps, dependlibs, libs, frameworks, variables)
142 |
143 | def bin(self, module, sources, binname, basepath = None, configs = None, includepaths = None, libpaths = None, implicit_deps = None, dependlibs = None, libs = None, frameworks = None, variables = None):
144 | return self.toolchain.bin(self.writer, module, sources, binname, basepath, configs, includepaths, libpaths, implicit_deps, dependlibs, libs, frameworks, variables)
145 |
146 | def app(self, module, sources, binname, basepath = None, configs = None, includepaths = None, libpaths = None, implicit_deps = None, dependlibs = None, libs = None, frameworks = None, variables = None, resources = None):
147 | return self.toolchain.app(self.writer, module, sources, binname, basepath, configs, includepaths, libpaths, implicit_deps, dependlibs, libs, frameworks, variables, resources)
148 |
149 | def test_includepaths(self):
150 | #TODO: This is ugly
151 | if self.project == "foundation":
152 | return ['test']
153 | foundation_path = os.path.join('..', 'foundation_lib')
154 | if not os.path.isfile(os.path.join(foundation_path, 'foundation', 'foundation.h')):
155 | foundation_path = os.path.join('..', 'foundation')
156 | return ['test', os.path.join(foundation_path, 'test')]
157 |
158 | def test_monolithic(self):
159 | return self.toolchain.is_monolithic()
160 |
--------------------------------------------------------------------------------
/build/ninja/platform.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | """Ninja platform abstraction"""
4 |
5 | import sys
6 |
7 | def supported_platforms():
8 | return [ 'windows', 'linux', 'macos', 'bsd', 'ios', 'android', 'raspberrypi', 'tizen', 'sunos', 'haiku' ]
9 |
10 | class Platform(object):
11 | def __init__(self, platform):
12 | self.platform = platform
13 | if self.platform is None:
14 | self.platform = sys.platform
15 | if self.platform.startswith('linux'):
16 | self.platform = 'linux'
17 | elif self.platform.startswith('darwin'):
18 | self.platform = 'macos'
19 | elif self.platform.startswith('macos'):
20 | self.platform = 'macos'
21 | elif self.platform.startswith('win'):
22 | self.platform = 'windows'
23 | elif 'bsd' in self.platform or self.platform.startswith('dragonfly'):
24 | self.platform = 'bsd'
25 | elif self.platform.startswith('ios'):
26 | self.platform = 'ios'
27 | elif self.platform.startswith('android'):
28 | self.platform = 'android'
29 | elif self.platform.startswith('raspberry'):
30 | self.platform = 'raspberrypi'
31 | elif self.platform.startswith('tizen'):
32 | self.platform = 'tizen'
33 | elif self.platform.startswith('sunos'):
34 | self.platform = 'sunos'
35 | elif self.platform.startswith('haiku'):
36 | self.platform = 'haiku'
37 |
38 | def platform(self):
39 | return self.platform
40 |
41 | def is_linux(self):
42 | return self.platform == 'linux'
43 |
44 | def is_windows(self):
45 | return self.platform == 'windows'
46 |
47 | def is_macos(self):
48 | return self.platform == 'macos'
49 |
50 | def is_bsd(self):
51 | return self.platform == 'bsd'
52 |
53 | def is_ios(self):
54 | return self.platform == 'ios'
55 |
56 | def is_android(self):
57 | return self.platform == 'android'
58 |
59 | def is_raspberrypi(self):
60 | return self.platform == 'raspberrypi'
61 |
62 | def is_tizen(self):
63 | return self.platform == 'tizen'
64 |
65 | def is_sunos(self):
66 | return self.platform == 'sunos'
67 |
68 | def is_haiku(self):
69 | return self.platform == 'haiku'
70 |
71 | def get(self):
72 | return self.platform
73 |
--------------------------------------------------------------------------------
/build/ninja/plist.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """PList utility"""
4 |
5 | import argparse
6 | import os
7 | import subprocess
8 | import re
9 | import unicodedata
10 |
11 | def normalize_char(c):
12 | try:
13 | UNICODE_EXISTS = bool(type(unicode))
14 | except NameError:
15 | unicode = lambda s: str(s)
16 | try:
17 | cname = unicodedata.name( unicode(c) )
18 | cname = cname[:cname.index( ' WITH' )]
19 | return unicodedata.lookup( cname )
20 | except ( ValueError, KeyError ):
21 | return c
22 |
23 | def normalize_string(s):
24 | return ''.join( normalize_char(c) for c in s )
25 |
26 | def replace_var( str, var, val ):
27 | if str.find( '$(' + var + ')' ) != -1:
28 | return str.replace( '$(' + var + ')', val )
29 | if str.find( '${' + var + '}' ) != -1:
30 | return str.replace( '${' + var + '}', val )
31 | return str
32 |
33 |
34 | parser = argparse.ArgumentParser( description = 'PList utility for Ninja builds' )
35 | parser.add_argument( 'files',
36 | metavar = 'file', type=open, nargs='+',
37 | help = 'Source plist file' )
38 | parser.add_argument( '--exename', type=str,
39 | help = 'Executable name',
40 | default = [] )
41 | parser.add_argument( '--prodname', type=str,
42 | help = 'Product name',
43 | default = [] )
44 | parser.add_argument( '--bundle', type=str,
45 | help = 'Bundle identifier',
46 | default = [] )
47 | parser.add_argument( '--output', type=str,
48 | help = 'Output path',
49 | default = [] )
50 | parser.add_argument( '--target', type=str,
51 | help = 'Target OS',
52 | default = [] )
53 | parser.add_argument( '--deploymenttarget', type=str,
54 | help = 'Target OS version',
55 | default = [] )
56 | options = parser.parse_args()
57 |
58 | if not options.exename:
59 | options.exename = 'unknown'
60 | if not options.prodname:
61 | options.prodname = 'unknown'
62 | if not options.target:
63 | options.target = 'macos'
64 | if not options.deploymenttarget:
65 | if options.target == 'macos':
66 | options.deploymenttarget = '12.0'
67 | else:
68 | options.deploymenttarget = '10.0'
69 |
70 | buildversion = subprocess.check_output( [ 'sw_vers', '-buildVersion' ] ).decode().strip()
71 |
72 | #Merge input plists using first file as base
73 | lines = []
74 | for f in options.files:
75 | _, extension = os.path.splitext(f.name)
76 | if extension != '.plist':
77 | continue
78 | if lines == []:
79 | lines += [ line.strip( '\n\r' ) for line in f ]
80 | else:
81 | mergelines = [ line.strip( '\n\r' ) for line in f ]
82 | for i in range( 0, len( mergelines ) ):
83 | if re.match( '^$', mergelines[i] ):
84 | break
85 | if re.match( '^$', mergelines[i] ):
86 | for j in range( 0, len( lines ) ):
87 | if re.match( '^$', lines[j] ):
88 | for k in range( i+1, len( mergelines ) ):
89 | if re.match( '^$', mergelines[k] ):
90 | break
91 | lines.insert( j+(k-(i+1)), mergelines[k] )
92 | break
93 | break
94 |
95 | #Parse input plist to get package type and signature
96 | bundle_package_type = 'APPL'
97 | bundle_signature = '????'
98 |
99 | for i in range( 0, len( lines ) ):
100 | if 'CFBundlePackageType' in lines[i]:
101 | match = re.match( '^.*>(.*)<.*$', lines[i+1] )
102 | if match:
103 | bundle_package_type = match.group(1)
104 | if 'CFBundleSignature' in lines[i]:
105 | match = re.match( '^.*>(.*)<.*$', lines[i+1] )
106 | if match:
107 | bundle_signature = match.group(1)
108 |
109 | #Write package type and signature to PkgInfo in output path
110 | with open( os.path.join( os.path.dirname( options.output ), 'PkgInfo' ), 'w' ) as pkginfo_file:
111 | pkginfo_file.write( bundle_package_type + bundle_signature )
112 | pkginfo_file.close()
113 |
114 | #insert os version
115 | for i in range( 0, len( lines ) ):
116 | if re.match( '^$', lines[i] ):
117 | lines.insert( i+1, '\tBuildMachineOSBuild' )
118 | lines.insert( i+2, '\t' + buildversion + '' )
119 | break
120 |
121 | #replace build variables name
122 | for i in range( 0, len( lines ) ):
123 | lines[i] = replace_var( lines[i], 'EXECUTABLE_NAME', options.exename )
124 | lines[i] = replace_var( lines[i], 'PRODUCT_NAME', options.prodname )
125 | lines[i] = replace_var( lines[i], 'PRODUCT_NAME:rfc1034identifier', normalize_string( options.exename ).lower() )
126 | lines[i] = replace_var( lines[i], 'PRODUCT_NAME:c99extidentifier', normalize_string( options.exename ).lower().replace( '-', '_' ).replace( '.', '_' ) )
127 | lines[i] = replace_var( lines[i], 'IOS_DEPLOYMENT_TARGET', options.deploymenttarget )
128 | lines[i] = replace_var( lines[i], 'MACOSX_DEPLOYMENT_TARGET', options.deploymenttarget )
129 |
130 | #replace bundle identifier if given
131 | if not options.bundle is None and options.bundle != '':
132 | for i in range( 0, len( lines ) ):
133 | if lines[i].find( 'CFBundleIdentifier' ) != -1:
134 | lines[i+1] = '\t' + normalize_string( options.bundle ) + ''
135 | break
136 |
137 | #add supported platform, minimum os version and requirements
138 | if options.target == 'ios':
139 | for i in range( 0, len( lines ) ):
140 | if 'CFBundleSignature' in lines[i]:
141 | lines.insert( i+2, '\tCFBundleSupportedPlatforms' )
142 | lines.insert( i+3, '\t' )
143 | lines.insert( i+4, '\t\tiPhoneOS' )
144 | lines.insert( i+5, '\t' )
145 | lines.insert( i+6, '\tMinimumOSVersion' )
146 | lines.insert( i+7, '\t6.0' )
147 | lines.insert( i+8, '\tUIDeviceFamily' )
148 | lines.insert( i+9, '\t' )
149 | lines.insert( i+10, '\t\t1' )
150 | lines.insert( i+11, '\t\t2' )
151 | lines.insert( i+12, '\t' )
152 | break
153 |
154 | #add build info
155 | #DTCompiler
156 | #com.apple.compilers.llvm.clang.1_0
157 | #DTPlatformBuild
158 | #12B411
159 | #DTPlatformName
160 | #iphoneos
161 | #DTPlatformVersion
162 | #8.1
163 | #DTSDKBuild
164 | #12B411
165 | #DTSDKName
166 | #iphoneos8.1
167 | #DTXcode
168 | #0611
169 | #DTXcodeBuild
170 | #6A2008a
171 |
172 | #write final Info.plist in output path
173 | with open( options.output, 'w' ) as plist_file:
174 | for line in lines:
175 | #print lines[i]
176 | plist_file.write( line + '\n' )
177 | plist_file.close()
178 |
179 | #run plutil -convert binary1
180 | sdk = 'iphoneos'
181 | platformpath = subprocess.check_output( [ 'xcrun', '--sdk', sdk, '--show-sdk-platform-path' ] ).decode().strip()
182 | localpath = platformpath + "/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"
183 | plutil = "PATH=" + localpath + " " + subprocess.check_output( [ 'xcrun', '--sdk', sdk, '-f', 'plutil' ] ).decode().strip()
184 | plcommand = plutil + ' -convert binary1 ' + options.output
185 | os.system( plcommand )
186 |
--------------------------------------------------------------------------------
/build/ninja/syntax.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | """Python module for generating .ninja files.
4 |
5 | Note that this is emphatically not a required piece of Ninja; it's
6 | just a helpful utility for build-file-generation systems that already
7 | use Python.
8 | """
9 |
10 | import textwrap
11 |
12 | def escape_path(word):
13 | return word.replace('$ ', '$$ ').replace(' ', '$ ').replace(':', '$:')
14 |
15 | class Writer(object):
16 | def __init__(self, output, width=78):
17 | self.output = output
18 | self.width = width
19 |
20 | def newline(self):
21 | self.output.write('\n')
22 |
23 | def comment(self, text):
24 | for line in textwrap.wrap(text, self.width - 2):
25 | self.output.write('# ' + line + '\n')
26 |
27 | def variable(self, key, value, indent=0):
28 | if value is None:
29 | return
30 | if isinstance(value, list):
31 | value = ' '.join(filter(None, value)) # Filter out empty strings.
32 | self._line('%s = %s' % (key, value), indent)
33 |
34 | def pool(self, name, depth):
35 | self._line('pool %s' % name)
36 | self.variable('depth', depth, indent=1)
37 |
38 | def rule(self, name, command, description=None, depfile=None,
39 | generator=False, pool=None, restat=False, rspfile=None,
40 | rspfile_content=None, deps=None):
41 | self._line('rule %s' % name)
42 | self.variable('command', command, indent=1)
43 | if description:
44 | self.variable('description', description, indent=1)
45 | if depfile:
46 | self.variable('depfile', depfile, indent=1)
47 | if generator:
48 | self.variable('generator', '1', indent=1)
49 | if pool:
50 | self.variable('pool', pool, indent=1)
51 | if restat:
52 | self.variable('restat', '1', indent=1)
53 | if rspfile:
54 | self.variable('rspfile', rspfile, indent=1)
55 | if rspfile_content:
56 | self.variable('rspfile_content', rspfile_content, indent=1)
57 | if deps:
58 | self.variable('deps', deps, indent=1)
59 |
60 | def build(self, outputs, rule, inputs=None, implicit=None, order_only=None,
61 | variables=None):
62 | outputs = self._as_list(outputs)
63 | out_outputs = [escape_path(x) for x in outputs]
64 | all_inputs = [escape_path(x) for x in self._as_list(inputs)]
65 |
66 | if implicit:
67 | implicit = [escape_path(x) for x in self._as_list(implicit)]
68 | all_inputs.append('|')
69 | all_inputs.extend(implicit)
70 | if order_only:
71 | order_only = [escape_path(x) for x in self._as_list(order_only)]
72 | all_inputs.append('||')
73 | all_inputs.extend(order_only)
74 |
75 | self._line('build %s: %s' % (' '.join(out_outputs),
76 | ' '.join([rule] + all_inputs)))
77 |
78 | if variables:
79 | if isinstance(variables, dict):
80 | iterator = iter(variables.items())
81 | else:
82 | iterator = iter(variables)
83 |
84 | for key, val in iterator:
85 | self.variable(key, val, indent=1)
86 |
87 | return outputs
88 |
89 | def include(self, path):
90 | self._line('include %s' % path)
91 |
92 | def subninja(self, path):
93 | self._line('subninja %s' % path)
94 |
95 | def default(self, paths):
96 | self._line('default %s' % ' '.join(self._as_list(paths)))
97 |
98 | def _count_dollars_before_index(self, s, i):
99 | """Returns the number of '$' characters right in front of s[i]."""
100 | dollar_count = 0
101 | dollar_index = i - 1
102 | while dollar_index > 0 and s[dollar_index] == '$':
103 | dollar_count += 1
104 | dollar_index -= 1
105 | return dollar_count
106 |
107 | def _line(self, text, indent=0):
108 | """Write 'text' word-wrapped at self.width characters."""
109 | leading_space = ' ' * indent
110 | while len(leading_space) + len(text) > self.width:
111 | # The text is too wide; wrap if possible.
112 |
113 | # Find the rightmost space that would obey our width constraint and
114 | # that's not an escaped space.
115 | available_space = self.width - len(leading_space) - len(' $')
116 | space = available_space
117 | while True:
118 | space = text.rfind(' ', 0, space)
119 | if (space < 0 or
120 | self._count_dollars_before_index(text, space) % 2 == 0):
121 | break
122 |
123 | if space < 0:
124 | # No such space; just use the first unescaped space we can find.
125 | space = available_space - 1
126 | while True:
127 | space = text.find(' ', space + 1)
128 | if (space < 0 or
129 | self._count_dollars_before_index(text, space) % 2 == 0):
130 | break
131 | if space < 0:
132 | # Give up on breaking.
133 | break
134 |
135 | self.output.write(leading_space + text[0:space] + ' $\n')
136 | text = text[space+1:]
137 |
138 | # Subsequent lines are continuations, so indent them.
139 | leading_space = ' ' * (indent+2)
140 |
141 | self.output.write(leading_space + text + '\n')
142 |
143 | def _as_list(self, input):
144 | if input is None:
145 | return []
146 | if isinstance(input, list):
147 | return input
148 | return [input]
149 |
150 |
151 | def escape(string):
152 | """Escape a string such that it can be embedded into a Ninja file without
153 | further interpretation."""
154 | assert '\n' not in string, 'Ninja syntax does not allow newlines'
155 | # We only have one special metacharacter: '$'.
156 | return string.replace('$', '$$')
157 |
--------------------------------------------------------------------------------
/build/ninja/version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Version utility"""
4 |
5 | import subprocess
6 | import os
7 | import sys
8 |
9 | def generate_version_string(libname):
10 |
11 | version_numbers = []
12 | tokens = []
13 |
14 | gitcmd = 'git'
15 | if sys.platform.startswith('win'):
16 | gitcmd = 'git.exe'
17 | try:
18 | git_version = subprocess.check_output( [ gitcmd, 'describe', '--tags', '--long' ], stderr = subprocess.STDOUT ).strip()
19 | tokens = git_version.decode().split( '-' )
20 | version_numbers = tokens[0].split( '.' )
21 | except Exception:
22 | pass
23 |
24 | version_major = "0"
25 | version_minor = "0"
26 | version_revision = "1"
27 | version_build = "0"
28 | version_scm = "0"
29 |
30 | if version_numbers and len( version_numbers ) > 2:
31 | version_major = version_numbers[0]
32 | version_minor = version_numbers[1]
33 | version_revision = version_numbers[2]
34 |
35 | if tokens and len( tokens ) > 2:
36 | version_build = tokens[1]
37 | version_scm = tokens[2][1:]
38 |
39 | module = ""
40 | if not libname == "foundation":
41 | module = "_module"
42 |
43 | source = """/* ****** AUTOMATICALLY GENERATED, DO NOT EDIT ******
44 | This file is generated from the git describe command.
45 | Run the configure script to regenerate this file */
46 |
47 | #include
48 | #include <""" + libname + "/" + libname + """.h>
49 |
50 | version_t
51 | """ + libname + module + """_version(void) {
52 | """
53 | source += " return version_make(" + version_major + ", " + version_minor + ", " + version_revision + ", " + version_build + ", 0x" + version_scm + ");\n}\n"
54 | return source
55 |
56 | def read_version_string(input_path):
57 | try:
58 | file = open( os.path.join( input_path, 'version.c' ), "r" )
59 | str = file.read()
60 | file.close()
61 | except IOError:
62 | str = ""
63 | return str
64 |
65 | def write_version_string(output_path, str):
66 | file = open( os.path.join( output_path, 'version.c' ), "w" )
67 | file.write( str )
68 | file.close
69 |
70 | def generate_version(libname, output_path):
71 | generated = generate_version_string(libname)
72 | if generated == None:
73 | return
74 | previous = read_version_string(output_path)
75 |
76 | if generated != previous:
77 | write_version_string(output_path, generated)
78 |
79 | if __name__ == "__main__":
80 | generate_version(sys.argv[1], sys.argv[2])
81 |
--------------------------------------------------------------------------------
/build/ninja/vslocate.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Locate Visual Studio installations with Visual Studio Setup Configuration utility DLL"""
4 |
5 | import os
6 | import ctypes
7 |
8 | def get_vs_installations():
9 |
10 | class ISetupInstanceVTable(ctypes.Structure):
11 | """Class matching VisualStudio Setup package ISetupInstance vtable"""
12 | pass
13 |
14 | class ISetupInstance(ctypes.Structure):
15 | """COM interface for ISetupInstance"""
16 | _fields_ = [('vtable', ctypes.POINTER(ISetupInstanceVTable))]
17 |
18 | class IEnumSetupInstancesVTable(ctypes.Structure):
19 | """Class matching VisualStudio Setup package IEnumSetupInstances vtable"""
20 | pass
21 |
22 | class IEnumSetupInstances(ctypes.Structure):
23 | """COM interface for IEnumSetupInstances"""
24 | _fields_ = [('vtable', ctypes.POINTER(IEnumSetupInstancesVTable))]
25 |
26 | class ISetupConfigurationVTable(ctypes.Structure):
27 | """Class matching VisualStudio Setup package ISetupConfiguration vtable"""
28 | pass
29 |
30 | class ISetupConfiguration(ctypes.Structure):
31 | """COM interface for ISetupConfiguration"""
32 | _fields_ = [('vtable', ctypes.POINTER(ISetupConfigurationVTable))]
33 |
34 | proto_get_installation_path = ctypes.WINFUNCTYPE(
35 | ctypes.c_int,
36 | ctypes.POINTER(ISetupInstance),
37 | ctypes.POINTER(ctypes.c_wchar_p))
38 |
39 | proto_get_installation_version = ctypes.WINFUNCTYPE(
40 | ctypes.c_int,
41 | ctypes.POINTER(ISetupInstance),
42 | ctypes.POINTER(ctypes.c_wchar_p))
43 |
44 | ISetupInstanceVTable._fields_ = (
45 | ('QueryInterface', ctypes.c_void_p),
46 | ('AddRef', ctypes.c_void_p),
47 | ('Release', ctypes.c_void_p),
48 | ('GetInstanceId', ctypes.c_void_p),
49 | ('GetInstallDate', ctypes.c_void_p),
50 | ('GetInstallationName', ctypes.c_void_p),
51 | ('GetInstallationPath', proto_get_installation_path),
52 | ('GetInstallationVersion', proto_get_installation_version),
53 | ('GetDisplayName', ctypes.c_void_p),
54 | ('GetDescription', ctypes.c_void_p),
55 | ('ResolvePath', ctypes.c_void_p))
56 |
57 | proto_next = ctypes.WINFUNCTYPE(
58 | ctypes.c_int,
59 | ctypes.POINTER(IEnumSetupInstances),
60 | ctypes.c_int,
61 | ctypes.POINTER(ctypes.POINTER(ISetupInstance)),
62 | ctypes.POINTER(ctypes.c_int))
63 |
64 | IEnumSetupInstancesVTable._fields_ = (
65 | ('QueryInterface', ctypes.c_void_p),
66 | ('AddRef', ctypes.c_void_p),
67 | ('Release', ctypes.c_void_p),
68 | ('Next', proto_next),
69 | ('Skip', ctypes.c_void_p),
70 | ('Reset', ctypes.c_void_p),
71 | ('Clone', ctypes.c_void_p))
72 |
73 | proto_enum_instances = ctypes.WINFUNCTYPE(
74 | ctypes.c_int,
75 | ctypes.POINTER(ISetupConfiguration),
76 | ctypes.POINTER(ctypes.POINTER(IEnumSetupInstances)))
77 |
78 | ISetupConfigurationVTable._fields_ = (
79 | ('QueryInterface', ctypes.c_void_p),
80 | ('AddRef', ctypes.c_void_p),
81 | ('Release', ctypes.c_void_p),
82 | ('EnumInstances', proto_enum_instances),
83 | ('GetInstanceForCurrentProcess', ctypes.c_void_p),
84 | ('GetInstanceForPath', ctypes.c_void_p))
85 |
86 | proto_get_setup_configuration = ctypes.WINFUNCTYPE(
87 | ctypes.c_int,
88 | ctypes.POINTER(ctypes.POINTER(ISetupConfiguration)),
89 | ctypes.c_void_p)
90 |
91 | installations = []
92 | dll = None
93 |
94 | dll_path = os.path.expandvars("$ProgramData\\Microsoft\\VisualStudio\\Setup\\x64\\Microsoft.VisualStudio.Setup.Configuration.Native.dll")
95 | try:
96 | dll = ctypes.WinDLL(dll_path)
97 | except OSError as e:
98 | #print("Failed to load Visual Studio setup configuration DLL: " + str(e))
99 | return installations
100 |
101 | params_get_setup_configuration = (1, "configuration", 0), (1, "reserved", 0),
102 |
103 | get_setup_configuration = proto_get_setup_configuration(("GetSetupConfiguration", dll), params_get_setup_configuration)
104 |
105 | configuration = ctypes.POINTER(ISetupConfiguration)()
106 | reserved = ctypes.c_void_p(0)
107 |
108 | result = get_setup_configuration(ctypes.byref(configuration), reserved)
109 | if result != 0:
110 | #print("Failed to get setup configuration: " + str(result))
111 | return installations
112 |
113 | enum_instances = configuration.contents.vtable.contents.EnumInstances
114 |
115 | enum_setup_instances = ctypes.POINTER(IEnumSetupInstances)()
116 | result = enum_instances(configuration, ctypes.byref(enum_setup_instances))
117 | if result != 0:
118 | #print("Failed to enum setup instances: " + str(result))
119 | return installations
120 |
121 |
122 | setup_instance = ctypes.POINTER(ISetupInstance)()
123 | fetched = ctypes.c_int(0)
124 |
125 | while True:
126 | next = enum_setup_instances.contents.vtable.contents.Next
127 | result = next(enum_setup_instances, 1, ctypes.byref(setup_instance), ctypes.byref(fetched))
128 | if result == 1 or fetched == 0:
129 | break
130 | if result != 0:
131 | #print("Failed to get next setup instance: " + str(result))
132 | break
133 |
134 | version = ctypes.c_wchar_p()
135 | path = ctypes.c_wchar_p()
136 |
137 | get_installation_version = setup_instance.contents.vtable.contents.GetInstallationVersion
138 | get_installation_path = setup_instance.contents.vtable.contents.GetInstallationPath
139 |
140 | result = get_installation_version(setup_instance, ctypes.byref(version))
141 | if result != 0:
142 | #print("Failed to get setup instance version: " + str(result))
143 | break
144 |
145 | result = get_installation_path(setup_instance, ctypes.byref(path))
146 | if result != 0:
147 | #print("Failed to get setup instance version: " + str(result))
148 | break
149 |
150 | installations.append((version.value, path.value))
151 |
152 | return installations
153 |
154 |
155 | if __name__ == "__main__":
156 |
157 | installations = get_vs_installations()
158 |
159 | for version, path in installations:
160 | print(version + " " + path)
161 |
--------------------------------------------------------------------------------
/build/ninja/xcode.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Ninja toolchain abstraction for XCode toolchain"""
4 |
5 | import os
6 | import subprocess
7 |
8 | import toolchain
9 | import syntax
10 |
11 | def make_target(toolchain, host, target):
12 | return XCode(toolchain, host, target)
13 |
14 | class XCode(object):
15 | def __init__(self, toolchain, host, target):
16 | self.toolchain = toolchain
17 | self.host = host
18 | self.target = target
19 |
20 | def initialize_toolchain(self):
21 | self.organisation = ''
22 | self.bundleidentifier = ''
23 | self.provisioning = ''
24 | if self.target.is_macos():
25 | self.deploymenttarget = '12.0'
26 | elif self.target.is_ios():
27 | self.deploymenttarget = '15.0'
28 |
29 | def build_toolchain(self):
30 | if self.target.is_macos():
31 | sdk = 'macosx'
32 | deploytarget = 'MACOSX_DEPLOYMENT_TARGET=' + self.deploymenttarget
33 | elif self.target.is_ios():
34 | sdk = 'iphoneos'
35 | deploytarget = 'IPHONEOS_DEPLOYMENT_TARGET=' + self.deploymenttarget
36 |
37 | platformpath = toolchain.check_last_output(['xcrun', '--sdk', sdk, '--show-sdk-platform-path'])
38 | localpath = platformpath + "/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"
39 |
40 | self.plist = "PATH=" + localpath + " " + toolchain.check_last_output(['xcrun', '--sdk', sdk, '-f', 'plutil'])
41 | self.xcassets = "PATH=" + localpath + " " + toolchain.check_last_output(['xcrun', '--sdk', sdk, '-f', 'actool'])
42 | self.xib = "PATH=" + localpath + " " + toolchain.check_last_output(['xcrun', '--sdk', sdk, '-f', 'ibtool'])
43 | self.dsymutil = "PATH=" + localpath + " " + toolchain.check_last_output(['xcrun', '--sdk', sdk, '-f', 'dsymutil'])
44 |
45 | self.plistcmd = 'build/ninja/plist.py --exename $exename --prodname $prodname --bundle $bundleidentifier --target $target --deploymenttarget $deploymenttarget --output $outpath $in'
46 | if self.target.is_macos():
47 | self.xcassetscmd = 'mkdir -p $outpath && $xcassets --output-format human-readable-text --output-partial-info-plist $outplist' \
48 | ' --app-icon AppIcon --launch-image LaunchImage --platform macosx --minimum-deployment-target ' + self.deploymenttarget + \
49 | ' --target-device mac --compress-pngs --compile $outpath $in >/dev/null'
50 | self.xibcmd = '$xib --target-device mac --module $module --minimum-deployment-target ' + self.deploymenttarget + \
51 | ' --output-partial-info-plist $outplist --auto-activate-custom-fonts' \
52 | ' --output-format human-readable-text --compile $outpath $in'
53 | elif self.target.is_ios():
54 | self.xcassetscmd = 'mkdir -p $outpath && $xcassets --output-format human-readable-text --output-partial-info-plist $outplist' \
55 | ' --app-icon AppIcon --launch-image LaunchImage --platform iphoneos --minimum-deployment-target ' + self.deploymenttarget + \
56 | ' --target-device iphone --target-device ipad --compress-pngs --compile $outpath $in >/dev/null'
57 | self.xibcmd = '$xib --target-device iphone --target-device ipad --module $module --minimum-deployment-target ' + self.deploymenttarget + \
58 | ' --output-partial-info-plist $outplist --auto-activate-custom-fonts' \
59 | ' --output-format human-readable-text --compile $outpath $in &> /dev/null '
60 | self.dsymutilcmd = '$dsymutil $in -o $outpath'
61 | self.codesigncmd = 'build/ninja/codesign.py --target $target --prefs codesign.json --builddir $builddir --binname $binname --config $config --entitlements $entitlements $outpath'
62 |
63 | def parse_default_variables(self, variables):
64 | if not variables:
65 | return
66 | if isinstance(variables, dict):
67 | iterator = iter(variables.items())
68 | else:
69 | iterator = iter(variables)
70 | for key, val in iterator:
71 | if key == 'deploymenttarget':
72 | self.deploymenttarget = val
73 | if key == 'organisation':
74 | self.organisation = val
75 | if key == 'bundleidentifier':
76 | self.bundleidentifier = val
77 | if key == 'provisioning':
78 | self.provisioning = val
79 |
80 | def parse_prefs(self, prefs):
81 | if self.target.is_ios() and 'ios' in prefs:
82 | iosprefs = prefs['ios']
83 | if 'deploymenttarget' in iosprefs:
84 | self.deploymenttarget = iosprefs['deploymenttarget']
85 | if 'organisation' in iosprefs:
86 | self.organisation = iosprefs['organisation']
87 | if 'bundleidentifier' in iosprefs:
88 | self.bundleidentifier = iosprefs['bundleidentifier']
89 | if 'provisioning' in iosprefs:
90 | self.provisioning = iosprefs['provisioning']
91 | elif self.target.is_macos() and 'macos' in prefs:
92 | macosprefs = prefs['macos']
93 | if 'deploymenttarget' in macosprefs:
94 | self.deploymenttarget = macosprefs['deploymenttarget']
95 | if 'organisation' in macosprefs:
96 | self.organisation = macosprefs['organisation']
97 | if 'bundleidentifier' in macosprefs:
98 | self.bundleidentifier = macosprefs['bundleidentifier']
99 | if 'provisioning' in macosprefs:
100 | self.provisioning = macosprefs['provisioning']
101 |
102 | def write_variables(self, writer):
103 | writer.variable('plist', self.plist)
104 | writer.variable('xcassets', self.xcassets)
105 | writer.variable('xib', self.xib)
106 | writer.variable('dsymutil', self.dsymutil)
107 | writer.variable('bundleidentifier', syntax.escape(self.bundleidentifier))
108 | writer.variable('deploymenttarget', self.deploymenttarget)
109 | writer.variable('entitlements', 'none')
110 |
111 | def write_rules(self, writer):
112 | writer.rule('dsymutil', command = self.dsymutilcmd, description = 'DSYMUTIL $outpath')
113 | writer.rule('plist', command = self.plistcmd, description = 'PLIST $outpath')
114 | writer.rule('xcassets', command = self.xcassetscmd, description = 'XCASSETS $outpath')
115 | writer.rule('xib', command = self.xibcmd, description = 'XIB $outpath')
116 | writer.rule('codesign', command = self.codesigncmd, description = 'CODESIGN $outpath')
117 |
118 | def make_bundleidentifier(self, binname):
119 | return self.bundleidentifier.replace('$(binname)', binname)
120 |
121 | def app(self, toolchain, writer, module, archbins, outpath, binname, basepath, config, implicit_deps, resources, codesign):
122 | #Outputs
123 | builtbin = []
124 | builtres = []
125 | builtsym = []
126 |
127 | #Paths
128 | builddir = os.path.join('$buildpath', config, 'app', binname)
129 | configpath = os.path.join(outpath, config)
130 | apppath = os.path.join(configpath, binname + '.app')
131 | dsympath = os.path.join(outpath, config, binname + '.dSYM')
132 |
133 | #Extract debug symbols from universal binary
134 | dsymcontentpath = os.path.join(dsympath, 'Contents')
135 | builtsym = writer.build([os.path.join(dsymcontentpath, 'Resources', 'DWARF', binname), os.path.join(dsymcontentpath, 'Resources', 'DWARF' ), os.path.join(dsymcontentpath, 'Resources'), os.path.join(dsymcontentpath, 'Info.plist'), dsymcontentpath, dsympath], 'dsymutil', archbins[config], variables = [('outpath', dsympath)])
136 |
137 | #Copy final universal binary
138 | if self.target.is_ios():
139 | builtbin = toolchain.copy(writer, archbins[config], os.path.join(apppath, toolchain.binprefix + binname + toolchain.binext))
140 | else:
141 | builtbin = toolchain.copy(writer, archbins[config], os.path.join(apppath, 'Contents', 'MacOS', toolchain.binprefix + binname + toolchain.binext))
142 |
143 | #Build resources
144 | if resources:
145 | has_resources = False
146 |
147 | #Lists of input plists and partial plist files produced by resources
148 | plists = []
149 | assetsplists = []
150 | xibplists = []
151 | entitlements = []
152 |
153 | #All resource output files
154 | outfiles = []
155 |
156 | #First build everything except plist inputs
157 | for resource in resources:
158 | if resource.endswith('.xcassets'):
159 | if self.target.is_macos():
160 | assetsvars = [('outpath', os.path.join(os.getcwd(), apppath, 'Contents', 'Resources'))]
161 | else:
162 | assetsvars = [('outpath', apppath)]
163 | outplist = os.path.join(os.getcwd(), builddir, os.path.splitext(os.path.basename(resource))[0] + '-xcassets.plist')
164 | assetsvars += [('outplist', outplist)]
165 | outfiles = [outplist]
166 | if self.target.is_macos():
167 | outfiles += [os.path.join(os.getcwd(), apppath, 'Contents', 'Resources', 'AppIcon.icns')]
168 | elif self.target.is_ios():
169 | pass #TODO: Need to list all icon and launch image files here
170 | assetsplists += writer.build(outfiles, 'xcassets', os.path.join(os.getcwd(), basepath, module, resource), variables = assetsvars)
171 | has_resources = True
172 | elif resource.endswith('.xib'):
173 | xibmodule = binname.replace('-', '_').replace('.', '_')
174 | if self.target.is_macos():
175 | nibpath = os.path.join(apppath, 'Contents', 'Resources', os.path.splitext(os.path.basename(resource))[0] + '.nib')
176 | else:
177 | nibpath = os.path.join(apppath, os.path.splitext(os.path.basename(resource))[0] + '.nib')
178 | plistpath = os.path.join(builddir, os.path.splitext(os.path.basename(resource))[0] + '-xib.plist')
179 | xibplists += [plistpath]
180 | outfiles = []
181 | if self.target.is_ios():
182 | outfiles += [os.path.join(nibpath, 'objects.nib'), os.path.join(nibpath, 'objects-8.0+.nib'), os.path.join(nibpath, 'runtime.nib')]
183 | outfiles += [nibpath, plistpath]
184 | builtres += writer.build(outfiles, 'xib', os.path.join(os.getcwd(), basepath, module, resource), variables = [('outpath', nibpath), ('outplist', plistpath), ('module', xibmodule)])
185 | has_resources = True
186 | elif resource.endswith('.plist'):
187 | plists += [os.path.join(os.getcwd(), basepath, module, resource)]
188 | elif resource.endswith('.entitlements'):
189 | entitlements += [os.path.join(os.getcwd(), basepath, module, resource)]
190 |
191 | #Extra output files/directories
192 | outfiles = []
193 | if has_resources and self.target.is_macos():
194 | outfiles += [os.path.join(apppath, 'Contents', 'Resources')]
195 |
196 | #Now build input plists appending partial plists created by previous resources
197 | if self.target.is_macos():
198 | plistpath = os.path.join(apppath, 'Contents', 'Info.plist')
199 | pkginfopath = os.path.join(apppath, 'Contents', 'PkgInfo')
200 | else:
201 | plistpath = os.path.join(apppath, 'Info.plist')
202 | pkginfopath = os.path.join(apppath, 'PkgInfo')
203 | plistvars = [('exename', binname), ('prodname', binname), ('outpath', plistpath)]
204 | bundleidentifier = self.make_bundleidentifier(binname)
205 | if bundleidentifier != '':
206 | plistvars += [('bundleidentifier', bundleidentifier)]
207 | outfiles += [plistpath, pkginfopath]
208 | builtres += writer.build(outfiles, 'plist', plists + assetsplists + xibplists, implicit = [os.path.join( 'build', 'ninja', 'plist.py')], variables = plistvars)
209 |
210 | #Do code signing (might modify binary, but does not matter, nothing should have final binary as input anyway)
211 | if codesign:
212 | codesignvars = [('builddir', builddir), ('binname', binname), ('outpath', apppath), ('config', config)]
213 | if self.target.is_ios():
214 | if self.provisioning != '':
215 | codesignvars += [('provisioning', self.provisioning)]
216 | writer.build([os.path.join(apppath, '_CodeSignature', 'CodeResources'), os.path.join(apppath, '_CodeSignature'), apppath], 'codesign', builtbin, implicit = builtres + [os.path.join('build', 'ninja', 'codesign.py')], variables = codesignvars)
217 | elif self.target.is_macos():
218 | if self.provisioning != '':
219 | codesignvars += [('provisioning', self.provisioning)]
220 | if len(entitlements) > 0:
221 | codesignvars += [('entitlements', entitlements[0])]
222 | writer.build([os.path.join(apppath, 'Contents', '_CodeSignature', 'CodeResources'), os.path.join(apppath, 'Contents', '_CodeSignature'), os.path.join(apppath, 'Contents'), apppath], 'codesign', builtbin, implicit = builtres + [os.path.join('build', 'ninja', 'codesign.py')], variables = codesignvars)
223 |
224 | return builtbin + builtsym + builtres
225 |
--------------------------------------------------------------------------------
/build/task.sublime-project:
--------------------------------------------------------------------------------
1 | {
2 | "folders":
3 | [
4 | {
5 | "follow_symlinks": true,
6 | "path": "../task"
7 | },
8 | {
9 | "follow_symlinks": true,
10 | "path": "../test"
11 | },
12 | {
13 | "follow_symlinks": true,
14 | "path": "../tools"
15 | },
16 | {
17 | "follow_symlinks": true,
18 | "path": "../doc"
19 | }
20 | ],
21 | "build_systems":
22 | [
23 | {
24 | "name": "Ninja",
25 | "shell_cmd": "ninja",
26 | "working_dir": "${project_path:${folder:${file_path}}}/..",
27 | }
28 | ],
29 | "translate_tabs_to_spaces": false,
30 | "use_tab_stops": true,
31 | "trim_trailing_white_space_on_save": true,
32 | "settings":
33 | {
34 | "AStyleFormatter":
35 | {
36 | "options_default":
37 | {
38 | "style" : "attach",
39 | "pad-oper": true,
40 | "indent-switches" : false,
41 | "indent-cases" : true,
42 | "unpad-paren": true,
43 | "break-closing-brackets": true,
44 | "align-pointer": "type",
45 | "max-code-length": 100,
46 | "max-instatement-indent": 60,
47 | "break-after-logical": true
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/configure.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Ninja build configurator for task library"""
4 |
5 | import sys
6 | import os
7 | import glob
8 | import shutil
9 |
10 | sys.path.insert(0, os.path.join('build', 'ninja'))
11 |
12 | import generator
13 |
14 | dependlibs = ['task', 'foundation']
15 |
16 | generator = generator.Generator(project='task', dependlibs=dependlibs, variables=[
17 | ('bundleidentifier', 'com.maniccoder.task.$(binname)')])
18 | target = generator.target
19 | writer = generator.writer
20 | toolchain = generator.toolchain
21 |
22 | task_lib = generator.lib(module='task', sources=[
23 | 'executor.c', 'fiber.c', 'scheduler.c', 'task.c', 'version.c'])
24 |
25 | if generator.skip_tests():
26 | sys.exit()
27 |
28 | includepaths = generator.test_includepaths()
29 |
30 | extralibs = []
31 |
32 | test_cases = [
33 | 'task'
34 | ]
35 | if toolchain.is_monolithic() or target.is_ios() or target.is_android() or target.is_tizen():
36 | # Build one fat binary with all test cases
37 | test_resources = []
38 | test_extrasources = []
39 | test_cases += ['all']
40 | if target.is_ios():
41 | test_resources = [os.path.join('all', 'ios', item) for item in [
42 | 'test-all.plist', 'Images.xcassets', 'test-all.xib']]
43 | test_extrasources = [os.path.join('all', 'ios', 'viewcontroller.m')]
44 | elif target.is_android():
45 | test_resources = [os.path.join('all', 'android', item) for item in [
46 | 'AndroidManifest.xml', os.path.join(
47 | 'layout', 'main.xml'), os.path.join('values', 'strings.xml'),
48 | os.path.join('drawable-ldpi', 'icon.png'), os.path.join('drawable-mdpi',
49 | 'icon.png'), os.path.join('drawable-hdpi', 'icon.png'),
50 | os.path.join('drawable-xhdpi', 'icon.png'), os.path.join('drawable-xxhdpi',
51 | 'icon.png'), os.path.join('drawable-xxxhdpi', 'icon.png')
52 | ]]
53 | test_extrasources = [os.path.join('test', 'all', 'android', 'java', 'com', 'maniccoder', 'task', 'test', item) for item in [
54 | 'TestActivity.java'
55 | ]]
56 | elif target.is_tizen():
57 | test_resources = [os.path.join('all', 'tizen', item) for item in [
58 | 'tizen-manifest.xml', os.path.join('res', 'tizenapp.png')
59 | ]]
60 | dependlibs = ['test'] + dependlibs
61 | if target.is_macos() or target.is_ios() or target.is_android() or target.is_tizen():
62 | generator.app(module='', sources=[os.path.join(module, 'main.c') for module in test_cases] + test_extrasources, binname='test-task',
63 | basepath='test', implicit_deps=[task_lib], libs=dependlibs, dependlibs=dependlibs, resources=test_resources, includepaths=includepaths)
64 | else:
65 | generator.bin(module='', sources=[os.path.join(module, 'main.c') for module in test_cases] + test_extrasources, binname='test-task',
66 | basepath='test', implicit_deps=[task_lib], libs=dependlibs, dependlibs=dependlibs, resources=test_resources, includepaths=includepaths)
67 | else:
68 | # Build one binary per test case
69 | if not generator.is_subninja:
70 | generator.bin(module='all', sources=['main.c'], binname='test-all', basepath='test',
71 | implicit_deps=[task_lib], libs=dependlibs, dependlibs=dependlibs, includepaths=includepaths)
72 | dependlibs = ['test'] + dependlibs
73 | for test in test_cases:
74 | generator.bin(module=test, sources=['main.c'], binname='test-' + test, basepath='test', implicit_deps=[
75 | task_lib], libs=dependlibs + extralibs, dependlibs=dependlibs, includepaths=includepaths)
76 |
--------------------------------------------------------------------------------
/task/build.h:
--------------------------------------------------------------------------------
1 | /* build.h - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | *
16 | */
17 |
18 | #pragma once
19 |
20 | /*! \file build.h
21 | Build setup */
22 |
23 | #include
24 |
25 | #include
26 |
27 | /*! \define BUILD_TASK_ENABLE_DEBUG_LOG
28 | Enable debug log output during task scheduling and execution */
29 | #define BUILD_TASK_ENABLE_DEBUG_LOG 0
30 |
31 | /*! \define BUILD_TASK_ENABLE_STATISTICS
32 | Enable statistics collection during task scheduling and execution */
33 | #define BUILD_TASK_ENABLE_STATISTICS 1
34 |
--------------------------------------------------------------------------------
/task/executor.c:
--------------------------------------------------------------------------------
1 | /* executor.c - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | *
16 | */
17 |
18 | #include "executor.h"
19 | #include "scheduler.h"
20 | #include "fiber.h"
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #include
29 | #include
30 |
31 | #if FOUNDATION_PLATFORM_APPLE
32 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
33 | #endif
34 | #if FOUNDATION_PLATFORM_POSIX
35 | #ifndef _XOPEN_SOURCE
36 | #define _XOPEN_SOURCE 700
37 | #endif
38 | #include
39 | #endif
40 |
41 | FOUNDATION_DECLARE_THREAD_LOCAL(task_executor_t*, task_executor_current, nullptr)
42 |
43 | extern task_executor_t*
44 | task_executor_thread_current(void);
45 |
46 | task_executor_t*
47 | task_executor_thread_current(void) {
48 | return get_thread_task_executor_current();
49 | }
50 |
51 | static task_fiber_t*
52 | task_executor_next_free_fiber(task_executor_t* executor) {
53 | task_fiber_t* fiber;
54 | if (executor->fiber_free) {
55 | fiber = executor->fiber_free;
56 | executor->fiber_free = nullptr;
57 | return fiber;
58 | }
59 |
60 | mutex_lock(executor->fiber_finished_lock);
61 | fiber = executor->fiber_finished;
62 | executor->fiber_finished = fiber ? fiber->fiber_next : nullptr;
63 | mutex_unlock(executor->fiber_finished_lock);
64 | if (fiber) {
65 | fiber->fiber_next = nullptr;
66 | return fiber;
67 | }
68 |
69 | return task_scheduler_next_free_fiber(executor->scheduler);
70 | }
71 |
72 | static void
73 | task_executor_fiber(task_executor_t* executor, task_fiber_t* self_fiber) {
74 | task_scheduler_t* scheduler = executor->scheduler;
75 |
76 | #if FOUNDATION_PLATFORM_POSIX
77 | // Make sure executor fiber resumes here
78 | ucontext_t* context = self_fiber->context;
79 | getcontext(context);
80 | #endif
81 |
82 | while (atomic_load32(&scheduler->running, memory_order_acquire)) {
83 | if (executor->fiber_waiting_release) {
84 | task_fiber_t* fiber = executor->fiber_waiting_release;
85 | executor->fiber_waiting_release = nullptr;
86 |
87 | // Release the artificial count done to make sure fiber was not prematurely
88 | // resumed before the switch back to executor was complete
89 | if (atomic_decr32(fiber->waiting_counter, memory_order_relaxed) == 0) {
90 | // All subtasks completed while switching to the executor fiber when
91 | // yielding this fiber (task), switch back and continue execution
92 | task_fiber_t* fiber_waiting = task_scheduler_pop_fiber_waiting(scheduler, fiber->waiting_counter);
93 | FOUNDATION_ASSERT(fiber_waiting == fiber);
94 | FOUNDATION_ASSERT_MSG(!fiber_waiting->fiber_pending_finished,
95 | "Internal fiber failure, continuation fiber already has pending finished fiber");
96 | FOUNDATION_ASSERT_MSG(
97 | fiber_waiting->state == TASK_FIBER_YIELD,
98 | "Internal fiber failure, waiting fiber not in yield state when resuming in fiber");
99 |
100 | task_fiber_switch(self_fiber, fiber_waiting);
101 | }
102 | }
103 |
104 | // Grab the next pending task, either a new task or a task to resume
105 | task_t task;
106 | if (task_scheduler_next_task(scheduler, &task)) {
107 | if (self_fiber->fiber_pending_finished) {
108 | // This will be reached once a fiber has finished executing a task and run out of
109 | // pending task recursions - the original task fiber is put in the executor pending
110 | // finished and context is switched back to this fiber to clean up
111 | task_executor_finished_fiber(executor, self_fiber->fiber_pending_finished);
112 | self_fiber->fiber_pending_finished = nullptr;
113 | }
114 |
115 | // This is a new task, grab a free fiber
116 | task_fiber_t* fiber = task_executor_next_free_fiber(executor);
117 | FOUNDATION_ASSERT_MSG((fiber->state == TASK_FIBER_FREE) || (fiber->state == TASK_FIBER_NOT_INITIALIZED),
118 | "Internal fiber failure, free fiber not in free state");
119 | task_fiber_initialize(fiber);
120 |
121 | // Switch to the task fiber to execute it
122 | fiber->task = task;
123 | fiber->state = TASK_FIBER_RUNNING;
124 | task_fiber_switch(self_fiber, fiber);
125 | } else {
126 | // Task queue is empty, wait for signal
127 | if (atomic_load32(&scheduler->running, memory_order_relaxed))
128 | semaphore_try_wait(&scheduler->signal, 10);
129 | }
130 | }
131 |
132 | if (self_fiber->fiber_pending_finished) {
133 | task_executor_finished_fiber(executor, self_fiber->fiber_pending_finished);
134 | self_fiber->fiber_pending_finished = nullptr;
135 | }
136 |
137 | task_fiber_switch(nullptr, self_fiber->fiber_return);
138 | }
139 |
140 | #if FOUNDATION_PLATFORM_WINDOWS
141 | extern void
142 | task_fiber_initialize_for_executor_thread(task_executor_t* executor, task_fiber_t* fiber,
143 | void (*executor_function)(long, long, long, long, task_executor_t*,
144 | task_fiber_t*));
145 |
146 | static FOUNDATION_NOINLINE void STDCALL
147 | task_executor_trampoline(long ecx, long edx, long r8, long r9, task_executor_t* executor, task_fiber_t* self_fiber) {
148 | FOUNDATION_UNUSED(ecx, edx, r8, r9);
149 |
150 | #elif FOUNDATION_PLATFORM_POSIX
151 | extern void
152 | task_fiber_initialize_for_executor_thread(task_executor_t* executor, task_fiber_t* fiber,
153 | void (*executor_function)(int, int, int, int, int, int, int, int, int, int));
154 |
155 | static FOUNDATION_NOINLINE void
156 | task_executor_trampoline(int r0, int r1, int r2, int r3, int r4, int r5, int executor_low, int executor_high,
157 | int fiber_low, int fiber_high) {
158 | FOUNDATION_UNUSED(r0, r1, r2, r3, r4, r5);
159 | // Reconstruct 64bit pointers
160 | task_executor_t* executor = (void*)(((uintptr_t)((uint)executor_high) << 32ULL) | (uintptr_t)((uint)executor_low));
161 | task_fiber_t* self_fiber = (void*)(((uintptr_t)((uint)fiber_high) << 32ULL) | (uintptr_t)((uint)fiber_low));
162 |
163 | #else
164 | #error not implemented
165 | #endif
166 | atomic_thread_fence_sequentially_consistent();
167 |
168 | self_fiber->state = TASK_FIBER_EXECUTOR;
169 |
170 | task_executor_fiber(executor, self_fiber);
171 | }
172 |
173 | void*
174 | task_executor_thread(void* arg) {
175 | task_executor_t* executor = arg;
176 | set_thread_task_executor_current(executor);
177 |
178 | size_t total_fiber_size =
179 | executor->scheduler->fiber_size + executor->scheduler->fiber_context_size + executor->scheduler->fiber_tib_size;
180 | executor->self_fiber = memory_allocate(HASH_TASK, total_fiber_size, 0, MEMORY_PERSISTENT);
181 | executor->self_fiber->context = pointer_offset(executor->self_fiber, executor->scheduler->fiber_size);
182 | executor->self_fiber->tib = pointer_offset(executor->self_fiber->context, executor->scheduler->fiber_context_size);
183 |
184 | // Grab a fiber to get a clean contained stack space
185 | task_fiber_t* executor_fiber = task_scheduler_next_free_fiber(executor->scheduler);
186 | task_fiber_initialize_for_executor_thread(executor, executor_fiber, task_executor_trampoline);
187 |
188 | // Store current thread context
189 | if (!task_fiber_initialize_from_current_thread(executor->self_fiber))
190 | exception_raise_abort();
191 |
192 | executor = get_thread_task_executor_current();
193 | if (atomic_load32(&executor->scheduler->running, memory_order_acquire))
194 | task_fiber_switch(executor->self_fiber, executor_fiber);
195 |
196 | executor = get_thread_task_executor_current();
197 | memory_deallocate(executor->self_fiber);
198 | executor->self_fiber = nullptr;
199 |
200 | #if BUILD_ENABLE_ERROR_CONTEXT
201 | error_context_set(nullptr);
202 | #endif
203 |
204 | return nullptr;
205 | }
206 |
207 | extern void
208 | task_executor_finished_fiber_internal(task_executor_t* executor, task_fiber_t* fiber);
209 |
210 | void
211 | task_executor_finished_fiber_internal(task_executor_t* executor, task_fiber_t* fiber) {
212 | FOUNDATION_ASSERT_MSG(fiber->stack, "Internal fiber failure, executor control fiber marked as free");
213 | FOUNDATION_ASSERT_MSG(fiber->state == TASK_FIBER_FINISHED,
214 | "Internal fiber failure, finished fiber not in finished state");
215 | fiber->state = TASK_FIBER_FREE;
216 |
217 | #if BUILD_ENABLE_ERROR_CONTEXT
218 | memory_deallocate(fiber->error_context);
219 | fiber->error_context = nullptr;
220 | #endif
221 |
222 | if (!executor->fiber_free) {
223 | executor->fiber_free = fiber;
224 | return;
225 | }
226 |
227 | mutex_lock(executor->fiber_finished_lock);
228 | fiber->fiber_next = executor->fiber_finished;
229 | executor->fiber_finished = fiber;
230 | mutex_unlock(executor->fiber_finished_lock);
231 | }
232 |
233 | void
234 | task_executor_finished_fiber(task_executor_t* executor, task_fiber_t* fiber) {
235 | FOUNDATION_ASSERT_MSG(fiber->stack, "Internal fiber failure, executor control fiber marked as free");
236 | FOUNDATION_ASSERT_MSG(fiber->state == TASK_FIBER_FINISHED,
237 | "Internal fiber failure, finished fiber not in finished state");
238 | fiber->state = TASK_FIBER_FREE;
239 |
240 | #if BUILD_ENABLE_ERROR_CONTEXT
241 | memory_deallocate(fiber->error_context);
242 | fiber->error_context = nullptr;
243 | #endif
244 |
245 | mutex_lock(executor->fiber_finished_lock);
246 | fiber->fiber_next = executor->fiber_finished;
247 | executor->fiber_finished = fiber;
248 | mutex_unlock(executor->fiber_finished_lock);
249 | }
250 |
--------------------------------------------------------------------------------
/task/executor.h:
--------------------------------------------------------------------------------
1 | /* executor.h - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | *
16 | */
17 |
18 | #pragma once
19 |
20 | /*! \file executor.h
21 | Task executor thread */
22 |
23 | #include
24 |
25 | #include
26 | #include
27 |
28 | /*! Task executor thread entry point
29 | * \param arg Thread argument (executor pointer)
30 | * \return Result (0)
31 | */
32 | TASK_API void*
33 | task_executor_thread(void* arg);
34 |
35 | /*! Notify executor that the fiber finished executing
36 | * \param executor Task executor
37 | * \param fiber Free fiber control structure */
38 | TASK_API void
39 | task_executor_finished_fiber(task_executor_t* executor, task_fiber_t* fiber);
40 |
--------------------------------------------------------------------------------
/task/fiber.c:
--------------------------------------------------------------------------------
1 | /* fiber.c - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | *
16 | */
17 |
18 | #include "fiber.h"
19 | #include "executor.h"
20 | #include "scheduler.h"
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #if FOUNDATION_PLATFORM_APPLE
27 | #define _XOPEN_SOURCE
28 | #endif
29 |
30 | #include
31 | #include
32 |
33 | #if FOUNDATION_COMPILER_CLANG
34 | #pragma clang diagnostic push
35 | #if __has_warning("-Walloca")
36 | #pragma clang diagnostic ignored "-Walloca"
37 | #endif
38 | #endif
39 |
40 | #if FOUNDATION_PLATFORM_APPLE
41 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
42 | #endif
43 | #if FOUNDATION_PLATFORM_POSIX
44 | #include
45 | #endif
46 |
47 | extern task_executor_t*
48 | task_executor_thread_current(void);
49 |
50 | extern void
51 | task_executor_finished_fiber_internal(task_executor_t* executor, task_fiber_t* fiber);
52 |
53 | #if FOUNDATION_PLATFORM_WINDOWS
54 | //! Used for return address of executor control fiber context
55 | static void FOUNDATION_NOINLINE
56 | task_fiber_resume(void) {
57 | }
58 | #endif
59 |
60 | bool FOUNDATION_NOINLINE
61 | task_fiber_initialize_from_current_thread(task_fiber_t* fiber) {
62 | fiber->state = TASK_FIBER_THREAD;
63 | fiber->fiber_next = nullptr;
64 | #if FOUNDATION_PLATFORM_WINDOWS
65 |
66 | NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
67 | memcpy(fiber->tib, tib, sizeof(NT_TIB));
68 | fiber->stack = (void*)tib->StackLimit;
69 | fiber->stack_size = pointer_diff((void*)tib->StackBase, fiber->stack);
70 |
71 | CONTEXT* context = fiber->context;
72 | context->ContextFlags = CONTEXT_FULL;
73 | BOOL res = GetThreadContext(GetCurrentThread(), context);
74 | if (!FOUNDATION_VALIDATE_MSG(res != 0, "Failed to get current thread context for fiber"))
75 | return false;
76 | // The stack pointer cannot be used as set by GetThreadContext, as it will be
77 | // captured inside the scope of the kernel DLL function. It will contain some other
78 | // data when actually executed. Capture the stack pointer as seen by this function
79 | // and simulate a immediate return by the dummy resume function (instruction pointer
80 | // will point to the ret instruction). It will pop the return value from the stack
81 | // which we have set to the address of the return address.
82 | context->Rsp = (DWORD64)_AddressOfReturnAddress();
83 | context->Rbp = 0;
84 | context->Rip = (DWORD64)task_fiber_resume;
85 | #elif FOUNDATION_PLATFORM_POSIX
86 | ucontext_t* context = fiber->context;
87 | getcontext(context);
88 | #else
89 | #error Not implemented
90 | #endif
91 | return true;
92 | }
93 |
94 | #if FOUNDATION_PLATFORM_WINDOWS
95 | static FOUNDATION_NOINLINE void STDCALL
96 | task_fiber_trampoline(long rcx, long rdx, long r8, long r9, task_fiber_t* fiber) {
97 | FOUNDATION_UNUSED(rcx, rdx, r8, r9);
98 | #else
99 | static FOUNDATION_NOINLINE void STDCALL
100 | task_fiber_trampoline(int fiber_low, int fiber_high) {
101 | // Reconstruct 64bit pointer
102 | task_fiber_t* fiber = (void*)(((uintptr_t)((uint)fiber_high) << 32ULL) | (uintptr_t)((uint)fiber_low));
103 | #endif
104 | FOUNDATION_ASSERT_MSG(fiber->state != TASK_FIBER_THREAD,
105 | "Internal fiber failure, executor control fiber used as task fiber");
106 | FOUNDATION_ASSERT_MSG(fiber->state == TASK_FIBER_RUNNING,
107 | "Internal fiber failure, running fiber not in running state");
108 |
109 | task_scheduler_t* scheduler = task_executor_thread_current()->scheduler;
110 | task_fiber_t* fiber_waiting = nullptr;
111 |
112 | // Mark a fiber that was pending finished as actually finished (see comment
113 | // below about current fiber when switching to a task with a pending fiber)
114 | if (fiber->fiber_pending_finished) {
115 | task_fiber_t* fiber_finished = fiber->fiber_pending_finished;
116 | fiber->fiber_pending_finished = nullptr;
117 | atomic_thread_fence_release();
118 | task_executor_finished_fiber_internal(task_executor_thread_current(), fiber_finished);
119 | }
120 |
121 | FOUNDATION_ASSERT_MSG(fiber->state == TASK_FIBER_RUNNING,
122 | "Internal fiber failure, running fiber not in running state when calling task function");
123 |
124 | atomic32_t* counter = fiber->task.counter;
125 | fiber->task.function(fiber->task.context);
126 |
127 | FOUNDATION_ASSERT_MSG(fiber->state == TASK_FIBER_RUNNING,
128 | "Internal fiber failure, running fiber not in running state after calling task function");
129 | #if BUILD_ENABLE_ERROR_CONTEXT
130 | FOUNDATION_ASSERT_MSG(!fiber->error_context || !((error_context_t*)fiber->error_context)->depth,
131 | "Fiber finished with non-null error context");
132 | error_context_t* current_error_context = error_context();
133 | FOUNDATION_ASSERT_MSG(!current_error_context || !current_error_context->depth,
134 | "Fiber finished with non-zero error context depth");
135 | #endif
136 |
137 | if (fiber->fiber_pending_finished) {
138 | task_fiber_t* fiber_finished = fiber->fiber_pending_finished;
139 | fiber->fiber_pending_finished = nullptr;
140 | atomic_thread_fence_release();
141 | task_executor_finished_fiber_internal(task_executor_thread_current(), fiber_finished);
142 | }
143 |
144 | if (counter) {
145 | if (!atomic_decr32(counter, memory_order_relaxed)) {
146 | // Get the fiber waiting for this subtask counter completion
147 | fiber_waiting = task_scheduler_pop_fiber_waiting(scheduler, counter);
148 | }
149 | }
150 |
151 | while (atomic_load32(&scheduler->running, memory_order_relaxed)) {
152 | // Check if there is a previously waiting fiber that is ready to execute
153 | if (fiber_waiting) {
154 | // This fiber has now finished, but cannot be released until the new fiber is executing in
155 | // it's own stack or it could be prematurely reused
156 | FOUNDATION_ASSERT_MSG(!fiber_waiting->fiber_pending_finished,
157 | "Internal fiber failure, continuation fiber already has pending finished fiber");
158 | FOUNDATION_ASSERT_MSG(!fiber->fiber_pending_finished,
159 | "Internal fiber failure, finished fiber has pending finished fiber");
160 | FOUNDATION_ASSERT_MSG(fiber->state == TASK_FIBER_RUNNING,
161 | "Internal fiber failure, running fiber not in running state");
162 | #if BUILD_ENABLE_ERROR_CONTEXT
163 | fiber->error_context = error_context_set(nullptr);
164 | #endif
165 | fiber->state = TASK_FIBER_FINISHED;
166 | fiber_waiting->fiber_pending_finished = fiber;
167 |
168 | FOUNDATION_ASSERT_MSG(fiber_waiting->state == TASK_FIBER_YIELD,
169 | "Internal fiber failure, waiting fiber not in yield state when resuming in fiber");
170 |
171 | // Switch to the waiting task fiber to execute it
172 | task_fiber_switch(fiber->fiber_return, fiber_waiting);
173 |
174 | // We will never return here since the fiber switched to will
175 | // switch back to the return context immediately
176 | FOUNDATION_ASSERT_FAIL_LOG(HASH_TASK, "Internal fiber failure, control returned to unreachable code");
177 | exception_raise_abort();
178 | }
179 |
180 | // Optimization, check if we can reuse this fiber immediately without
181 | // switching context back to the executor task loop (tail recursion)
182 | if (task_scheduler_next_task(scheduler, &fiber->task)) {
183 | // This is a new task, reuse this fiber
184 | counter = fiber->task.counter;
185 | fiber->task.function(fiber->task.context);
186 |
187 | FOUNDATION_ASSERT_MSG(
188 | fiber->state == TASK_FIBER_RUNNING,
189 | "Internal fiber failure, running fiber not in running state after calling task function");
190 | #if BUILD_ENABLE_ERROR_CONTEXT
191 | FOUNDATION_ASSERT_MSG(!fiber->error_context || !((error_context_t*)fiber->error_context)->depth,
192 | "Fiber finished with non-null error context");
193 | current_error_context = error_context();
194 | FOUNDATION_ASSERT_MSG(!current_error_context || !current_error_context->depth,
195 | "Fiber finished with non-zero error context depth");
196 | #endif
197 |
198 | if (fiber->fiber_pending_finished) {
199 | task_fiber_t* fiber_finished = fiber->fiber_pending_finished;
200 | fiber->fiber_pending_finished = nullptr;
201 | atomic_thread_fence_release();
202 | task_executor_finished_fiber_internal(task_executor_thread_current(), fiber_finished);
203 | }
204 |
205 | if (counter) {
206 | if (!atomic_decr32(counter, memory_order_relaxed)) {
207 | // Get the fiber waiting for this subtask counter completion
208 | fiber_waiting = task_scheduler_pop_fiber_waiting(scheduler, counter);
209 | }
210 | }
211 | } else {
212 | // Break and return to executor control fiber
213 | break;
214 | }
215 | }
216 |
217 | FOUNDATION_ASSERT_MSG(!fiber->fiber_return->fiber_pending_finished,
218 | "Internal fiber failure, return context already has pending finished fiber");
219 | fiber->fiber_return->fiber_pending_finished = fiber;
220 |
221 | FOUNDATION_ASSERT_MSG(fiber->fiber_return->state == TASK_FIBER_EXECUTOR,
222 | "Internal fiber failure, return to executor fiber not in executor state");
223 | FOUNDATION_ASSERT_MSG(fiber->state == TASK_FIBER_RUNNING,
224 | "Internal fiber failure, running fiber not in running state");
225 | #if BUILD_ENABLE_ERROR_CONTEXT
226 | FOUNDATION_ASSERT_MSG(!fiber->error_context || !((error_context_t*)fiber->error_context)->depth,
227 | "Fiber finished with non-null error context");
228 | fiber->error_context = error_context_set(nullptr);
229 | #endif
230 | fiber->state = TASK_FIBER_FINISHED;
231 |
232 | task_fiber_switch(nullptr, fiber->fiber_return);
233 | }
234 |
235 | bool FOUNDATION_NOINLINE
236 | task_fiber_initialize(task_fiber_t* fiber) {
237 | #if FOUNDATION_PLATFORM_WINDOWS
238 | NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
239 | memcpy(fiber->tib, tib, sizeof(NT_TIB));
240 | NT_TIB* fiber_tib = fiber->tib;
241 | // fiber_tib->FiberData = fiber;
242 | fiber_tib->StackBase = fiber->stack;
243 | fiber_tib->StackLimit = pointer_offset(fiber->stack, -(ssize_t)fiber->stack_size);
244 |
245 | CONTEXT* context = fiber->context;
246 | context->ContextFlags = CONTEXT_FULL;
247 | BOOL res = GetThreadContext(GetCurrentThread(), context);
248 | if (!FOUNDATION_VALIDATE_MSG(res != 0, "Failed to get current thread context for fiber"))
249 | return false;
250 |
251 | FOUNDATION_ASSERT_MSG(fiber->state != TASK_FIBER_THREAD,
252 | "Internal fiber failure, executor control fiber used for execution of task");
253 | FOUNDATION_ASSERT_MSG(fiber->stack, "Internal fiber failure, fiber without a stack used");
254 |
255 | void* stack_pointer = fiber->stack;
256 | void** argument_pointer = (void**)pointer_offset(stack_pointer, -32);
257 | *(argument_pointer + 0) = fiber;
258 | *(argument_pointer + 1) = 0;
259 | *(argument_pointer + 2) = 0;
260 | *(argument_pointer + 3) = 0;
261 | stack_pointer = pointer_offset(argument_pointer, -40);
262 | void** stack_content = (void**)stack_pointer;
263 | *(stack_content + 0) = 0;
264 | *(stack_content + 1) = 0;
265 | *(stack_content + 2) = 0;
266 | *(stack_content + 3) = 0;
267 | *(stack_content + 4) = 0;
268 | context->Rsp = (DWORD64)stack_pointer;
269 | context->Rbp = 0;
270 | context->Rip = (DWORD64)task_fiber_trampoline;
271 | context->ContextFlags = CONTEXT_FULL;
272 | #elif FOUNDATION_PLATFORM_POSIX
273 | ucontext_t* context = fiber->context;
274 | #if FOUNDATION_PLATFORM_APPLE
275 | memset(fiber->context, 0, sizeof(ucontext_t));
276 | context->uc_mcontext = fiber->tib;
277 | context->uc_mcsize = sizeof(*context->uc_mcontext);
278 | #else
279 | if (fiber->state == TASK_FIBER_NOT_INITIALIZED) {
280 | memset(fiber->context, 0, sizeof(ucontext_t));
281 | getcontext(context);
282 | }
283 | #endif
284 | context->uc_stack.ss_sp = pointer_offset(fiber->stack, -(ssize_t)fiber->stack_size);
285 | context->uc_stack.ss_size = fiber->stack_size;
286 |
287 | // Deconstruct 64bit pointer
288 | int fiber_low = (int)((uintptr_t)fiber & 0xFFFFFFFFULL);
289 | int fiber_high = (int)((uintptr_t)fiber >> 32ULL);
290 |
291 | makecontext(context, (void (*)(void))task_fiber_trampoline, 2, fiber_low, fiber_high);
292 | #else
293 | #error Not implemented
294 | #endif
295 | return true;
296 | }
297 |
298 | #if FOUNDATION_PLATFORM_WINDOWS
299 | extern void
300 | task_fiber_initialize_for_executor_thread(task_executor_t* executor, task_fiber_t* fiber,
301 | void (*executor_function)(long, long, long, long, task_executor_t*,
302 | task_fiber_t*));
303 |
304 | void
305 | task_fiber_initialize_for_executor_thread(task_executor_t* executor, task_fiber_t* fiber,
306 | void (*executor_function)(long, long, long, long, task_executor_t*,
307 | task_fiber_t*)) {
308 | #elif FOUNDATION_PLATFORM_POSIX
309 | extern void
310 | task_fiber_initialize_for_executor_thread(task_executor_t* executor, task_fiber_t* fiber,
311 | void (*executor_function)(int, int, int, int, int, int, int, int, int, int));
312 |
313 | void
314 | task_fiber_initialize_for_executor_thread(task_executor_t* executor, task_fiber_t* fiber,
315 | void (*executor_function)(int, int, int, int, int, int, int, int, int, int)) {
316 | #endif
317 | #if FOUNDATION_PLATFORM_POSIX
318 | bool was_initialized = (fiber->state != TASK_FIBER_NOT_INITIALIZED);
319 | #endif
320 | fiber->state = TASK_FIBER_EXECUTOR;
321 | fiber->fiber_next = nullptr;
322 |
323 | #if FOUNDATION_PLATFORM_WINDOWS
324 | NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
325 | memcpy(fiber->tib, tib, sizeof(NT_TIB));
326 | NT_TIB* fiber_tib = fiber->tib;
327 | // fiber_tib->FiberData = fiber;
328 | fiber_tib->StackBase = fiber->stack;
329 | fiber_tib->StackLimit = pointer_offset(fiber->stack, -(ssize_t)fiber->stack_size);
330 |
331 | CONTEXT* context = fiber->context;
332 | context->ContextFlags = CONTEXT_FULL;
333 | BOOL res = GetThreadContext(GetCurrentThread(), context);
334 | if (!FOUNDATION_VALIDATE_MSG(res != 0, "Failed to get current thread context for fiber"))
335 | return;
336 |
337 | FOUNDATION_ASSERT_MSG(fiber->state != TASK_FIBER_THREAD,
338 | "Internal fiber failure, executor control fiber used for execution of task");
339 | FOUNDATION_ASSERT_MSG(fiber->stack, "Internal fiber failure, fiber without a stack used");
340 |
341 | void* stack_pointer = fiber->stack;
342 | void** argument_pointer = (void**)pointer_offset(stack_pointer, -32);
343 | *(argument_pointer + 0) = executor;
344 | *(argument_pointer + 1) = fiber;
345 | *(argument_pointer + 2) = 0;
346 | *(argument_pointer + 3) = 0;
347 | stack_pointer = pointer_offset(argument_pointer, -40);
348 | void** stack_content = (void**)stack_pointer;
349 | *(stack_content + 0) = 0;
350 | *(stack_content + 1) = 0;
351 | *(stack_content + 2) = 0;
352 | *(stack_content + 3) = 0;
353 | *(stack_content + 4) = 0;
354 | context->Rsp = (DWORD64)stack_pointer;
355 | context->Rbp = 0;
356 | context->Rip = (DWORD64)executor_function;
357 | context->ContextFlags = CONTEXT_FULL;
358 | #elif FOUNDATION_PLATFORM_POSIX
359 | ucontext_t* context = fiber->context;
360 | FOUNDATION_UNUSED(was_initialized);
361 | #if FOUNDATION_PLATFORM_APPLE
362 | memset(fiber->context, 0, sizeof(ucontext_t));
363 | context->uc_mcontext = fiber->tib;
364 | context->uc_mcsize = sizeof(*context->uc_mcontext);
365 | #else
366 | if (!was_initialized) {
367 | memset(fiber->context, 0, sizeof(ucontext_t));
368 | getcontext(context);
369 | }
370 | #endif
371 | context->uc_stack.ss_sp = pointer_offset(fiber->stack, -(ssize_t)fiber->stack_size);
372 | context->uc_stack.ss_size = fiber->stack_size;
373 |
374 | // Deconstruct 64bit pointers
375 | int executor_low = (int)((uintptr_t)executor & 0xFFFFFFFFULL);
376 | int executor_high = (int)((uintptr_t)executor >> 32ULL);
377 | int fiber_low = (int)((uintptr_t)fiber & 0xFFFFFFFFULL);
378 | int fiber_high = (int)((uintptr_t)fiber >> 32ULL);
379 |
380 | makecontext(context, (void (*)(void))executor_function, 10, 0, 1, 2, 3, 4, 5, executor_low, executor_high,
381 | fiber_low, fiber_high);
382 | #else
383 | #error Not implemented
384 | #endif
385 | }
386 |
387 | FOUNDATION_NOINLINE void
388 | task_fiber_switch(task_fiber_t* from, task_fiber_t* to) {
389 | FOUNDATION_ASSERT(to != nullptr);
390 | FOUNDATION_ASSERT(!to->fiber_next);
391 | if (from)
392 | to->fiber_return = from;
393 |
394 | task_executor_thread_current()->fiber_current = to;
395 |
396 | #if BUILD_ENABLE_ERROR_CONTEXT
397 | error_context_set(to->error_context);
398 | #endif
399 |
400 | #if FOUNDATION_PLATFORM_WINDOWS
401 | BOOL res;
402 | HANDLE thread = GetCurrentThread();
403 | CONTEXT* to_context = to->context;
404 |
405 | // Copy stack pointers to new thread information block
406 | NT_TIB* thread_tib = (NT_TIB*)NtCurrentTeb();
407 | NT_TIB* fiber_tib = (NT_TIB*)to->tib;
408 | thread_tib->StackBase = fiber_tib->StackBase;
409 | thread_tib->StackLimit = fiber_tib->StackLimit;
410 |
411 | // Switch to fiber context
412 | res = SetThreadContext(thread, to_context);
413 | if (!FOUNDATION_VALIDATE_MSG(res != 0, "Failed to switch current fiber context")) {
414 | exception_raise_abort();
415 | }
416 | #elif FOUNDATION_PLATFORM_POSIX
417 | int res = setcontext(to->context);
418 | if (!FOUNDATION_VALIDATE_MSG(res == 0, "Failed to switch current fiber context")) {
419 | exception_raise_abort();
420 | }
421 | #else
422 | #error Not implemented
423 | #endif
424 | }
425 |
426 | static FOUNDATION_NOINLINE void
427 | task_fiber_push_waiting_and_yield(volatile void* stack_reserve, task_fiber_t* fiber, atomic32_t* counter) {
428 | FOUNDATION_UNUSED(stack_reserve);
429 | task_scheduler_push_fiber_waiting_and_yield(task_executor_thread_current()->scheduler, fiber, counter);
430 | }
431 |
432 | FOUNDATION_NOINLINE void
433 | task_fiber_yield(task_fiber_t* fiber, atomic32_t* counter) {
434 | FOUNDATION_ASSERT_MSG(fiber->state == TASK_FIBER_RUNNING, "Yielding a non-running fiber is not allowed");
435 | if (fiber->state != TASK_FIBER_RUNNING)
436 | return;
437 | #if BUILD_ENABLE_ERROR_CONTEXT
438 | fiber->error_context = error_context_set(nullptr);
439 | #endif
440 | #if FOUNDATION_PLATFORM_WINDOWS
441 | HANDLE thread = GetCurrentThread();
442 | CONTEXT* context = fiber->context;
443 | BOOL res = GetThreadContext(thread, context);
444 | if (!FOUNDATION_VALIDATE_MSG(res != 0, "Failed to store current fiber context in fiber yield")) {
445 | exception_raise_abort();
446 | return;
447 | }
448 | #elif FOUNDATION_PLATFORM_POSIX
449 | getcontext(fiber->context);
450 | #else
451 | #error Not implemented
452 | #endif
453 | if (fiber->state == TASK_FIBER_RUNNING) {
454 | atomic_thread_fence_release();
455 | volatile void* stack_reserve = alloca(256);
456 | task_fiber_push_waiting_and_yield(stack_reserve, fiber, counter);
457 | }
458 | if (fiber->state == TASK_FIBER_YIELD) {
459 | fiber->state = TASK_FIBER_RUNNING;
460 | }
461 | }
462 |
--------------------------------------------------------------------------------
/task/fiber.h:
--------------------------------------------------------------------------------
1 | /* fiber.h - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | *
16 | */
17 |
18 | #pragma once
19 |
20 | /*! \file fiber.h
21 | Task fiber abstraction */
22 |
23 | #include
24 |
25 | #include
26 | #include
27 |
28 | /*! Initialize a fiber for calling a
29 | * \param fiber Fiber control structure
30 | * \return true if success, false if error
31 | */
32 | TASK_API bool
33 | task_fiber_initialize_from_current_thread(task_fiber_t* fiber);
34 |
35 | /*! Initialize a fiber for executing a task
36 | * \param fiber Fiber control structure
37 | */
38 | TASK_API bool
39 | task_fiber_initialize(task_fiber_t* fiber);
40 |
41 | /*! Switch fiber
42 | * \param from Fiber to switch from
43 | * \param to Fiber to switch to
44 | */
45 | TASK_API void
46 | task_fiber_switch(task_fiber_t* from, task_fiber_t* to);
47 |
48 | /*! Yield fiber
49 | * \param fiber Fiber to yield
50 | * \param counter Counter to wait on
51 | */
52 | TASK_API void
53 | task_fiber_yield(task_fiber_t* fiber, atomic32_t* counter);
54 |
55 | /*! Get the current fiber executing in this thread
56 | * \return Fiber executing in this thread, null if none */
57 | TASK_API task_fiber_t*
58 | task_fiber_current(void);
59 |
--------------------------------------------------------------------------------
/task/hashstrings.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | /* ****** AUTOMATICALLY GENERATED, DO NOT EDIT ******
6 | Edit corresponding definitions file and rerun
7 | the foundation hashify tool to update this file */
8 |
9 | #define HASH_TASK static_hash_string("task", 4, 0x1172f53a50ad4fc0ULL)
10 |
--------------------------------------------------------------------------------
/task/hashstrings.txt:
--------------------------------------------------------------------------------
1 |
2 | HASH_TASK task
3 |
--------------------------------------------------------------------------------
/task/scheduler.h:
--------------------------------------------------------------------------------
1 | /* scheduler.h - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | *
16 | */
17 |
18 | #pragma once
19 |
20 | /*! \file scheduler.h
21 | Task scheduler */
22 |
23 | #include
24 |
25 | #include
26 | #include
27 |
28 | /*! Allocate a scheduler
29 | \param executor_count Number of executor threads
30 | \param fiber_count Number of fibers
31 | \return New task scheduler */
32 | TASK_API task_scheduler_t*
33 | task_scheduler_allocate(size_t executor_count, size_t fiber_count);
34 |
35 | /*! Deallocate a scheduler
36 | \param scheduler Task scheduler */
37 | TASK_API void
38 | task_scheduler_deallocate(task_scheduler_t* scheduler);
39 |
40 | /*! Queue a task
41 | \param scheduler Task scheduler
42 | \param task Task */
43 | TASK_API void
44 | task_scheduler_queue(task_scheduler_t* scheduler, task_t task);
45 |
46 | /*! Queue multiple tasks
47 | \param scheduler Task scheduler
48 | \param task Tasks
49 | \param task_count Number of tasks */
50 | TASK_API void
51 | task_scheduler_multiqueue(task_scheduler_t* scheduler, task_t* task, size_t task_count);
52 |
53 | /*! Pop the next task from the scheduler queue
54 | * \param scheduler Task scheduler
55 | * \param task Task structure to fill */
56 | TASK_API bool
57 | task_scheduler_next_task(task_scheduler_t* scheduler, task_t* task);
58 |
59 | /*! Pop a free fiber from the scheduler pool
60 | * \param scheduler Task scheduler
61 | * \return Free fiber control structure */
62 | TASK_API task_fiber_t*
63 | task_scheduler_next_free_fiber(task_scheduler_t* scheduler);
64 |
65 | /*! Add fiber as waiting on subtask counter
66 | * \param scheduler Scheduler
67 | * \param fiber Fiber
68 | * \param counter Subtask counter
69 | * \return true if fiber is ready to execute, false if waiting on subtask counter */
70 | TASK_API bool
71 | task_scheduler_push_fiber_waiting_and_yield(task_scheduler_t* scheduler, task_fiber_t* fiber, atomic32_t* counter);
72 |
73 | /*! Get fiber that was waiting for the given counter
74 | * \param scheduler Scheduler
75 | * \param counter Subtask counter
76 | * \return Fiber that was waiting for the given subtask counter */
77 | TASK_API task_fiber_t*
78 | task_scheduler_pop_fiber_waiting(task_scheduler_t* scheduler, atomic32_t* counter);
79 |
--------------------------------------------------------------------------------
/task/task.c:
--------------------------------------------------------------------------------
1 | /* task.c - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | *
16 | */
17 |
18 | #include "task.h"
19 |
20 | #include
21 |
22 | #if FOUNDATION_PLATFORM_POSIX
23 | #include
24 | #endif
25 |
26 | static task_config_t task_config;
27 | static bool task_initialized;
28 |
29 | static void
30 | task_module_initialize_config(const task_config_t config) {
31 | task_config = config;
32 |
33 | #if FOUNDATION_PLATFORM_POSIX
34 | size_t min_stack_size = (size_t)MINSIGSTKSZ;
35 | #if BUILD_DEBUG
36 | size_t default_stack_size = 128 * 1024;
37 | #else
38 | size_t default_stack_size = 64 * 1024;
39 | #endif
40 | size_t max_stack_size = 2 * 1024 * 1024;
41 | #else
42 | size_t min_stack_size = 8 * 1024;
43 | size_t default_stack_size = 64 * 1024;
44 | size_t max_stack_size = 2 * 1024 * 1024;
45 | #endif
46 |
47 | if (!task_config.fiber_stack_size)
48 | task_config.fiber_stack_size = default_stack_size;
49 | else if (task_config.fiber_stack_size < min_stack_size)
50 | task_config.fiber_stack_size = min_stack_size;
51 | else if (task_config.fiber_stack_size > max_stack_size)
52 | task_config.fiber_stack_size = max_stack_size;
53 | }
54 |
55 | int
56 | task_module_initialize(const task_config_t config) {
57 | if (task_initialized)
58 | return 0;
59 |
60 | task_module_initialize_config(config);
61 |
62 | task_initialized = true;
63 |
64 | return 0;
65 | }
66 |
67 | bool
68 | task_module_is_initialized(void) {
69 | return task_initialized;
70 | }
71 |
72 | task_config_t
73 | task_module_config(void) {
74 | return task_config;
75 | }
76 |
77 | void
78 | task_module_finalize(void) {
79 | task_initialized = false;
80 | }
81 |
82 | extern task_executor_t*
83 | task_executor_thread_current(void);
84 |
85 | FOUNDATION_NOINLINE void
86 | task_yield_and_wait(atomic32_t* counter) {
87 | if (!counter)
88 | return;
89 | task_executor_t* executor = task_executor_thread_current();
90 | if (executor) {
91 | if (atomic_incr32(counter, memory_order_relaxed) > 1)
92 | task_fiber_yield(executor->fiber_current, counter);
93 | else
94 | atomic_decr32(counter, memory_order_relaxed);
95 | } else {
96 | // TODO: Do a task executor step instead of yielding thread slice
97 | while (atomic_load32(counter, memory_order_relaxed))
98 | thread_yield();
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/task/task.h:
--------------------------------------------------------------------------------
1 | /* task.h - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | *
16 | */
17 |
18 | #pragma once
19 |
20 | /*! \file task.h
21 | Task library entry points */
22 |
23 | #include
24 |
25 | #include
26 | #include
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | /*! Initialize task library
33 | \param config Task library configuration
34 | \return 0 if success, <0 if error */
35 | TASK_API int
36 | task_module_initialize(const task_config_t config);
37 |
38 | /*! Finalize task library */
39 | TASK_API void
40 | task_module_finalize(void);
41 |
42 | /*! Query if task library is initialized
43 | \return true if initialized, false if not */
44 | TASK_API bool
45 | task_module_is_initialized(void);
46 |
47 | /*! Get the task library config
48 | \return Current configuration */
49 | TASK_API task_config_t
50 | task_module_config(void);
51 |
52 | /* Get task library version
53 | \return Task library version */
54 | TASK_API version_t
55 | task_module_version(void);
56 |
57 | /*! Main task synchronization point, yield execution and wait for subtasks to complete before continuing
58 | * \param counter Subtask counter to wait on */
59 | TASK_API FOUNDATION_NOINLINE void
60 | task_yield_and_wait(atomic32_t* counter);
61 |
--------------------------------------------------------------------------------
/task/types.h:
--------------------------------------------------------------------------------
1 | /* types.h - Task library - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any
15 | * restrictions.
16 | *
17 | */
18 |
19 | #pragma once
20 |
21 | /*! \file types.h
22 | Task data types */
23 |
24 | #include
25 | #include
26 |
27 | #include
28 |
29 | #if defined(TASK_COMPILE) && TASK_COMPILE
30 | #ifdef __cplusplus
31 | #define TASK_EXTERN extern "C"
32 | #define TASK_API extern "C"
33 | #else
34 | #define TASK_EXTERN extern
35 | #define TASK_API extern
36 | #endif
37 | #else
38 | #ifdef __cplusplus
39 | #define TASK_EXTERN extern "C"
40 | #define TASK_API extern "C"
41 | #else
42 | #define TASK_EXTERN extern
43 | #define TASK_API extern
44 | #endif
45 | #endif
46 |
47 | /*! Task library configuration */
48 | typedef struct task_config_t task_config_t;
49 | /*! Task declaration */
50 | typedef struct task_t task_t;
51 | /*! Task scheduler control */
52 | typedef struct task_scheduler_t task_scheduler_t;
53 | /*! Task executor thread control */
54 | typedef struct task_executor_t task_executor_t;
55 | /*! Task fiber control */
56 | typedef struct task_fiber_t task_fiber_t;
57 | /*! Block of tasks in a queue */
58 | typedef struct task_queue_block_t task_queue_block_t;
59 |
60 | /*! Context type for a task */
61 | typedef void* task_context_t;
62 | /*! Counter for task dependencies and synchronization */
63 | typedef atomic32_t task_counter_t;
64 |
65 | /*! Task function */
66 | typedef void (*task_fn)(task_context_t context);
67 |
68 | /*! Number of tasks in one queue block */
69 | #define TASK_QUEUE_BLOCK_CAPACITY 256
70 |
71 | typedef enum task_fiber_state {
72 | TASK_FIBER_NOT_INITIALIZED = 0,
73 | TASK_FIBER_THREAD,
74 | TASK_FIBER_EXECUTOR,
75 | TASK_FIBER_FREE,
76 | TASK_FIBER_RUNNING,
77 | TASK_FIBER_YIELD,
78 | TASK_FIBER_FINISHED
79 | } task_fiber_state;
80 |
81 | /*! Task declaration */
82 | struct task_t {
83 | /*! Function to execute */
84 | task_fn function;
85 | /*! Task context */
86 | task_context_t context;
87 | /*! Task counter */
88 | atomic32_t* counter;
89 | };
90 |
91 | /*! Block of tasks in a queue */
92 | struct task_queue_block_t {
93 | /*! Tasks */
94 | task_t task[TASK_QUEUE_BLOCK_CAPACITY];
95 | /*! Read offset */
96 | size_t read;
97 | /*! Write offset */
98 | size_t write;
99 | /*! Next task block */
100 | task_queue_block_t* block_next;
101 | };
102 |
103 | /*! Task executor control */
104 | struct task_executor_t {
105 | /*! Owning task scheduler */
106 | task_scheduler_t* scheduler;
107 | /*! Index of executor in scheduler */
108 | size_t index;
109 | /*! Execution thread */
110 | thread_t thread;
111 | /*! Thread fiber */
112 | task_fiber_t* self_fiber;
113 | /*! Currently executing fiber */
114 | task_fiber_t* fiber_current;
115 | /*! Free fiber (local to executor, cannot be accessed outside executor context) */
116 | task_fiber_t* fiber_free;
117 | /*! Fiber that was just put in waiting hold (local to executor, cannot be accessed outside executor context) */
118 | task_fiber_t* fiber_waiting_release;
119 | /*! First finished fiber index (linked list) */
120 | task_fiber_t* fiber_finished;
121 | /*! List mutex */
122 | mutex_t* fiber_finished_lock;
123 | };
124 |
125 | /*! Task fiber control */
126 | struct task_fiber_t {
127 | /*! Context */
128 | void* context;
129 | /*! Thread information block */
130 | void* tib;
131 | /*! Stack pointer */
132 | void* stack;
133 | /*! Stack size */
134 | size_t stack_size;
135 | /*! Index in scheduler fiber array */
136 | uint index;
137 | /*! State */
138 | task_fiber_state state;
139 | /*! Task */
140 | task_t task;
141 | /*! Counter we are waiting on */
142 | atomic32_t* waiting_counter;
143 | /*! Fiber to return to after execution finishes */
144 | task_fiber_t* fiber_return;
145 | /*! Old fiber that should be released */
146 | task_fiber_t* fiber_pending_finished;
147 | /*! Next fiber in a linked list */
148 | task_fiber_t* fiber_next;
149 | /*! Error context */
150 | void* error_context;
151 | /*! Platform data */
152 | char platform_data[FOUNDATION_FLEXIBLE_ARRAY];
153 | };
154 |
155 | /*! Task scheduler control */
156 | struct task_scheduler_t {
157 | /*! Total size of memory block */
158 | size_t control_block_size;
159 | /*! Executors */
160 | task_executor_t* executor;
161 | /*! Number of executors */
162 | size_t executor_count;
163 | /*! Fibers */
164 | task_fiber_t** fiber;
165 | /*! Number of fibers */
166 | size_t fiber_count;
167 | /*! Total size of a fiber control block */
168 | size_t fiber_size;
169 | /*! Size of fiber context */
170 | size_t fiber_context_size;
171 | /*! Size of fiber tib */
172 | size_t fiber_tib_size;
173 | /*! Wakeup signal */
174 | semaphore_t signal;
175 | /*! Running flag */
176 | atomic32_t running;
177 | /*! Free fibers */
178 | task_fiber_t* fiber_free;
179 | /*! Current task block */
180 | task_queue_block_t* task_queue_block;
181 | /*! Last queued task block */
182 | task_queue_block_t* task_queue_block_tail;
183 | /*! Free task blocks */
184 | task_queue_block_t* task_free_block;
185 | /*! Waiting tasks/fibers */
186 | hashmap_t* fiber_waiting;
187 | /*! Lock for task blocks */
188 | mutex_t* task_lock;
189 | /*! Lock for free fibers */
190 | mutex_t* fiber_lock;
191 | /*! Lock for waiting fibers */
192 | mutex_t* waiting_lock;
193 | /* Additional fiber blocks */
194 | task_fiber_t** additional_fiber;
195 | };
196 |
197 | /*! Task library config */
198 | struct task_config_t {
199 | /*! Fiber stack size */
200 | size_t fiber_stack_size;
201 | };
202 |
--------------------------------------------------------------------------------
/task/version.c:
--------------------------------------------------------------------------------
1 | /* ****** AUTOMATICALLY GENERATED, DO NOT EDIT ******
2 | This file is generated from the git describe command.
3 | Run the configure script to regenerate this file */
4 |
5 | #include
6 | #include
7 |
8 | version_t
9 | task_module_version(void) {
10 | return version_make(0, 0, 1, 0, 0x0);
11 | }
12 |
--------------------------------------------------------------------------------
/test/all/android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/test/all/android/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/android/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/test/all/android/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/android/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/test/all/android/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/android/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/test/all/android/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/android/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/test/all/android/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/android/drawable-xxhdpi/icon.png
--------------------------------------------------------------------------------
/test/all/android/drawable-xxxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/android/drawable-xxxhdpi/icon.png
--------------------------------------------------------------------------------
/test/all/android/java/com/maniccoder/task/test/TestActivity.java:
--------------------------------------------------------------------------------
1 | package com.maniccoder.task.test;
2 |
3 | import android.os.Bundle;
4 | import android.app.NativeActivity;
5 | import android.graphics.Color;
6 | import android.graphics.Point;
7 | import android.widget.TextView;
8 | import android.util.Log;
9 | import android.widget.LinearLayout;
10 | import android.widget.PopupWindow;
11 | import android.view.Gravity;
12 | import android.view.Display;
13 | import android.view.ViewGroup;
14 | import android.view.ViewGroup.LayoutParams;
15 | import android.view.ViewGroup.MarginLayoutParams;
16 |
17 | public class TestActivity extends NativeActivity
18 | {
19 | private TextView textView;
20 | private boolean displayedTextView = false;
21 |
22 | @Override
23 | public void onWindowFocusChanged( boolean hasFocus )
24 | {
25 | super.onWindowFocusChanged( hasFocus );
26 |
27 | if( !displayedTextView && hasFocus )
28 | {
29 | displayedTextView = true;
30 |
31 | setContentView( R.layout.main );
32 |
33 | textView = (TextView)findViewById( R.id.logtext );
34 | textView.setText( "" );
35 | ((ViewGroup)textView.getParent()).removeView(textView);
36 |
37 | final TestActivity activity = this;
38 |
39 | runOnUiThread( new Runnable() {
40 |
41 | @Override
42 | public void run()
43 | {
44 | PopupWindow popup = new PopupWindow( activity );
45 |
46 | Display display = getWindowManager().getDefaultDisplay();
47 | Point size = new Point();
48 | display.getSize( size );
49 |
50 | popup.setWidth( size.x );
51 | popup.setHeight( size.y );
52 | popup.setWindowLayoutMode( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT );
53 | popup.setClippingEnabled( false );
54 |
55 | MarginLayoutParams params = new MarginLayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT );
56 | params.setMargins(0, 0, 0, 0);
57 |
58 | LinearLayout layout = new LinearLayout( activity );
59 | layout.setOrientation( LinearLayout.VERTICAL );
60 | layout.addView( activity.textView, params );
61 |
62 | popup.setContentView( layout );
63 |
64 | final ViewGroup viewGroup = (ViewGroup)((ViewGroup)activity.findViewById( android.R.id.content )).getChildAt(0);
65 |
66 | popup.showAtLocation( viewGroup, Gravity.TOP, 0, 0 );
67 | popup.update();
68 | }
69 | } );
70 | }
71 | }
72 |
73 | public void appendLog( final String msg )
74 | {
75 | runOnUiThread( new Runnable() {
76 | @Override
77 | public void run()
78 | {
79 | if( textView != null )
80 | textView.append( msg );
81 | }
82 | } );
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/test/all/android/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/test/all/android/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Task Test Suite
4 |
5 |
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "icon_29.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "icon_58.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "40x40",
17 | "idiom" : "iphone",
18 | "filename" : "icon_80-1.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "57x57",
23 | "idiom" : "iphone",
24 | "filename" : "icon_57.png",
25 | "scale" : "1x"
26 | },
27 | {
28 | "size" : "57x57",
29 | "idiom" : "iphone",
30 | "filename" : "icon_114.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "icon_120.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "icon_180.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "icon_29-1.png",
49 | "scale" : "1x"
50 | },
51 | {
52 | "size" : "29x29",
53 | "idiom" : "ipad",
54 | "filename" : "icon_58-1.png",
55 | "scale" : "2x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "icon_40.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "40x40",
65 | "idiom" : "ipad",
66 | "filename" : "icon_80.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "50x50",
71 | "idiom" : "ipad",
72 | "filename" : "icon_50.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "50x50",
77 | "idiom" : "ipad",
78 | "filename" : "icon_100.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "72x72",
83 | "idiom" : "ipad",
84 | "filename" : "icon_72.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "72x72",
89 | "idiom" : "ipad",
90 | "filename" : "icon_144.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "icon_76.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "icon_152.png",
103 | "scale" : "2x"
104 | }
105 | ],
106 | "info" : {
107 | "version" : 1,
108 | "author" : "xcode"
109 | }
110 | }
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_100.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_114.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_120.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_144.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_152.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_180.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_29-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_29-1.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_29.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_40.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_50.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_57.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_58-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_58-1.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_58.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_72.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_76.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_80-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_80-1.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/AppIcon.appiconset/icon_80.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "filename" : "launch_640_960.png",
9 | "scale" : "2x"
10 | },
11 | {
12 | "extent" : "full-screen",
13 | "idiom" : "iphone",
14 | "subtype" : "retina4",
15 | "filename" : "launch_640_1136.png",
16 | "minimum-system-version" : "7.0",
17 | "orientation" : "portrait",
18 | "scale" : "2x"
19 | },
20 | {
21 | "orientation" : "portrait",
22 | "idiom" : "ipad",
23 | "extent" : "full-screen",
24 | "minimum-system-version" : "7.0",
25 | "filename" : "launch_768_1024.png",
26 | "scale" : "1x"
27 | },
28 | {
29 | "orientation" : "landscape",
30 | "idiom" : "ipad",
31 | "extent" : "full-screen",
32 | "minimum-system-version" : "7.0",
33 | "filename" : "launch_1024_768.png",
34 | "scale" : "1x"
35 | },
36 | {
37 | "orientation" : "portrait",
38 | "idiom" : "ipad",
39 | "extent" : "full-screen",
40 | "minimum-system-version" : "7.0",
41 | "filename" : "launch_1536_2048.png",
42 | "scale" : "2x"
43 | },
44 | {
45 | "orientation" : "landscape",
46 | "idiom" : "ipad",
47 | "extent" : "full-screen",
48 | "minimum-system-version" : "7.0",
49 | "filename" : "launch_2048_1536.png",
50 | "scale" : "2x"
51 | },
52 | {
53 | "orientation" : "portrait",
54 | "idiom" : "iphone",
55 | "extent" : "full-screen",
56 | "filename" : "launch_320_480.png",
57 | "scale" : "1x"
58 | },
59 | {
60 | "orientation" : "portrait",
61 | "idiom" : "iphone",
62 | "extent" : "full-screen",
63 | "filename" : "launch_640_960.png",
64 | "scale" : "2x"
65 | },
66 | {
67 | "orientation" : "portrait",
68 | "idiom" : "iphone",
69 | "extent" : "full-screen",
70 | "filename" : "launch_640_1136.png",
71 | "subtype" : "retina4",
72 | "scale" : "2x"
73 | },
74 | {
75 | "orientation" : "portrait",
76 | "idiom" : "ipad",
77 | "extent" : "to-status-bar",
78 | "filename" : "launch_768_1004.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "orientation" : "landscape",
83 | "idiom" : "ipad",
84 | "extent" : "to-status-bar",
85 | "filename" : "launch_1024_748.png",
86 | "scale" : "1x"
87 | },
88 | {
89 | "orientation" : "portrait",
90 | "idiom" : "ipad",
91 | "extent" : "to-status-bar",
92 | "filename" : "launch_1536_2008.png",
93 | "scale" : "2x"
94 | },
95 | {
96 | "orientation" : "landscape",
97 | "idiom" : "ipad",
98 | "extent" : "to-status-bar",
99 | "filename" : "launch_2048_1496.png",
100 | "scale" : "2x"
101 | }
102 | ],
103 | "info" : {
104 | "version" : 1,
105 | "author" : "xcode"
106 | }
107 | }
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_1024_748.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_1024_748.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_1024_768.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_1024_768.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_1536_2008.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_1536_2008.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_1536_2048.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_1536_2048.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_2048_1496.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_2048_1496.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_2048_1536.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_2048_1536.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_320_480.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_320_480.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_640_1136.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_640_1136.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_640_960.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_640_960.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_768_1004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_768_1004.png
--------------------------------------------------------------------------------
/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_768_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/ios/Images.xcassets/LaunchImage.launchimage/launch_768_1024.png
--------------------------------------------------------------------------------
/test/all/ios/test-all.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.maniccoder.task.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | Foundation
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | TEST
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSMainNibFile
26 | test-all
27 | NSMainNibFile~ipad
28 | test-all
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UIStatusBarHidden
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 | UIInterfaceOrientationPortraitUpsideDown
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/test/all/ios/test-all.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/test/all/ios/viewcontroller.h:
--------------------------------------------------------------------------------
1 | /* viewcontroller.h - Foundation test launcher - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform foundation library in C11 providing basic support
4 | * data types and functions to write applications and games in a platform-independent fashion.
5 | * The latest source code is always available at
6 | *
7 | * https://github.com/mjansson/foundation_lib
8 | *
9 | * This library is put in the public domain; you can redistribute it and/or modify it without
10 | * any restrictions.
11 | */
12 |
13 | #pragma once
14 |
15 | #include
16 | #include
17 |
18 | #ifdef __OBJC__
19 |
20 | @interface ViewController : UIViewController {
21 | @public
22 | }
23 | @end
24 |
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/test/all/ios/viewcontroller.m:
--------------------------------------------------------------------------------
1 | /* viewcontroller.m - Foundation test launcher - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform foundation library in C11 providing basic support
4 | * data types and functions to write applications and games in a platform-independent fashion.
5 | * The latest source code is always available at
6 | *
7 | * https://github.com/mjansson/foundation_lib
8 | *
9 | * This library is put in the public domain; you can redistribute it and/or modify it without
10 | * any restrictions.
11 | */
12 |
13 | #include "viewcontroller.h"
14 |
15 | @interface ViewController()
16 | @end
17 |
18 | @implementation ViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 |
23 | if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)])
24 | [self setNeedsStatusBarAppearanceUpdate];
25 | else
26 | [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
27 | }
28 |
29 | - (void)didReceiveMemoryWarning {
30 | [super didReceiveMemoryWarning];
31 | }
32 |
33 | - (BOOL)prefersStatusBarHidden {
34 | return TRUE;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/test/all/main.c:
--------------------------------------------------------------------------------
1 | /* main.c - Foundation test launcher - Public Domain - 2013 Mattias Jansson
2 | *
3 | * This library provides a cross-platform foundation library in C11 providing basic support
4 | * data types and functions to write applications and games in a platform-independent fashion.
5 | * The latest source code is always available at
6 | *
7 | * https://github.com/mjansson/foundation_lib
8 | *
9 | * This library is put in the public domain; you can redistribute it and/or modify it without
10 | * any restrictions.
11 | */
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | static volatile bool test_should_start_flag;
18 | static volatile bool test_have_focus_flag;
19 | static volatile bool test_should_terminate_flag;
20 | static volatile bool test_memory_tracker;
21 |
22 | static void*
23 | event_loop(void* arg) {
24 | event_block_t* block;
25 | event_t* event = 0;
26 | FOUNDATION_UNUSED(arg);
27 |
28 | event_stream_set_beacon(system_event_stream(), &thread_self()->beacon);
29 |
30 | while (!test_should_terminate_flag) {
31 | block = event_stream_process(system_event_stream());
32 | event = 0;
33 | while ((event = event_next(block, event))) {
34 | switch (event->id) {
35 | case FOUNDATIONEVENT_START:
36 | #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID
37 | log_debug(HASH_TEST, STRING_CONST("Application start event received"));
38 | test_should_start_flag = true;
39 | #endif
40 | break;
41 |
42 | case FOUNDATIONEVENT_TERMINATE:
43 | #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID
44 | log_debug(HASH_TEST, STRING_CONST("Application stop/terminate event received"));
45 | test_should_terminate_flag = true;
46 | break;
47 | #else
48 | log_warn(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Terminating tests due to event"));
49 | process_exit(-2);
50 | #endif
51 |
52 | case FOUNDATIONEVENT_FOCUS_GAIN:
53 | test_have_focus_flag = true;
54 | break;
55 |
56 | case FOUNDATIONEVENT_FOCUS_LOST:
57 | test_have_focus_flag = false;
58 | break;
59 |
60 | default:
61 | break;
62 | }
63 | }
64 | thread_wait();
65 | }
66 |
67 | log_debug(HASH_TEST, STRING_CONST("Application event thread exiting"));
68 |
69 | return 0;
70 | }
71 |
72 | #if (FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID) && BUILD_ENABLE_LOG
73 |
74 | #if FOUNDATION_PLATFORM_ANDROID
75 | #include
76 | #include
77 | #endif
78 |
79 | #include
80 | #include
81 |
82 | static void
83 | test_log_handler(hash_t context, error_level_t severity, const char* msg, size_t length) {
84 | FOUNDATION_UNUSED(context);
85 | FOUNDATION_UNUSED(severity);
86 |
87 | if (test_should_terminate_flag)
88 | return;
89 |
90 | #if FOUNDATION_PLATFORM_IOS
91 | test_text_view_append(delegate_uiwindow(), 1, msg, length);
92 | #elif FOUNDATION_PLATFORM_ANDROID
93 | jclass test_log_class = 0;
94 | jmethodID test_log_append = 0;
95 | const struct JNINativeInterface** jnienv = thread_attach_jvm();
96 | test_log_class = (*jnienv)->GetObjectClass(jnienv, android_app()->activity->clazz);
97 | if (test_log_class)
98 | test_log_append = (*jnienv)->GetMethodID(jnienv, test_log_class, "appendLog", "(Ljava/lang/String;)V");
99 | if (test_log_append) {
100 | jstring jstr = (*jnienv)->NewStringUTF(jnienv, msg);
101 | (*jnienv)->CallVoidMethod(jnienv, android_app()->activity->clazz, test_log_append, jstr);
102 | (*jnienv)->DeleteLocalRef(jnienv, jstr);
103 | }
104 | thread_detach_jvm();
105 | FOUNDATION_UNUSED(length);
106 | #endif
107 | }
108 |
109 | #endif
110 |
111 | #if !BUILD_MONOLITHIC
112 |
113 | void
114 | test_exception_handler(const char* dump_file, size_t length) {
115 | FOUNDATION_UNUSED(dump_file);
116 | FOUNDATION_UNUSED(length);
117 | log_error(HASH_TEST, ERROR_EXCEPTION, STRING_CONST("Test raised exception"));
118 | process_exit(-1);
119 | }
120 |
121 | #endif
122 |
123 | bool
124 | test_should_terminate(void) {
125 | return test_should_terminate_flag;
126 | }
127 |
128 | int
129 | main_initialize(void) {
130 | foundation_config_t config;
131 | application_t application;
132 | int ret;
133 | size_t iarg, asize;
134 | const string_const_t* cmdline = environment_command_line();
135 |
136 | test_memory_tracker = true;
137 | for (iarg = 0, asize = array_size(cmdline); iarg < asize; ++iarg) {
138 | if (string_equal(STRING_ARGS(cmdline[iarg]), STRING_CONST("--no-memory-tracker")))
139 | test_memory_tracker = false;
140 | }
141 |
142 | if (test_memory_tracker)
143 | memory_set_tracker(memory_tracker_local());
144 |
145 | memset(&config, 0, sizeof(config));
146 |
147 | memset(&application, 0, sizeof(application));
148 | application.name = string_const(STRING_CONST("Task library test suite"));
149 | application.short_name = string_const(STRING_CONST("test_all"));
150 | application.company = string_const(STRING_CONST(""));
151 | application.version = task_module_version();
152 | application.flags = APPLICATION_UTILITY;
153 | application.exception_handler = test_exception_handler;
154 |
155 | log_set_suppress(0, ERRORLEVEL_INFO);
156 |
157 | #if (FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID) && BUILD_ENABLE_LOG
158 | log_set_handler(test_log_handler);
159 | #endif
160 |
161 | #if !FOUNDATION_PLATFORM_IOS && !FOUNDATION_PLATFORM_ANDROID
162 |
163 | test_should_start_flag = true;
164 |
165 | #endif
166 |
167 | ret = foundation_initialize(memory_system_malloc(), application, config);
168 |
169 | #if BUILD_MONOLITHIC
170 | if (ret == 0) {
171 | task_config_t task_config;
172 | memset(&task_config, 0, sizeof(task_config));
173 | ret = task_module_initialize(task_config);
174 |
175 | test_set_suitable_working_directory();
176 | }
177 | #endif
178 | return ret;
179 | }
180 |
181 | #if FOUNDATION_PLATFORM_ANDROID
182 | #include
183 | #endif
184 |
185 | #if BUILD_MONOLITHIC
186 | extern int
187 | test_task_run(void);
188 | typedef int (*test_run_fn)(void);
189 |
190 | static void*
191 | test_runner(void* arg) {
192 | test_run_fn* tests = (test_run_fn*)arg;
193 | int test_fn = 0;
194 | int process_result = 0;
195 |
196 | while (tests[test_fn] && (process_result >= 0)) {
197 | if ((process_result = tests[test_fn]()) >= 0)
198 | log_infof(HASH_TEST, STRING_CONST("All tests passed (%d)"), process_result);
199 | ++test_fn;
200 | }
201 |
202 | return (void*)(intptr_t)process_result;
203 | }
204 |
205 | #endif
206 |
207 | int
208 | main_run(void* main_arg) {
209 | #if !BUILD_MONOLITHIC
210 | string_const_t pattern;
211 | string_t* exe_paths = 0;
212 | size_t iexe, exesize;
213 | process_t* process = 0;
214 | string_t process_path = {0, 0};
215 | unsigned int* exe_flags = 0;
216 | #else
217 | void* test_result;
218 | #endif
219 | #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID
220 | int remain_counter = 0;
221 | #endif
222 | #if BUILD_DEBUG
223 | const string_const_t build_name = string_const(STRING_CONST("debug"));
224 | #elif BUILD_RELEASE
225 | const string_const_t build_name = string_const(STRING_CONST("release"));
226 | #elif BUILD_PROFILE
227 | const string_const_t build_name = string_const(STRING_CONST("profile"));
228 | #elif BUILD_DEPLOY
229 | const string_const_t build_name = string_const(STRING_CONST("deploy"));
230 | #endif
231 | #if BUILD_MONOLITHIC
232 | const string_const_t build_type = string_const(STRING_CONST(" monolithic"));
233 | #else
234 | const string_const_t build_type = string_empty();
235 | #endif
236 | char* pathbuf;
237 | int process_result = 0;
238 | thread_t event_thread;
239 | FOUNDATION_UNUSED(main_arg);
240 | FOUNDATION_UNUSED(build_name);
241 |
242 | log_set_suppress(HASH_TEST, ERRORLEVEL_DEBUG);
243 |
244 | log_infof(HASH_TEST, STRING_CONST("Task library v%s built for %s using %s (%.*s%.*s)"),
245 | string_from_version_static(task_module_version()).str, FOUNDATION_PLATFORM_DESCRIPTION,
246 | FOUNDATION_COMPILER_DESCRIPTION, STRING_FORMAT(build_name), STRING_FORMAT(build_type));
247 |
248 | thread_initialize(&event_thread, event_loop, 0, STRING_CONST("event_thread"), THREAD_PRIORITY_NORMAL, 0);
249 | thread_start(&event_thread);
250 |
251 | pathbuf = memory_allocate(HASH_STRING, BUILD_MAX_PATHLEN, 0, MEMORY_PERSISTENT);
252 |
253 | while (!thread_is_running(&event_thread))
254 | thread_sleep(10);
255 |
256 | #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID
257 | while (!test_should_start_flag) {
258 | #if FOUNDATION_PLATFORM_ANDROID
259 | system_process_events();
260 | #endif
261 | thread_sleep(100);
262 | }
263 | #endif
264 |
265 | fs_remove_directory(STRING_ARGS(environment_temporary_directory()));
266 |
267 | #if BUILD_MONOLITHIC
268 |
269 | test_run_fn tests[] = {test_task_run, 0};
270 |
271 | #if FOUNDATION_PLATFORM_ANDROID
272 |
273 | thread_t test_thread;
274 | thread_initialize(&test_thread, test_runner, tests, STRING_CONST("test_runner"), THREAD_PRIORITY_NORMAL, 0);
275 | thread_start(&test_thread);
276 |
277 | log_debug(HASH_TEST, STRING_CONST("Starting test runner thread"));
278 |
279 | while (!thread_is_running(&test_thread)) {
280 | system_process_events();
281 | thread_sleep(10);
282 | }
283 |
284 | while (thread_is_running(&test_thread)) {
285 | system_process_events();
286 | thread_sleep(10);
287 | }
288 |
289 | test_result = thread_join(&test_thread);
290 | process_result = (int)(intptr_t)test_result;
291 |
292 | thread_finalize(&test_thread);
293 |
294 | #else
295 |
296 | test_result = test_runner(tests);
297 | process_result = (int)(intptr_t)test_result;
298 |
299 | #endif
300 |
301 | if (process_result != 0)
302 | log_warnf(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Tests failed with exit code %d"), process_result);
303 |
304 | #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID
305 |
306 | while (!test_should_terminate() && test_have_focus() && (remain_counter < 50)) {
307 | system_process_events();
308 | thread_sleep(100);
309 | ++remain_counter;
310 | }
311 |
312 | #endif
313 |
314 | log_debug(HASH_TEST, STRING_CONST("Exiting main loop"));
315 |
316 | #else // !BUILD_MONOLITHIC
317 |
318 | // Find all test executables in the current executable directory
319 | #if FOUNDATION_PLATFORM_WINDOWS
320 | pattern = string_const(STRING_CONST("^test-.*\\.exe$"));
321 | #elif FOUNDATION_PLATFORM_MACOS
322 | pattern = string_const(STRING_CONST("^test-.*$"));
323 | #elif FOUNDATION_PLATFORM_POSIX
324 | pattern = string_const(STRING_CONST("^test-.*$"));
325 | #else
326 | #error Not implemented
327 | #endif
328 | exe_paths = fs_matching_files(STRING_ARGS(environment_executable_directory()), STRING_ARGS(pattern), false);
329 | array_resize(exe_flags, array_size(exe_paths));
330 | memset(exe_flags, 0, sizeof(unsigned int) * array_size(exe_flags));
331 | #if FOUNDATION_PLATFORM_MACOS
332 | // Also search for test applications
333 | string_const_t app_pattern = string_const(STRING_CONST("^test-.*\\.app$"));
334 | regex_t* app_regex = regex_compile(app_pattern.str, app_pattern.length);
335 | string_t* subdirs = fs_subdirs(STRING_ARGS(environment_executable_directory()));
336 | for (size_t idir = 0, dirsize = array_size(subdirs); idir < dirsize; ++idir) {
337 | if (regex_match(app_regex, subdirs[idir].str, subdirs[idir].length, 0, 0)) {
338 | string_t exe_path = {subdirs[idir].str, subdirs[idir].length - 4};
339 | array_push(exe_paths, exe_path);
340 | array_push(exe_flags, PROCESS_MACOS_USE_OPENAPPLICATION);
341 | }
342 | }
343 | string_array_deallocate(subdirs);
344 | regex_deallocate(app_regex);
345 | #endif
346 | for (iexe = 0, exesize = array_size(exe_paths); iexe < exesize; ++iexe) {
347 | string_const_t* process_args = 0;
348 | string_const_t exe_file_name = path_base_file_name(STRING_ARGS(exe_paths[iexe]));
349 | if (string_equal(STRING_ARGS(exe_file_name), STRING_ARGS(environment_executable_name())))
350 | continue; // Don't run self
351 |
352 | process_path = path_concat(pathbuf, BUILD_MAX_PATHLEN, STRING_ARGS(environment_executable_directory()),
353 | STRING_ARGS(exe_paths[iexe]));
354 | process = process_allocate();
355 |
356 | process_set_executable_path(process, STRING_ARGS(process_path));
357 | process_set_working_directory(process, STRING_ARGS(environment_executable_directory()));
358 | process_set_flags(process, PROCESS_ATTACHED | exe_flags[iexe]);
359 |
360 | if (!test_memory_tracker)
361 | array_push(process_args, string_const(STRING_CONST("--no-memory-tracker")));
362 | process_set_arguments(process, process_args, array_size(process_args));
363 |
364 | log_infof(HASH_TEST, STRING_CONST("Running test executable: %.*s"), STRING_FORMAT(exe_paths[iexe]));
365 |
366 | process_result = process_spawn(process);
367 | while (process_result == PROCESS_WAIT_INTERRUPTED) {
368 | thread_sleep(10);
369 | process_result = process_wait(process);
370 | }
371 | process_deallocate(process);
372 | array_deallocate(process_args);
373 |
374 | if (process_result != 0) {
375 | if (process_result >= PROCESS_INVALID_ARGS)
376 | log_warnf(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Tests failed, process terminated with error %x"),
377 | process_result);
378 | else
379 | log_warnf(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Tests failed with exit code %d"),
380 | process_result);
381 | process_set_exit_code(-1);
382 | goto exit;
383 | }
384 |
385 | log_infof(HASH_TEST, STRING_CONST("All tests from %.*s passed (%d)"), STRING_FORMAT(exe_paths[iexe]),
386 | process_result);
387 | }
388 |
389 | log_info(HASH_TEST, STRING_CONST("All tests passed"));
390 |
391 | exit:
392 |
393 | if (exe_paths)
394 | string_array_deallocate(exe_paths);
395 | array_deallocate(exe_flags);
396 |
397 | #endif
398 |
399 | test_should_terminate_flag = true;
400 |
401 | thread_signal(&event_thread);
402 | thread_finalize(&event_thread);
403 |
404 | memory_deallocate(pathbuf);
405 |
406 | log_infof(HASH_TEST, STRING_CONST("Tests exiting: %s (%d)"), process_result ? "FAILED" : "PASSED", process_result);
407 |
408 | if (process_result)
409 | memory_set_tracker(memory_tracker_none());
410 |
411 | return process_result;
412 | }
413 |
414 | void
415 | main_finalize(void) {
416 | #if FOUNDATION_PLATFORM_ANDROID
417 | thread_detach_jvm();
418 | #endif
419 |
420 | foundation_finalize();
421 | }
422 |
--------------------------------------------------------------------------------
/test/all/tizen/res/tizenapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mjansson/task_lib/4305e770d295ea96b79c9be0d6921cbc089f9630/test/all/tizen/res/tizenapp.png
--------------------------------------------------------------------------------
/test/all/tizen/tizen-manifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | tizenapp.png
6 |
7 |
8 |
9 | http://tizen.org/privilege/systemsettings
10 |
11 |
12 |
--------------------------------------------------------------------------------
/test/task/main.c:
--------------------------------------------------------------------------------
1 | /* main.c - Task test for task library - MIT License - 2014 Mattias Jansson
2 | *
3 | * This library provides a cross-platform library in C11 providing
4 | * task-based parallellism for projects based on our foundation library.
5 | *
6 | * The latest source code maintained by Mattias Jansson is always available at
7 | *
8 | * https://github.com/mjansson/task_lib
9 | *
10 | * The foundation library source code maintained by Mattias Jansson is always available at
11 | *
12 | * https://github.com/mjansson/foundation_lib
13 | *
14 | * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | static application_t
22 | test_task_application(void) {
23 | application_t app;
24 | memset(&app, 0, sizeof(app));
25 | app.name = string_const(STRING_CONST("Task tests"));
26 | app.short_name = string_const(STRING_CONST("test_task"));
27 | app.company = string_const(STRING_CONST(""));
28 | app.flags = APPLICATION_UTILITY;
29 | app.exception_handler = test_exception_handler;
30 | return app;
31 | }
32 |
33 | static memory_system_t
34 | test_task_memory_system(void) {
35 | return memory_system_malloc();
36 | }
37 |
38 | static foundation_config_t
39 | test_task_config(void) {
40 | foundation_config_t config;
41 | memset(&config, 0, sizeof(config));
42 | return config;
43 | }
44 |
45 | static int
46 | test_task_initialize(void) {
47 | task_config_t config;
48 | log_set_suppress(HASH_TASK, ERRORLEVEL_NONE);
49 | memset(&config, 0, sizeof(config));
50 | config.fiber_stack_size = 16 * 1024;
51 | return task_module_initialize(config);
52 | }
53 |
54 | static void
55 | test_task_finalize(void) {
56 | task_module_finalize();
57 | }
58 |
59 | static task_scheduler_t* task_scheduler;
60 | static atomic32_t task_counter;
61 | static atomic32_t remain_counter;
62 |
63 | static struct multi_task_setup_t {
64 | size_t sub_task_count;
65 | size_t final_task_count;
66 | } multi_task_setup;
67 |
68 | static FOUNDATION_NOINLINE void
69 | task_single_test(task_context_t context) {
70 | FOUNDATION_UNUSED(context);
71 | // log_infof(HASH_TASK, STRING_CONST("Task executing %d"), atomic_load32(&task_counter, memory_order_relaxed));
72 | atomic_incr32(&task_counter, memory_order_relaxed);
73 | }
74 |
75 | static FOUNDATION_NOINLINE void
76 | task_multi_sub_test(task_context_t context) {
77 | struct multi_task_setup_t* setup = (struct multi_task_setup_t*)context;
78 | size_t sub_task_count = setup->final_task_count;
79 | atomic32_t sub_counter;
80 | atomic_store32(&sub_counter, (int32_t)sub_task_count, memory_order_relaxed);
81 |
82 | task_t* sub_task = memory_allocate(HASH_TEST, sizeof(task_t) * sub_task_count, 0, MEMORY_PERSISTENT);
83 | for (size_t itask = 0; itask < sub_task_count; ++itask) {
84 | sub_task[itask].function = task_single_test;
85 | sub_task[itask].context = 0;
86 | sub_task[itask].counter = &sub_counter;
87 | }
88 |
89 | task_scheduler_multiqueue(task_scheduler, sub_task, sub_task_count);
90 |
91 | memory_deallocate(sub_task);
92 |
93 | task_yield_and_wait(&sub_counter);
94 |
95 | FOUNDATION_ASSERT(atomic_load32(&sub_counter, memory_order_relaxed) == 0);
96 | }
97 |
98 | static FOUNDATION_NOINLINE void
99 | task_multi_test(task_context_t context) {
100 | struct multi_task_setup_t* setup = (struct multi_task_setup_t*)context;
101 | size_t sub_task_count = setup->sub_task_count;
102 | task_t* sub_task = memory_allocate(HASH_TEST, sizeof(task_t) * sub_task_count, 0, MEMORY_PERSISTENT);
103 |
104 | atomic32_t sub_counter;
105 | atomic_store32(&sub_counter, (int32_t)sub_task_count, memory_order_relaxed);
106 | for (size_t itask = 0; itask < sub_task_count; ++itask) {
107 | sub_task[itask].function = task_multi_sub_test;
108 | sub_task[itask].context = (task_context_t)setup;
109 | sub_task[itask].counter = &sub_counter;
110 | }
111 |
112 | task_scheduler_multiqueue(task_scheduler, sub_task, sub_task_count);
113 | task_yield_and_wait(&sub_counter);
114 |
115 | FOUNDATION_ASSERT(atomic_load32(&sub_counter, memory_order_relaxed) == 0);
116 |
117 | atomic_store32(&sub_counter, (int32_t)sub_task_count, memory_order_relaxed);
118 | memset(sub_task, 0xFF, sizeof(task_t) * sub_task_count);
119 | for (size_t itask = 0; itask < sub_task_count; ++itask) {
120 | sub_task[itask].function = task_multi_sub_test;
121 | sub_task[itask].context = (task_context_t)setup;
122 | sub_task[itask].counter = &sub_counter;
123 | }
124 |
125 | task_scheduler_multiqueue(task_scheduler, sub_task, sub_task_count);
126 | task_yield_and_wait(&sub_counter);
127 |
128 | FOUNDATION_ASSERT(atomic_load32(&sub_counter, memory_order_relaxed) == 0);
129 |
130 | memory_deallocate(sub_task);
131 | }
132 |
133 | DECLARE_TEST(task, single) {
134 | task_scheduler = task_scheduler_allocate(1 /*system_hardware_threads()*/, 128);
135 |
136 | thread_sleep(100);
137 |
138 | task_t task = {0};
139 | task.function = task_single_test;
140 | task.counter = &remain_counter;
141 |
142 | atomic_store32(&task_counter, 0, memory_order_relaxed);
143 | atomic_store32(&remain_counter, 1, memory_order_relaxed);
144 |
145 | task_scheduler_queue(task_scheduler, task);
146 |
147 | task_yield_and_wait(&remain_counter);
148 |
149 | task_scheduler_deallocate(task_scheduler);
150 |
151 | EXPECT_EQ(atomic_load32(&task_counter, memory_order_relaxed), 1);
152 | EXPECT_EQ(atomic_load32(&remain_counter, memory_order_relaxed), 0);
153 |
154 | return 0;
155 | }
156 |
157 | DECLARE_TEST(task, multi) {
158 | assert_force_continue(false);
159 |
160 | task_scheduler = task_scheduler_allocate(system_hardware_threads(), 1024);
161 |
162 | thread_sleep(100);
163 |
164 | // Six million tasks in total (20*30*5000*2)
165 | size_t task_count = 20;
166 | multi_task_setup.sub_task_count = 30;
167 | multi_task_setup.final_task_count = 5000;
168 | task_t* task = memory_allocate(HASH_TEST, sizeof(task_t) * task_count, 0, MEMORY_PERSISTENT);
169 | for (size_t itask = 0; itask < task_count; ++itask) {
170 | task[itask].function = task_multi_test;
171 | task[itask].context = (task_context_t)&multi_task_setup;
172 | task[itask].counter = &remain_counter;
173 | }
174 |
175 | atomic_store32(&task_counter, 0, memory_order_relaxed);
176 | atomic_store32(&remain_counter, (int32_t)task_count, memory_order_relaxed);
177 |
178 | task_scheduler_multiqueue(task_scheduler, task, task_count);
179 |
180 | memory_deallocate(task);
181 |
182 | task_yield_and_wait(&remain_counter);
183 |
184 | task_scheduler_deallocate(task_scheduler);
185 |
186 | size_t total_count = task_count * multi_task_setup.sub_task_count * multi_task_setup.final_task_count * 2;
187 | EXPECT_EQ(atomic_load32(&task_counter, memory_order_relaxed), (int32_t)total_count);
188 | EXPECT_EQ(atomic_load32(&remain_counter, memory_order_relaxed), 0);
189 |
190 | return 0;
191 | }
192 |
193 | static atomic32_t directories_searched;
194 | static atomic32_t files_searched;
195 | static atomic32_t files_found;
196 | static atomic32_t file_remain_counter;
197 |
198 | static const char keyword[] = "main";
199 |
200 | static void
201 | task_find_in_file(task_context_t context) {
202 | char* file_to_search = (char*)context;
203 |
204 | stream_t* stream = stream_open(file_to_search, string_length(file_to_search), STREAM_IN | STREAM_BINARY);
205 | string_deallocate(file_to_search);
206 |
207 | if (!stream)
208 | return;
209 |
210 | error_context_push(STRING_CONST("Find in file"), STRING_ARGS(stream->path));
211 |
212 | bool keyword_found = false;
213 | size_t buffer_size = 60 * 1024;
214 | char* buffer = memory_allocate(0, buffer_size, 0, MEMORY_PERSISTENT);
215 | while (!keyword_found && !stream_eos(stream)) {
216 | size_t read = stream_read(stream, buffer, buffer_size);
217 |
218 | void* current = buffer;
219 | size_t remain = read;
220 | while (remain) {
221 | void* found = memchr(current, keyword[0], remain);
222 | if (!found)
223 | break;
224 |
225 | size_t offset = (size_t)pointer_diff(found, current);
226 | remain -= offset;
227 | if (remain < sizeof(keyword)) {
228 | if (!stream_eos(stream))
229 | stream_seek(stream, (ssize_t)sizeof(keyword) - (ssize_t)remain, STREAM_SEEK_CURRENT);
230 | break;
231 | }
232 |
233 | current = found;
234 | if (string_equal(current, sizeof(keyword), keyword, sizeof(keyword))) {
235 | atomic_incr32(&files_found, memory_order_relaxed);
236 | keyword_found = true;
237 | break;
238 | }
239 | current = pointer_offset(current, 1);
240 | --remain;
241 | }
242 | }
243 |
244 | memory_deallocate(buffer);
245 |
246 | error_context_pop();
247 |
248 | stream_deallocate(stream);
249 |
250 | atomic_incr32(&files_searched, memory_order_relaxed);
251 | }
252 |
253 | static void
254 | task_find_in_files(string_const_t path) {
255 | error_context_push(STRING_CONST("Find in files"), STRING_ARGS(path));
256 |
257 | /* Files */
258 | string_t* files = fs_files(STRING_ARGS(path));
259 | uint filecount = array_count(files);
260 | atomic_add32(&file_remain_counter, (int32_t)filecount, memory_order_relaxed);
261 | for (uint ifile = 0; ifile < filecount; ++ifile) {
262 | task_t subtask = {0};
263 | subtask.function = task_find_in_file;
264 | subtask.context = (task_context_t)path_allocate_concat(STRING_ARGS(path), STRING_ARGS(files[ifile])).str;
265 | subtask.counter = &file_remain_counter;
266 | task_scheduler_queue(task_scheduler, subtask);
267 | }
268 |
269 | string_array_deallocate(files);
270 |
271 | /* Subdirectories */
272 | string_t* subdirectories = fs_subdirs(STRING_ARGS(path));
273 | uint dircount = array_count(subdirectories);
274 | for (uint idir = 0; idir < dircount; ++idir) {
275 | string_t subpath = path_allocate_concat(STRING_ARGS(path), STRING_ARGS(subdirectories[idir]));
276 | task_find_in_files(string_const(STRING_ARGS(subpath)));
277 | string_deallocate(subpath.str);
278 | atomic_incr32(&directories_searched, memory_order_relaxed);
279 | }
280 |
281 | string_array_deallocate(subdirectories);
282 |
283 | error_context_pop();
284 | }
285 |
286 | DECLARE_TEST(task, find_in_file) {
287 | task_scheduler = task_scheduler_allocate(system_hardware_threads(), 4096);
288 |
289 | atomic_store32(&file_remain_counter, 0, memory_order_relaxed);
290 |
291 | task_find_in_files(environment_current_working_directory());
292 |
293 | task_yield_and_wait(&file_remain_counter);
294 |
295 | task_scheduler_deallocate(task_scheduler);
296 |
297 | error_level_t suppress = log_suppress(HASH_TEST);
298 | log_set_suppress(HASH_TEST, ERRORLEVEL_DEBUG);
299 | log_infof(HASH_TEST, STRING_CONST("Searched %d files and %d directories, found %d matching files"),
300 | atomic_load32(&files_searched, memory_order_relaxed),
301 | atomic_load32(&directories_searched, memory_order_relaxed),
302 | atomic_load32(&files_found, memory_order_relaxed));
303 | log_set_suppress(HASH_TEST, suppress);
304 |
305 | return 0;
306 | }
307 |
308 | static void
309 | test_task_declare(void) {
310 | ADD_TEST(task, single);
311 | ADD_TEST(task, multi);
312 | ADD_TEST(task, find_in_file);
313 | }
314 |
315 | static test_suite_t test_task_suite = {test_task_application, test_task_memory_system, test_task_config,
316 | test_task_declare, test_task_initialize, test_task_finalize};
317 |
318 | #if BUILD_MONOLITHIC
319 |
320 | int
321 | test_task_run(void);
322 |
323 | int
324 | test_task_run(void) {
325 | test_suite = test_task_suite;
326 | return test_run_all();
327 | }
328 |
329 | #else
330 |
331 | test_suite_t
332 | test_suite_define(void);
333 |
334 | test_suite_t
335 | test_suite_define(void) {
336 | return test_task_suite;
337 | }
338 |
339 | #endif
340 |
--------------------------------------------------------------------------------