├── .gitignore ├── .travis.yml ├── AUTHORS ├── COPYING ├── COPYING.LGPL ├── ChangeLog ├── Doxyfile ├── Makefile.am ├── NEWS ├── README ├── README.md ├── ToDo ├── aminclude.am ├── autogen.sh ├── configure.ac ├── examples ├── .gitignore ├── Makefile.am ├── high_load_test │ ├── Makefile.am │ ├── high_load_test.c │ └── high_load_test.vcproj ├── job_control │ ├── Makefile.am │ └── job_control.c ├── periodic_test │ ├── Makefile.am │ ├── periodic_test.c │ └── periodic_test.vcproj ├── pthread_wrap_ex │ ├── Makefile.am │ ├── ex.c │ ├── ex.h │ ├── ex_test_periodic.c │ ├── pthread_ex.c │ └── pthread_ex.h ├── serial_port_test │ ├── Makefile.am │ └── serial_port_test.c ├── simple_cpp │ ├── Makefile.am │ └── simple.cpp ├── simple_test │ ├── Makefile.am │ ├── simple_test.c │ └── simple_test.vcproj └── time_sort │ ├── Makefile.am │ └── time_sort.c ├── lib ├── Makefile.am ├── win32 │ └── stdbool.h ├── workqueue.c └── workqueue.h ├── libworkqueue.sln ├── libworkqueue.suo ├── libworkqueue.vcproj └── m4 ├── .gitignore └── ax_prog_doxygen.m4 /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE! Don't add files that are generated in specific 3 | # subdirectories here. Add them in the ".gitignore" file 4 | # in that subdirectory instead. 5 | # 6 | # NOTE! Please use 'git ls-files -i --exclude-standard' 7 | # command after changing this file, to see if there are 8 | # any tracked files which get ignored after the change. 9 | # 10 | # Normal rules 11 | # 12 | *.o 13 | *.o.* 14 | *.a 15 | *.s 16 | *.ko 17 | *.so 18 | *.so.dbg 19 | *.mod.c 20 | *.i 21 | *.lst 22 | *.symtypes 23 | *.order 24 | *.elf 25 | *.bin 26 | *.gz 27 | *.lzma 28 | *.patch 29 | *.gcno 30 | *.bak 31 | 32 | # 33 | # Top-level generic files 34 | # 35 | tags 36 | TAGS 37 | 38 | Debug 39 | Release 40 | 41 | #automake and autoconf generated files 42 | config.* 43 | Makefile.in 44 | Makefile 45 | aclocal.m4 46 | autom4te.cache/ 47 | compile 48 | configure 49 | depcomp 50 | install-sh 51 | INSTALL 52 | lib/libworkqueue.la 53 | lib/workqueue.lo 54 | libtool 55 | libworkqueue-config.h 56 | libworkqueue-config.h.in 57 | ltmain.sh 58 | missing 59 | stamp-h1 60 | 61 | ar-lib 62 | examples/high_load_test/.deps/ 63 | examples/high_load_test/.libs/ 64 | examples/job_control/.deps/ 65 | examples/job_control/.libs/ 66 | examples/periodic_test/.deps/ 67 | examples/periodic_test/.libs/ 68 | examples/pthread_wrap_ex/.deps/ 69 | examples/pthread_wrap_ex/.libs/ 70 | examples/serial_port_test/.deps/ 71 | examples/serial_port_test/.libs/ 72 | examples/simple_cpp/.deps/ 73 | examples/simple_cpp/.libs/ 74 | examples/simple_test/.deps/ 75 | examples/simple_test/.libs/ 76 | examples/time_sort/.deps/ 77 | examples/time_sort/.libs/ 78 | lib/.deps/ 79 | lib/.libs/ 80 | 81 | 82 | example_progs 83 | 84 | # stgit generated dirs 85 | patches-* 86 | 87 | # quilt's files 88 | patches 89 | series 90 | 91 | #ignore generate doc files for now 92 | doc/ 93 | 94 | # cscope files 95 | cscope.* 96 | ncscope.* 97 | 98 | # gnu global files 99 | GPATH 100 | GRTAGS 101 | GSYMS 102 | GTAGS 103 | 104 | #kdevelop files 105 | libworkqueue.kde* 106 | 107 | *.orig 108 | *~ 109 | \#*# 110 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - gcc 4 | env: 5 | # Default build. Release. 6 | - BUILD_ARGS="" 7 | # Build without example test programs 8 | - BUILD_ARGS="--disable-examples" 9 | 10 | #before_install: 11 | # - sudo apt-get update -qq 12 | # - sudo apt-get install automake1.9 13 | # - sudo pip install cpp-coveralls --use-mirrors 14 | script: 15 | - autoreconf -fi && ./configure $BUILD_ARGS && make 16 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Karl Hiramoto 2 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LIBRARY GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the library GPL. It is 10 | numbered 2 because it goes with version 2 of the ordinary GPL.] 11 | 12 | Preamble 13 | 14 | The licenses for most software are designed to take away your 15 | freedom to share and change it. By contrast, the GNU General Public 16 | Licenses are intended to guarantee your freedom to share and change 17 | free software--to make sure the software is free for all its users. 18 | 19 | This license, the Library General Public License, applies to some 20 | specially designated Free Software Foundation software, and to any 21 | other libraries whose authors decide to use it. You can use it for 22 | your libraries, too. 23 | 24 | When we speak of free software, we are referring to freedom, not 25 | price. Our General Public Licenses are designed to make sure that you 26 | have the freedom to distribute copies of free software (and charge for 27 | this service if you wish), that you receive source code or can get it 28 | if you want it, that you can change the software or use pieces of it 29 | in new free programs; and that you know you can do these things. 30 | 31 | To protect your rights, we need to make restrictions that forbid 32 | anyone to deny you these rights or to ask you to surrender the rights. 33 | These restrictions translate to certain responsibilities for you if 34 | you distribute copies of the library, or if you modify it. 35 | 36 | For example, if you distribute copies of the library, whether gratis 37 | or for a fee, you must give the recipients all the rights that we gave 38 | you. You must make sure that they, too, receive or can get the source 39 | code. If you link a program with the library, you must provide 40 | complete object files to the recipients so that they can relink them 41 | with the library, after making changes to the library and recompiling 42 | it. And you must show them these terms so they know their rights. 43 | 44 | Our method of protecting your rights has two steps: (1) copyright 45 | the library, and (2) offer you this license which gives you legal 46 | permission to copy, distribute and/or modify the library. 47 | 48 | Also, for each distributor's protection, we want to make certain 49 | that everyone understands that there is no warranty for this free 50 | library. If the library is modified by someone else and passed on, we 51 | want its recipients to know that what they have is not the original 52 | version, so that any problems introduced by others will not reflect on 53 | the original authors' reputations. 54 | 55 | Finally, any free program is threatened constantly by software 56 | patents. We wish to avoid the danger that companies distributing free 57 | software will individually obtain patent licenses, thus in effect 58 | transforming the program into proprietary software. To prevent this, 59 | we have made it clear that any patent must be licensed for everyone's 60 | free use or not licensed at all. 61 | 62 | Most GNU software, including some libraries, is covered by the ordinary 63 | GNU General Public License, which was designed for utility programs. This 64 | license, the GNU Library General Public License, applies to certain 65 | designated libraries. This license is quite different from the ordinary 66 | one; be sure to read it in full, and don't assume that anything in it is 67 | the same as in the ordinary license. 68 | 69 | The reason we have a separate public license for some libraries is that 70 | they blur the distinction we usually make between modifying or adding to a 71 | program and simply using it. Linking a program with a library, without 72 | changing the library, is in some sense simply using the library, and is 73 | analogous to running a utility program or application program. However, in 74 | a textual and legal sense, the linked executable is a combined work, a 75 | derivative of the original library, and the ordinary General Public License 76 | treats it as such. 77 | 78 | Because of this blurred distinction, using the ordinary General 79 | Public License for libraries did not effectively promote software 80 | sharing, because most developers did not use the libraries. We 81 | concluded that weaker conditions might promote sharing better. 82 | 83 | However, unrestricted linking of non-free programs would deprive the 84 | users of those programs of all benefit from the free status of the 85 | libraries themselves. This Library General Public License is intended to 86 | permit developers of non-free programs to use free libraries, while 87 | preserving your freedom as a user of such programs to change the free 88 | libraries that are incorporated in them. (We have not seen how to achieve 89 | this as regards changes in header files, but we have achieved it as regards 90 | changes in the actual functions of the Library.) The hope is that this 91 | will lead to faster development of free libraries. 92 | 93 | The precise terms and conditions for copying, distribution and 94 | modification follow. Pay close attention to the difference between a 95 | "work based on the library" and a "work that uses the library". The 96 | former contains code derived from the library, while the latter only 97 | works together with the library. 98 | 99 | Note that it is possible for a library to be covered by the ordinary 100 | General Public License rather than by this special one. 101 | 102 | GNU LIBRARY GENERAL PUBLIC LICENSE 103 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 104 | 105 | 0. This License Agreement applies to any software library which 106 | contains a notice placed by the copyright holder or other authorized 107 | party saying it may be distributed under the terms of this Library 108 | General Public License (also called "this License"). Each licensee is 109 | addressed as "you". 110 | 111 | A "library" means a collection of software functions and/or data 112 | prepared so as to be conveniently linked with application programs 113 | (which use some of those functions and data) to form executables. 114 | 115 | The "Library", below, refers to any such software library or work 116 | which has been distributed under these terms. A "work based on the 117 | Library" means either the Library or any derivative work under 118 | copyright law: that is to say, a work containing the Library or a 119 | portion of it, either verbatim or with modifications and/or translated 120 | straightforwardly into another language. (Hereinafter, translation is 121 | included without limitation in the term "modification".) 122 | 123 | "Source code" for a work means the preferred form of the work for 124 | making modifications to it. For a library, complete source code means 125 | all the source code for all modules it contains, plus any associated 126 | interface definition files, plus the scripts used to control compilation 127 | and installation of the library. 128 | 129 | Activities other than copying, distribution and modification are not 130 | covered by this License; they are outside its scope. The act of 131 | running a program using the Library is not restricted, and output from 132 | such a program is covered only if its contents constitute a work based 133 | on the Library (independent of the use of the Library in a tool for 134 | writing it). Whether that is true depends on what the Library does 135 | and what the program that uses the Library does. 136 | 137 | 1. You may copy and distribute verbatim copies of the Library's 138 | complete source code as you receive it, in any medium, provided that 139 | you conspicuously and appropriately publish on each copy an 140 | appropriate copyright notice and disclaimer of warranty; keep intact 141 | all the notices that refer to this License and to the absence of any 142 | warranty; and distribute a copy of this License along with the 143 | Library. 144 | 145 | You may charge a fee for the physical act of transferring a copy, 146 | and you may at your option offer warranty protection in exchange for a 147 | fee. 148 | 149 | 2. You may modify your copy or copies of the Library or any portion 150 | of it, thus forming a work based on the Library, and copy and 151 | distribute such modifications or work under the terms of Section 1 152 | above, provided that you also meet all of these conditions: 153 | 154 | a) The modified work must itself be a software library. 155 | 156 | b) You must cause the files modified to carry prominent notices 157 | stating that you changed the files and the date of any change. 158 | 159 | c) You must cause the whole of the work to be licensed at no 160 | charge to all third parties under the terms of this License. 161 | 162 | d) If a facility in the modified Library refers to a function or a 163 | table of data to be supplied by an application program that uses 164 | the facility, other than as an argument passed when the facility 165 | is invoked, then you must make a good faith effort to ensure that, 166 | in the event an application does not supply such function or 167 | table, the facility still operates, and performs whatever part of 168 | its purpose remains meaningful. 169 | 170 | (For example, a function in a library to compute square roots has 171 | a purpose that is entirely well-defined independent of the 172 | application. Therefore, Subsection 2d requires that any 173 | application-supplied function or table used by this function must 174 | be optional: if the application does not supply it, the square 175 | root function must still compute square roots.) 176 | 177 | These requirements apply to the modified work as a whole. If 178 | identifiable sections of that work are not derived from the Library, 179 | and can be reasonably considered independent and separate works in 180 | themselves, then this License, and its terms, do not apply to those 181 | sections when you distribute them as separate works. But when you 182 | distribute the same sections as part of a whole which is a work based 183 | on the Library, the distribution of the whole must be on the terms of 184 | this License, whose permissions for other licensees extend to the 185 | entire whole, and thus to each and every part regardless of who wrote 186 | it. 187 | 188 | Thus, it is not the intent of this section to claim rights or contest 189 | your rights to work written entirely by you; rather, the intent is to 190 | exercise the right to control the distribution of derivative or 191 | collective works based on the Library. 192 | 193 | In addition, mere aggregation of another work not based on the Library 194 | with the Library (or with a work based on the Library) on a volume of 195 | a storage or distribution medium does not bring the other work under 196 | the scope of this License. 197 | 198 | 3. You may opt to apply the terms of the ordinary GNU General Public 199 | License instead of this License to a given copy of the Library. To do 200 | this, you must alter all the notices that refer to this License, so 201 | that they refer to the ordinary GNU General Public License, version 2, 202 | instead of to this License. (If a newer version than version 2 of the 203 | ordinary GNU General Public License has appeared, then you can specify 204 | that version instead if you wish.) Do not make any other change in 205 | these notices. 206 | 207 | Once this change is made in a given copy, it is irreversible for 208 | that copy, so the ordinary GNU General Public License applies to all 209 | subsequent copies and derivative works made from that copy. 210 | 211 | This option is useful when you wish to copy part of the code of 212 | the Library into a program that is not a library. 213 | 214 | 4. You may copy and distribute the Library (or a portion or 215 | derivative of it, under Section 2) in object code or executable form 216 | under the terms of Sections 1 and 2 above provided that you accompany 217 | it with the complete corresponding machine-readable source code, which 218 | must be distributed under the terms of Sections 1 and 2 above on a 219 | medium customarily used for software interchange. 220 | 221 | If distribution of object code is made by offering access to copy 222 | from a designated place, then offering equivalent access to copy the 223 | source code from the same place satisfies the requirement to 224 | distribute the source code, even though third parties are not 225 | compelled to copy the source along with the object code. 226 | 227 | 5. A program that contains no derivative of any portion of the 228 | Library, but is designed to work with the Library by being compiled or 229 | linked with it, is called a "work that uses the Library". Such a 230 | work, in isolation, is not a derivative work of the Library, and 231 | therefore falls outside the scope of this License. 232 | 233 | However, linking a "work that uses the Library" with the Library 234 | creates an executable that is a derivative of the Library (because it 235 | contains portions of the Library), rather than a "work that uses the 236 | library". The executable is therefore covered by this License. 237 | Section 6 states terms for distribution of such executables. 238 | 239 | When a "work that uses the Library" uses material from a header file 240 | that is part of the Library, the object code for the work may be a 241 | derivative work of the Library even though the source code is not. 242 | Whether this is true is especially significant if the work can be 243 | linked without the Library, or if the work is itself a library. The 244 | threshold for this to be true is not precisely defined by law. 245 | 246 | If such an object file uses only numerical parameters, data 247 | structure layouts and accessors, and small macros and small inline 248 | functions (ten lines or less in length), then the use of the object 249 | file is unrestricted, regardless of whether it is legally a derivative 250 | work. (Executables containing this object code plus portions of the 251 | Library will still fall under Section 6.) 252 | 253 | Otherwise, if the work is a derivative of the Library, you may 254 | distribute the object code for the work under the terms of Section 6. 255 | Any executables containing that work also fall under Section 6, 256 | whether or not they are linked directly with the Library itself. 257 | 258 | 6. As an exception to the Sections above, you may also compile or 259 | link a "work that uses the Library" with the Library to produce a 260 | work containing portions of the Library, and distribute that work 261 | under terms of your choice, provided that the terms permit 262 | modification of the work for the customer's own use and reverse 263 | engineering for debugging such modifications. 264 | 265 | You must give prominent notice with each copy of the work that the 266 | Library is used in it and that the Library and its use are covered by 267 | this License. You must supply a copy of this License. If the work 268 | during execution displays copyright notices, you must include the 269 | copyright notice for the Library among them, as well as a reference 270 | directing the user to the copy of this License. Also, you must do one 271 | of these things: 272 | 273 | a) Accompany the work with the complete corresponding 274 | machine-readable source code for the Library including whatever 275 | changes were used in the work (which must be distributed under 276 | Sections 1 and 2 above); and, if the work is an executable linked 277 | with the Library, with the complete machine-readable "work that 278 | uses the Library", as object code and/or source code, so that the 279 | user can modify the Library and then relink to produce a modified 280 | executable containing the modified Library. (It is understood 281 | that the user who changes the contents of definitions files in the 282 | Library will not necessarily be able to recompile the application 283 | to use the modified definitions.) 284 | 285 | b) Accompany the work with a written offer, valid for at 286 | least three years, to give the same user the materials 287 | specified in Subsection 6a, above, for a charge no more 288 | than the cost of performing this distribution. 289 | 290 | c) If distribution of the work is made by offering access to copy 291 | from a designated place, offer equivalent access to copy the above 292 | specified materials from the same place. 293 | 294 | d) Verify that the user has already received a copy of these 295 | materials or that you have already sent this user a copy. 296 | 297 | For an executable, the required form of the "work that uses the 298 | Library" must include any data and utility programs needed for 299 | reproducing the executable from it. However, as a special exception, 300 | the source code distributed need not include anything that is normally 301 | distributed (in either source or binary form) with the major 302 | components (compiler, kernel, and so on) of the operating system on 303 | which the executable runs, unless that component itself accompanies 304 | the executable. 305 | 306 | It may happen that this requirement contradicts the license 307 | restrictions of other proprietary libraries that do not normally 308 | accompany the operating system. Such a contradiction means you cannot 309 | use both them and the Library together in an executable that you 310 | distribute. 311 | 312 | 7. You may place library facilities that are a work based on the 313 | Library side-by-side in a single library together with other library 314 | facilities not covered by this License, and distribute such a combined 315 | library, provided that the separate distribution of the work based on 316 | the Library and of the other library facilities is otherwise 317 | permitted, and provided that you do these two things: 318 | 319 | a) Accompany the combined library with a copy of the same work 320 | based on the Library, uncombined with any other library 321 | facilities. This must be distributed under the terms of the 322 | Sections above. 323 | 324 | b) Give prominent notice with the combined library of the fact 325 | that part of it is a work based on the Library, and explaining 326 | where to find the accompanying uncombined form of the same work. 327 | 328 | 8. You may not copy, modify, sublicense, link with, or distribute 329 | the Library except as expressly provided under this License. Any 330 | attempt otherwise to copy, modify, sublicense, link with, or 331 | distribute the Library is void, and will automatically terminate your 332 | rights under this License. However, parties who have received copies, 333 | or rights, from you under this License will not have their licenses 334 | terminated so long as such parties remain in full compliance. 335 | 336 | 9. You are not required to accept this License, since you have not 337 | signed it. However, nothing else grants you permission to modify or 338 | distribute the Library or its derivative works. These actions are 339 | prohibited by law if you do not accept this License. Therefore, by 340 | modifying or distributing the Library (or any work based on the 341 | Library), you indicate your acceptance of this License to do so, and 342 | all its terms and conditions for copying, distributing or modifying 343 | the Library or works based on it. 344 | 345 | 10. Each time you redistribute the Library (or any work based on the 346 | Library), the recipient automatically receives a license from the 347 | original licensor to copy, distribute, link with or modify the Library 348 | subject to these terms and conditions. You may not impose any further 349 | restrictions on the recipients' exercise of the rights granted herein. 350 | You are not responsible for enforcing compliance by third parties to 351 | this License. 352 | 353 | 11. If, as a consequence of a court judgment or allegation of patent 354 | infringement or for any other reason (not limited to patent issues), 355 | conditions are imposed on you (whether by court order, agreement or 356 | otherwise) that contradict the conditions of this License, they do not 357 | excuse you from the conditions of this License. If you cannot 358 | distribute so as to satisfy simultaneously your obligations under this 359 | License and any other pertinent obligations, then as a consequence you 360 | may not distribute the Library at all. For example, if a patent 361 | license would not permit royalty-free redistribution of the Library by 362 | all those who receive copies directly or indirectly through you, then 363 | the only way you could satisfy both it and this License would be to 364 | refrain entirely from distribution of the Library. 365 | 366 | If any portion of this section is held invalid or unenforceable under any 367 | particular circumstance, the balance of the section is intended to apply, 368 | and the section as a whole is intended to apply in other circumstances. 369 | 370 | It is not the purpose of this section to induce you to infringe any 371 | patents or other property right claims or to contest validity of any 372 | such claims; this section has the sole purpose of protecting the 373 | integrity of the free software distribution system which is 374 | implemented by public license practices. Many people have made 375 | generous contributions to the wide range of software distributed 376 | through that system in reliance on consistent application of that 377 | system; it is up to the author/donor to decide if he or she is willing 378 | to distribute software through any other system and a licensee cannot 379 | impose that choice. 380 | 381 | This section is intended to make thoroughly clear what is believed to 382 | be a consequence of the rest of this License. 383 | 384 | 12. If the distribution and/or use of the Library is restricted in 385 | certain countries either by patents or by copyrighted interfaces, the 386 | original copyright holder who places the Library under this License may add 387 | an explicit geographical distribution limitation excluding those countries, 388 | so that distribution is permitted only in or among countries not thus 389 | excluded. In such case, this License incorporates the limitation as if 390 | written in the body of this License. 391 | 392 | 13. The Free Software Foundation may publish revised and/or new 393 | versions of the Library General Public License from time to time. 394 | Such new versions will be similar in spirit to the present version, 395 | but may differ in detail to address new problems or concerns. 396 | 397 | Each version is given a distinguishing version number. If the Library 398 | specifies a version number of this License which applies to it and 399 | "any later version", you have the option of following the terms and 400 | conditions either of that version or of any later version published by 401 | the Free Software Foundation. If the Library does not specify a 402 | license version number, you may choose any version ever published by 403 | the Free Software Foundation. 404 | 405 | 14. If you wish to incorporate parts of the Library into other free 406 | programs whose distribution conditions are incompatible with these, 407 | write to the author to ask for permission. For software which is 408 | copyrighted by the Free Software Foundation, write to the Free 409 | Software Foundation; we sometimes make exceptions for this. Our 410 | decision will be guided by the two goals of preserving the free status 411 | of all derivatives of our free software and of promoting the sharing 412 | and reuse of software generally. 413 | 414 | NO WARRANTY 415 | 416 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 417 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 418 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 419 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 420 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 421 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 422 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 423 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 424 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 425 | 426 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 427 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 428 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 429 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 430 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 431 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 432 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 433 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 434 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 435 | DAMAGES. 436 | 437 | END OF TERMS AND CONDITIONS 438 | 439 | How to Apply These Terms to Your New Libraries 440 | 441 | If you develop a new library, and you want it to be of the greatest 442 | possible use to the public, we recommend making it free software that 443 | everyone can redistribute and change. You can do so by permitting 444 | redistribution under these terms (or, alternatively, under the terms of the 445 | ordinary General Public License). 446 | 447 | To apply these terms, attach the following notices to the library. It is 448 | safest to attach them to the start of each source file to most effectively 449 | convey the exclusion of warranty; and each file should have at least the 450 | "copyright" line and a pointer to where the full notice is found. 451 | 452 | 453 | Copyright (C) 454 | 455 | This library is free software; you can redistribute it and/or 456 | modify it under the terms of the GNU Library General Public 457 | License as published by the Free Software Foundation; either 458 | version 2 of the License, or (at your option) any later version. 459 | 460 | This library is distributed in the hope that it will be useful, 461 | but WITHOUT ANY WARRANTY; without even the implied warranty of 462 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 463 | Library General Public License for more details. 464 | 465 | You should have received a copy of the GNU Library General Public 466 | License along with this library; if not, write to the Free 467 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 468 | 469 | Also add information on how to contact you by electronic and paper mail. 470 | 471 | You should also get your employer (if you work as a programmer) or your 472 | school, if any, to sign a "copyright disclaimer" for the library, if 473 | necessary. Here is a sample; alter the names: 474 | 475 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 476 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 477 | 478 | , 1 April 1990 479 | Ty Coon, President of Vice 480 | 481 | That's all there is to it! 482 | -------------------------------------------------------------------------------- /COPYING.LGPL: -------------------------------------------------------------------------------- 1 | GNU LIBRARY GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the library GPL. It is 10 | numbered 2 because it goes with version 2 of the ordinary GPL.] 11 | 12 | Preamble 13 | 14 | The licenses for most software are designed to take away your 15 | freedom to share and change it. By contrast, the GNU General Public 16 | Licenses are intended to guarantee your freedom to share and change 17 | free software--to make sure the software is free for all its users. 18 | 19 | This license, the Library General Public License, applies to some 20 | specially designated Free Software Foundation software, and to any 21 | other libraries whose authors decide to use it. You can use it for 22 | your libraries, too. 23 | 24 | When we speak of free software, we are referring to freedom, not 25 | price. Our General Public Licenses are designed to make sure that you 26 | have the freedom to distribute copies of free software (and charge for 27 | this service if you wish), that you receive source code or can get it 28 | if you want it, that you can change the software or use pieces of it 29 | in new free programs; and that you know you can do these things. 30 | 31 | To protect your rights, we need to make restrictions that forbid 32 | anyone to deny you these rights or to ask you to surrender the rights. 33 | These restrictions translate to certain responsibilities for you if 34 | you distribute copies of the library, or if you modify it. 35 | 36 | For example, if you distribute copies of the library, whether gratis 37 | or for a fee, you must give the recipients all the rights that we gave 38 | you. You must make sure that they, too, receive or can get the source 39 | code. If you link a program with the library, you must provide 40 | complete object files to the recipients so that they can relink them 41 | with the library, after making changes to the library and recompiling 42 | it. And you must show them these terms so they know their rights. 43 | 44 | Our method of protecting your rights has two steps: (1) copyright 45 | the library, and (2) offer you this license which gives you legal 46 | permission to copy, distribute and/or modify the library. 47 | 48 | Also, for each distributor's protection, we want to make certain 49 | that everyone understands that there is no warranty for this free 50 | library. If the library is modified by someone else and passed on, we 51 | want its recipients to know that what they have is not the original 52 | version, so that any problems introduced by others will not reflect on 53 | the original authors' reputations. 54 | 55 | Finally, any free program is threatened constantly by software 56 | patents. We wish to avoid the danger that companies distributing free 57 | software will individually obtain patent licenses, thus in effect 58 | transforming the program into proprietary software. To prevent this, 59 | we have made it clear that any patent must be licensed for everyone's 60 | free use or not licensed at all. 61 | 62 | Most GNU software, including some libraries, is covered by the ordinary 63 | GNU General Public License, which was designed for utility programs. This 64 | license, the GNU Library General Public License, applies to certain 65 | designated libraries. This license is quite different from the ordinary 66 | one; be sure to read it in full, and don't assume that anything in it is 67 | the same as in the ordinary license. 68 | 69 | The reason we have a separate public license for some libraries is that 70 | they blur the distinction we usually make between modifying or adding to a 71 | program and simply using it. Linking a program with a library, without 72 | changing the library, is in some sense simply using the library, and is 73 | analogous to running a utility program or application program. However, in 74 | a textual and legal sense, the linked executable is a combined work, a 75 | derivative of the original library, and the ordinary General Public License 76 | treats it as such. 77 | 78 | Because of this blurred distinction, using the ordinary General 79 | Public License for libraries did not effectively promote software 80 | sharing, because most developers did not use the libraries. We 81 | concluded that weaker conditions might promote sharing better. 82 | 83 | However, unrestricted linking of non-free programs would deprive the 84 | users of those programs of all benefit from the free status of the 85 | libraries themselves. This Library General Public License is intended to 86 | permit developers of non-free programs to use free libraries, while 87 | preserving your freedom as a user of such programs to change the free 88 | libraries that are incorporated in them. (We have not seen how to achieve 89 | this as regards changes in header files, but we have achieved it as regards 90 | changes in the actual functions of the Library.) The hope is that this 91 | will lead to faster development of free libraries. 92 | 93 | The precise terms and conditions for copying, distribution and 94 | modification follow. Pay close attention to the difference between a 95 | "work based on the library" and a "work that uses the library". The 96 | former contains code derived from the library, while the latter only 97 | works together with the library. 98 | 99 | Note that it is possible for a library to be covered by the ordinary 100 | General Public License rather than by this special one. 101 | 102 | GNU LIBRARY GENERAL PUBLIC LICENSE 103 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 104 | 105 | 0. This License Agreement applies to any software library which 106 | contains a notice placed by the copyright holder or other authorized 107 | party saying it may be distributed under the terms of this Library 108 | General Public License (also called "this License"). Each licensee is 109 | addressed as "you". 110 | 111 | A "library" means a collection of software functions and/or data 112 | prepared so as to be conveniently linked with application programs 113 | (which use some of those functions and data) to form executables. 114 | 115 | The "Library", below, refers to any such software library or work 116 | which has been distributed under these terms. A "work based on the 117 | Library" means either the Library or any derivative work under 118 | copyright law: that is to say, a work containing the Library or a 119 | portion of it, either verbatim or with modifications and/or translated 120 | straightforwardly into another language. (Hereinafter, translation is 121 | included without limitation in the term "modification".) 122 | 123 | "Source code" for a work means the preferred form of the work for 124 | making modifications to it. For a library, complete source code means 125 | all the source code for all modules it contains, plus any associated 126 | interface definition files, plus the scripts used to control compilation 127 | and installation of the library. 128 | 129 | Activities other than copying, distribution and modification are not 130 | covered by this License; they are outside its scope. The act of 131 | running a program using the Library is not restricted, and output from 132 | such a program is covered only if its contents constitute a work based 133 | on the Library (independent of the use of the Library in a tool for 134 | writing it). Whether that is true depends on what the Library does 135 | and what the program that uses the Library does. 136 | 137 | 1. You may copy and distribute verbatim copies of the Library's 138 | complete source code as you receive it, in any medium, provided that 139 | you conspicuously and appropriately publish on each copy an 140 | appropriate copyright notice and disclaimer of warranty; keep intact 141 | all the notices that refer to this License and to the absence of any 142 | warranty; and distribute a copy of this License along with the 143 | Library. 144 | 145 | You may charge a fee for the physical act of transferring a copy, 146 | and you may at your option offer warranty protection in exchange for a 147 | fee. 148 | 149 | 2. You may modify your copy or copies of the Library or any portion 150 | of it, thus forming a work based on the Library, and copy and 151 | distribute such modifications or work under the terms of Section 1 152 | above, provided that you also meet all of these conditions: 153 | 154 | a) The modified work must itself be a software library. 155 | 156 | b) You must cause the files modified to carry prominent notices 157 | stating that you changed the files and the date of any change. 158 | 159 | c) You must cause the whole of the work to be licensed at no 160 | charge to all third parties under the terms of this License. 161 | 162 | d) If a facility in the modified Library refers to a function or a 163 | table of data to be supplied by an application program that uses 164 | the facility, other than as an argument passed when the facility 165 | is invoked, then you must make a good faith effort to ensure that, 166 | in the event an application does not supply such function or 167 | table, the facility still operates, and performs whatever part of 168 | its purpose remains meaningful. 169 | 170 | (For example, a function in a library to compute square roots has 171 | a purpose that is entirely well-defined independent of the 172 | application. Therefore, Subsection 2d requires that any 173 | application-supplied function or table used by this function must 174 | be optional: if the application does not supply it, the square 175 | root function must still compute square roots.) 176 | 177 | These requirements apply to the modified work as a whole. If 178 | identifiable sections of that work are not derived from the Library, 179 | and can be reasonably considered independent and separate works in 180 | themselves, then this License, and its terms, do not apply to those 181 | sections when you distribute them as separate works. But when you 182 | distribute the same sections as part of a whole which is a work based 183 | on the Library, the distribution of the whole must be on the terms of 184 | this License, whose permissions for other licensees extend to the 185 | entire whole, and thus to each and every part regardless of who wrote 186 | it. 187 | 188 | Thus, it is not the intent of this section to claim rights or contest 189 | your rights to work written entirely by you; rather, the intent is to 190 | exercise the right to control the distribution of derivative or 191 | collective works based on the Library. 192 | 193 | In addition, mere aggregation of another work not based on the Library 194 | with the Library (or with a work based on the Library) on a volume of 195 | a storage or distribution medium does not bring the other work under 196 | the scope of this License. 197 | 198 | 3. You may opt to apply the terms of the ordinary GNU General Public 199 | License instead of this License to a given copy of the Library. To do 200 | this, you must alter all the notices that refer to this License, so 201 | that they refer to the ordinary GNU General Public License, version 2, 202 | instead of to this License. (If a newer version than version 2 of the 203 | ordinary GNU General Public License has appeared, then you can specify 204 | that version instead if you wish.) Do not make any other change in 205 | these notices. 206 | 207 | Once this change is made in a given copy, it is irreversible for 208 | that copy, so the ordinary GNU General Public License applies to all 209 | subsequent copies and derivative works made from that copy. 210 | 211 | This option is useful when you wish to copy part of the code of 212 | the Library into a program that is not a library. 213 | 214 | 4. You may copy and distribute the Library (or a portion or 215 | derivative of it, under Section 2) in object code or executable form 216 | under the terms of Sections 1 and 2 above provided that you accompany 217 | it with the complete corresponding machine-readable source code, which 218 | must be distributed under the terms of Sections 1 and 2 above on a 219 | medium customarily used for software interchange. 220 | 221 | If distribution of object code is made by offering access to copy 222 | from a designated place, then offering equivalent access to copy the 223 | source code from the same place satisfies the requirement to 224 | distribute the source code, even though third parties are not 225 | compelled to copy the source along with the object code. 226 | 227 | 5. A program that contains no derivative of any portion of the 228 | Library, but is designed to work with the Library by being compiled or 229 | linked with it, is called a "work that uses the Library". Such a 230 | work, in isolation, is not a derivative work of the Library, and 231 | therefore falls outside the scope of this License. 232 | 233 | However, linking a "work that uses the Library" with the Library 234 | creates an executable that is a derivative of the Library (because it 235 | contains portions of the Library), rather than a "work that uses the 236 | library". The executable is therefore covered by this License. 237 | Section 6 states terms for distribution of such executables. 238 | 239 | When a "work that uses the Library" uses material from a header file 240 | that is part of the Library, the object code for the work may be a 241 | derivative work of the Library even though the source code is not. 242 | Whether this is true is especially significant if the work can be 243 | linked without the Library, or if the work is itself a library. The 244 | threshold for this to be true is not precisely defined by law. 245 | 246 | If such an object file uses only numerical parameters, data 247 | structure layouts and accessors, and small macros and small inline 248 | functions (ten lines or less in length), then the use of the object 249 | file is unrestricted, regardless of whether it is legally a derivative 250 | work. (Executables containing this object code plus portions of the 251 | Library will still fall under Section 6.) 252 | 253 | Otherwise, if the work is a derivative of the Library, you may 254 | distribute the object code for the work under the terms of Section 6. 255 | Any executables containing that work also fall under Section 6, 256 | whether or not they are linked directly with the Library itself. 257 | 258 | 6. As an exception to the Sections above, you may also compile or 259 | link a "work that uses the Library" with the Library to produce a 260 | work containing portions of the Library, and distribute that work 261 | under terms of your choice, provided that the terms permit 262 | modification of the work for the customer's own use and reverse 263 | engineering for debugging such modifications. 264 | 265 | You must give prominent notice with each copy of the work that the 266 | Library is used in it and that the Library and its use are covered by 267 | this License. You must supply a copy of this License. If the work 268 | during execution displays copyright notices, you must include the 269 | copyright notice for the Library among them, as well as a reference 270 | directing the user to the copy of this License. Also, you must do one 271 | of these things: 272 | 273 | a) Accompany the work with the complete corresponding 274 | machine-readable source code for the Library including whatever 275 | changes were used in the work (which must be distributed under 276 | Sections 1 and 2 above); and, if the work is an executable linked 277 | with the Library, with the complete machine-readable "work that 278 | uses the Library", as object code and/or source code, so that the 279 | user can modify the Library and then relink to produce a modified 280 | executable containing the modified Library. (It is understood 281 | that the user who changes the contents of definitions files in the 282 | Library will not necessarily be able to recompile the application 283 | to use the modified definitions.) 284 | 285 | b) Accompany the work with a written offer, valid for at 286 | least three years, to give the same user the materials 287 | specified in Subsection 6a, above, for a charge no more 288 | than the cost of performing this distribution. 289 | 290 | c) If distribution of the work is made by offering access to copy 291 | from a designated place, offer equivalent access to copy the above 292 | specified materials from the same place. 293 | 294 | d) Verify that the user has already received a copy of these 295 | materials or that you have already sent this user a copy. 296 | 297 | For an executable, the required form of the "work that uses the 298 | Library" must include any data and utility programs needed for 299 | reproducing the executable from it. However, as a special exception, 300 | the source code distributed need not include anything that is normally 301 | distributed (in either source or binary form) with the major 302 | components (compiler, kernel, and so on) of the operating system on 303 | which the executable runs, unless that component itself accompanies 304 | the executable. 305 | 306 | It may happen that this requirement contradicts the license 307 | restrictions of other proprietary libraries that do not normally 308 | accompany the operating system. Such a contradiction means you cannot 309 | use both them and the Library together in an executable that you 310 | distribute. 311 | 312 | 7. You may place library facilities that are a work based on the 313 | Library side-by-side in a single library together with other library 314 | facilities not covered by this License, and distribute such a combined 315 | library, provided that the separate distribution of the work based on 316 | the Library and of the other library facilities is otherwise 317 | permitted, and provided that you do these two things: 318 | 319 | a) Accompany the combined library with a copy of the same work 320 | based on the Library, uncombined with any other library 321 | facilities. This must be distributed under the terms of the 322 | Sections above. 323 | 324 | b) Give prominent notice with the combined library of the fact 325 | that part of it is a work based on the Library, and explaining 326 | where to find the accompanying uncombined form of the same work. 327 | 328 | 8. You may not copy, modify, sublicense, link with, or distribute 329 | the Library except as expressly provided under this License. Any 330 | attempt otherwise to copy, modify, sublicense, link with, or 331 | distribute the Library is void, and will automatically terminate your 332 | rights under this License. However, parties who have received copies, 333 | or rights, from you under this License will not have their licenses 334 | terminated so long as such parties remain in full compliance. 335 | 336 | 9. You are not required to accept this License, since you have not 337 | signed it. However, nothing else grants you permission to modify or 338 | distribute the Library or its derivative works. These actions are 339 | prohibited by law if you do not accept this License. Therefore, by 340 | modifying or distributing the Library (or any work based on the 341 | Library), you indicate your acceptance of this License to do so, and 342 | all its terms and conditions for copying, distributing or modifying 343 | the Library or works based on it. 344 | 345 | 10. Each time you redistribute the Library (or any work based on the 346 | Library), the recipient automatically receives a license from the 347 | original licensor to copy, distribute, link with or modify the Library 348 | subject to these terms and conditions. You may not impose any further 349 | restrictions on the recipients' exercise of the rights granted herein. 350 | You are not responsible for enforcing compliance by third parties to 351 | this License. 352 | 353 | 11. If, as a consequence of a court judgment or allegation of patent 354 | infringement or for any other reason (not limited to patent issues), 355 | conditions are imposed on you (whether by court order, agreement or 356 | otherwise) that contradict the conditions of this License, they do not 357 | excuse you from the conditions of this License. If you cannot 358 | distribute so as to satisfy simultaneously your obligations under this 359 | License and any other pertinent obligations, then as a consequence you 360 | may not distribute the Library at all. For example, if a patent 361 | license would not permit royalty-free redistribution of the Library by 362 | all those who receive copies directly or indirectly through you, then 363 | the only way you could satisfy both it and this License would be to 364 | refrain entirely from distribution of the Library. 365 | 366 | If any portion of this section is held invalid or unenforceable under any 367 | particular circumstance, the balance of the section is intended to apply, 368 | and the section as a whole is intended to apply in other circumstances. 369 | 370 | It is not the purpose of this section to induce you to infringe any 371 | patents or other property right claims or to contest validity of any 372 | such claims; this section has the sole purpose of protecting the 373 | integrity of the free software distribution system which is 374 | implemented by public license practices. Many people have made 375 | generous contributions to the wide range of software distributed 376 | through that system in reliance on consistent application of that 377 | system; it is up to the author/donor to decide if he or she is willing 378 | to distribute software through any other system and a licensee cannot 379 | impose that choice. 380 | 381 | This section is intended to make thoroughly clear what is believed to 382 | be a consequence of the rest of this License. 383 | 384 | 12. If the distribution and/or use of the Library is restricted in 385 | certain countries either by patents or by copyrighted interfaces, the 386 | original copyright holder who places the Library under this License may add 387 | an explicit geographical distribution limitation excluding those countries, 388 | so that distribution is permitted only in or among countries not thus 389 | excluded. In such case, this License incorporates the limitation as if 390 | written in the body of this License. 391 | 392 | 13. The Free Software Foundation may publish revised and/or new 393 | versions of the Library General Public License from time to time. 394 | Such new versions will be similar in spirit to the present version, 395 | but may differ in detail to address new problems or concerns. 396 | 397 | Each version is given a distinguishing version number. If the Library 398 | specifies a version number of this License which applies to it and 399 | "any later version", you have the option of following the terms and 400 | conditions either of that version or of any later version published by 401 | the Free Software Foundation. If the Library does not specify a 402 | license version number, you may choose any version ever published by 403 | the Free Software Foundation. 404 | 405 | 14. If you wish to incorporate parts of the Library into other free 406 | programs whose distribution conditions are incompatible with these, 407 | write to the author to ask for permission. For software which is 408 | copyrighted by the Free Software Foundation, write to the Free 409 | Software Foundation; we sometimes make exceptions for this. Our 410 | decision will be guided by the two goals of preserving the free status 411 | of all derivatives of our free software and of promoting the sharing 412 | and reuse of software generally. 413 | 414 | NO WARRANTY 415 | 416 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 417 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 418 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 419 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 420 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 421 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 422 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 423 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 424 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 425 | 426 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 427 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 428 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 429 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 430 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 431 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 432 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 433 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 434 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 435 | DAMAGES. 436 | 437 | END OF TERMS AND CONDITIONS 438 | 439 | How to Apply These Terms to Your New Libraries 440 | 441 | If you develop a new library, and you want it to be of the greatest 442 | possible use to the public, we recommend making it free software that 443 | everyone can redistribute and change. You can do so by permitting 444 | redistribution under these terms (or, alternatively, under the terms of the 445 | ordinary General Public License). 446 | 447 | To apply these terms, attach the following notices to the library. It is 448 | safest to attach them to the start of each source file to most effectively 449 | convey the exclusion of warranty; and each file should have at least the 450 | "copyright" line and a pointer to where the full notice is found. 451 | 452 | 453 | Copyright (C) 454 | 455 | This library is free software; you can redistribute it and/or 456 | modify it under the terms of the GNU Library General Public 457 | License as published by the Free Software Foundation; either 458 | version 2 of the License, or (at your option) any later version. 459 | 460 | This library is distributed in the hope that it will be useful, 461 | but WITHOUT ANY WARRANTY; without even the implied warranty of 462 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 463 | Library General Public License for more details. 464 | 465 | You should have received a copy of the GNU Library General Public 466 | License along with this library; if not, write to the Free 467 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 468 | 469 | Also add information on how to contact you by electronic and paper mail. 470 | 471 | You should also get your employer (if you work as a programmer) or your 472 | school, if any, to sign a "copyright disclaimer" for the library, if 473 | necessary. Here is a sample; alter the names: 474 | 475 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 476 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 477 | 478 | , 1 April 1990 479 | Ty Coon, President of Vice 480 | 481 | That's all there is to it! 482 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Version 0.6 2 | * API change workqueue_init() now allows optional arg to initilize worker threads 3 | * add version nubmer to library with libtool, N/A on windows. 4 | * more examples and documentation 5 | Version 0.5 6 | * Fix bug with start time nano/mili seconds overflow. 7 | * Fix pthread_cond_timedwait() to only use one mutex to lock condition variable 8 | * workqueue_show_status() now shows scheduled time 9 | * windows fixes 10 | 11 | Version 0.4 12 | * New functions workqueue_empty() and workqueue_empty_wait() 13 | Will empty the Queue, and if wanted wait for any running job. 14 | * Improve locking workqueue_destroy() to fix potenial race on 15 | shutdown. 16 | 17 | Version 0.3 18 | * Initial support for Win32 tested on Win XP SP3 19 | 20 | Version 0.2: 21 | * Improve Documentation using DoxyGen 22 | * Change to autotools based build system 23 | * Serial port queueing test 24 | * High Load test 25 | * Fix warnings 26 | 27 | Version 0.1: 28 | * First working tag/release 29 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | include $(top_srcdir)/aminclude.am 2 | 3 | ACLOCAL_AMFLAGS = -I m4 4 | 5 | OPT_DIRS = 6 | if ENABLE_EXAMPLES 7 | OPT_DIRS += examples 8 | endif 9 | 10 | SUBDIRS = . lib $(OPT_DIRS) 11 | 12 | 13 | # ensure the distribution of the doxygen configuration file 14 | EXTRA_DIST = Doxygen 15 | 16 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/karlhiramoto/libworkqueue/7ec2a7099b25a841beb05e1b5abaca922932e3bd/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libWorkQueue 2 | 3 | [![Build Status](https://travis-ci.org/karlhiramoto/libworkqueue.svg)](http://travis-ci.org/karlhiramoto/libworkqueue) 4 | 5 | 6 | This library is a priority work queue scheduler. 7 | 8 | Possible applications of this library is prioritizing, queuing, and/or scheduling: 9 | 10 | * Queue, parallelize, and/or schedule transactions to a synchronous database API. 11 | 12 | * Hardware I/O to a device where commands must be queued. 13 | 14 | * Periodic work that must be scheduled every X period for example: 15 | * A software watchdog to check that your system is OK. 16 | * A periodic check of network I/O 17 | * a cron job scheduler 18 | 19 | * If you have many threads that spend most of the time sleeping or blocked, 20 | use libworkqueue to reduce the number of threads and to queue the jobs. 21 | The result may be a lower memory footprint by a lower number of threads. 22 | 23 | * If you have other threads and wich to serialize operations you may use libworkqueue 24 | to make a FIFO or priority queue. 25 | 26 | * A thread pool. Send work tasks to the pool. 27 | 28 | 29 | ### Linux/UNIX 30 | Help on Configure options 31 | ``` 32 | ./autogen.sh 33 | ./configure --help 34 | ``` 35 | 36 | Dependencies to compile: 37 | * C compiler 38 | * libtool, autoconf, automake (gnu auto tools) 39 | 40 | To compile library: 41 | ``` 42 | ./autogen.sh 43 | ./configure 44 | make 45 | ``` 46 | 47 | To compile examples: 48 | ``` 49 | make examples 50 | ``` 51 | 52 | To install: 53 | ``` 54 | make install 55 | ``` 56 | 57 | To build doxygen documentation graphvis is required: 58 | ``` 59 | make doxygen-doc 60 | ``` 61 | 62 | ## MS windows 63 | * Tested on Windows XP SP3 with MS Visual C++ 2008 Express Edition. Load solution libworkqueue.sln 64 | -------------------------------------------------------------------------------- /ToDo: -------------------------------------------------------------------------------- 1 | * Fully test and debug MS Windows support. Mostly working now, but may have unknown bugs. 2 | -------------------------------------------------------------------------------- /aminclude.am: -------------------------------------------------------------------------------- 1 | # Automake Support 2 | # 3 | # The following is a template aminclude.am file for use with Automake. 4 | # Make targets and variables values are controlled by the various 5 | # DX_COND_* conditionals set by autoconf. 6 | # 7 | # The provided targets are: 8 | # 9 | # doxygen-doc: Generate all doxygen documentation. 10 | # 11 | # doxygen-run: Run doxygen, which will generate some of the 12 | # documentation (HTML, CHM, CHI, MAN, RTF, XML) 13 | # but will not do the post processing required 14 | # for the rest of it (PS, PDF, and some MAN). 15 | # 16 | # doxygen-man: Rename some doxygen generated man pages. 17 | # 18 | # doxygen-ps: Generate doxygen PostScript documentation. 19 | # 20 | # doxygen-pdf: Generate doxygen PDF documentation. 21 | # 22 | # Note that by default these are not integrated into the automake targets. 23 | # If doxygen is used to generate man pages, you can achieve this 24 | # integration by setting man3_MANS to the list of man pages generated and 25 | # then adding the dependency: 26 | # 27 | # $(man3_MANS): doxygen-doc 28 | # 29 | # This will cause make to run doxygen and generate all the documentation. 30 | # 31 | # The following variable is intended for use in Makefile.am: 32 | # 33 | # DX_CLEANFILES = everything to clean. 34 | # 35 | # Then add this variable to MOSTLYCLEANFILES. 36 | # 37 | # ----- begin aminclude.am ------------------------------------- 38 | 39 | ## --------------------------------- ## 40 | ## Format-independent Doxygen rules. ## 41 | ## --------------------------------- ## 42 | 43 | if DX_COND_doc 44 | 45 | ## ------------------------------- ## 46 | ## Rules specific for HTML output. ## 47 | ## ------------------------------- ## 48 | 49 | if DX_COND_html 50 | 51 | DX_CLEAN_HTML = @DX_DOCDIR@/html 52 | 53 | endif DX_COND_html 54 | 55 | ## ------------------------------ ## 56 | ## Rules specific for CHM output. ## 57 | ## ------------------------------ ## 58 | 59 | if DX_COND_chm 60 | 61 | DX_CLEAN_CHM = @DX_DOCDIR@/chm 62 | 63 | if DX_COND_chi 64 | 65 | DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi 66 | 67 | endif DX_COND_chi 68 | 69 | endif DX_COND_chm 70 | 71 | ## ------------------------------ ## 72 | ## Rules specific for MAN output. ## 73 | ## ------------------------------ ## 74 | 75 | if DX_COND_man 76 | DX_CLEAN_MAN = @DX_DOCDIR@/man 77 | endif DX_COND_man 78 | 79 | ## ------------------------------ ## 80 | ## Rules specific for RTF output. ## 81 | ## ------------------------------ ## 82 | 83 | if DX_COND_rtf 84 | 85 | DX_CLEAN_RTF = @DX_DOCDIR@/rtf 86 | 87 | endif DX_COND_rtf 88 | 89 | ## ------------------------------ ## 90 | ## Rules specific for XML output. ## 91 | ## ------------------------------ ## 92 | 93 | if DX_COND_xml 94 | 95 | DX_CLEAN_XML = @DX_DOCDIR@/xml 96 | 97 | endif DX_COND_xml 98 | 99 | ## ----------------------------- ## 100 | ## Rules specific for PS output. ## 101 | ## ----------------------------- ## 102 | 103 | if DX_COND_ps 104 | 105 | DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps 106 | 107 | DX_PS_GOAL = doxygen-ps 108 | 109 | doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps 110 | 111 | @DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag 112 | cd @DX_DOCDIR@/latex; \ 113 | rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ 114 | $(DX_LATEX) refman.tex; \ 115 | $(MAKEINDEX_PATH) refman.idx; \ 116 | $(DX_LATEX) refman.tex; \ 117 | countdown=5; \ 118 | while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ 119 | refman.log > /dev/null 2>&1 \ 120 | && test $$countdown -gt 0; do \ 121 | $(DX_LATEX) refman.tex; \ 122 | countdown=`expr $$countdown - 1`; \ 123 | done; \ 124 | $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi 125 | endif DX_COND_ps 126 | 127 | ## ------------------------------ ## 128 | ## Rules specific for PDF output. ## 129 | ## ------------------------------ ## 130 | 131 | if DX_COND_pdf 132 | 133 | DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf 134 | 135 | DX_PDF_GOAL = doxygen-pdf 136 | 137 | doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf 138 | 139 | @DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag 140 | cd @DX_DOCDIR@/latex; \ 141 | rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ 142 | $(DX_PDFLATEX) refman.tex; \ 143 | $(DX_MAKEINDEX) refman.idx; \ 144 | $(DX_PDFLATEX) refman.tex; \ 145 | countdown=5; \ 146 | while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ 147 | refman.log > /dev/null 2>&1 \ 148 | && test $$countdown -gt 0; do \ 149 | $(DX_PDFLATEX) refman.tex; \ 150 | countdown=`expr $$countdown - 1`; \ 151 | done; \ 152 | mv refman.pdf ../@PACKAGE@.pdf 153 | endif DX_COND_pdf 154 | 155 | ## ------------------------------------------------- ## 156 | ## Rules specific for LaTeX (shared for PS and PDF). ## 157 | ## ------------------------------------------------- ## 158 | 159 | if DX_COND_latex 160 | 161 | DX_CLEAN_LATEX = @DX_DOCDIR@/latex 162 | 163 | endif DX_COND_latex 164 | 165 | .PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL) 166 | 167 | .INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) 168 | 169 | doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag 170 | 171 | doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) 172 | 173 | @DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS) 174 | rm -rf @DX_DOCDIR@ 175 | $(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG) 176 | 177 | DX_CLEANFILES = \ 178 | @DX_DOCDIR@/@PACKAGE@.tag \ 179 | -r \ 180 | $(DX_CLEAN_HTML) \ 181 | $(DX_CLEAN_CHM) \ 182 | $(DX_CLEAN_CHI) \ 183 | $(DX_CLEAN_MAN) \ 184 | $(DX_CLEAN_RTF) \ 185 | $(DX_CLEAN_XML) \ 186 | $(DX_CLEAN_PS) \ 187 | $(DX_CLEAN_PDF) \ 188 | $(DX_CLEAN_LATEX) 189 | endif DX_COND_doc 190 | 191 | # ----- end aminclude.am --------------------------------------- 192 | # 193 | # LICENSE 194 | # 195 | # Copyright (c) 2009 Oren Ben-Kiki 196 | # 197 | # Copying and distribution of this file, with or without modification, are 198 | # permitted in any medium without royalty provided the copyright notice 199 | # and this notice are preserved. 200 | # 201 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | libtoolize --copy --force --automake 2 | aclocal --force -I m4 && \ 3 | autoheader --force 4 | automake --gnu --copy --foreign --include-deps --add-missing && \ 5 | autoconf 6 | 7 | 8 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.59) 2 | AC_INIT([libworkqueue priority workqueue scheduler], [0.1], [karl@hiramoto.org]) 3 | 4 | AC_CONFIG_MACRO_DIR([m4]) 5 | 6 | AM_INIT_AUTOMAKE([-Wall -Werror]) 7 | AC_PROG_CC 8 | AC_PROG_CXX 9 | AM_PROG_AR 10 | AC_PROG_LIBTOOL 11 | AM_PROG_CC_C_O 12 | 13 | ###################################################################### 14 | # DOXYGEN SUPPORT 15 | ###################################################################### 16 | 17 | DX_HTML_FEATURE(ON) 18 | DX_CHM_FEATURE(OFF) 19 | DX_CHI_FEATURE(OFF) 20 | DX_MAN_FEATURE(OFF) 21 | DX_RTF_FEATURE(OFF) 22 | DX_XML_FEATURE(OFF) 23 | DX_PDF_FEATURE(OFF) 24 | DX_PS_FEATURE(OFF) 25 | 26 | DX_INIT_DOXYGEN([$PACKAGE_NAME],[Doxyfile]) 27 | 28 | ###################################################################### 29 | 30 | AC_CONFIG_HEADERS([libworkqueue-config.h]) 31 | 32 | 33 | AC_LANG([C]) 34 | # Checks for header files. 35 | AC_HEADER_STDC 36 | AC_CHECK_HEADERS([string]) 37 | 38 | 39 | AC_ARG_ENABLE([examples], 40 | AS_HELP_STRING([--disable-examples], [don't build example programs]), 41 | [enable_examples="$enableval"], [enable_examples="yes"]) 42 | 43 | AM_CONDITIONAL([ENABLE_EXAMPLES], [test "$enable_examples" = "yes"]) 44 | 45 | 46 | AC_CONFIG_FILES([Makefile 47 | lib/Makefile 48 | examples/Makefile 49 | examples/high_load_test/Makefile 50 | examples/job_control/Makefile 51 | examples/serial_port_test/Makefile 52 | examples/simple_test/Makefile 53 | examples/simple_cpp/Makefile 54 | examples/time_sort/Makefile 55 | examples/periodic_test/Makefile 56 | examples/pthread_wrap_ex/Makefile 57 | ]) 58 | 59 | 60 | AC_OUTPUT 61 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | #generated files 2 | 3 | high_load_test/high_load_test 4 | job_control/job_control 5 | periodic_test/periodic_test 6 | serial_port_test/serial_port_test 7 | simple_cpp/simple 8 | simple_test/simple_test 9 | time_sort/time_sort 10 | pthread_wrap_ex/ex_test_periodic 11 | -------------------------------------------------------------------------------- /examples/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = periodic_test simple_test high_load_test serial_port_test \ 2 | job_control simple_cpp time_sort pthread_wrap_ex 3 | -------------------------------------------------------------------------------- /examples/high_load_test/Makefile.am: -------------------------------------------------------------------------------- 1 | # TESTS = simple_test periodic_test serial_port_test 2 | 3 | WORKQUEUE_CFLAGS = -pthread -g3 -I../../lib 4 | WORKQUEUE_LDLAGS = -pthread -lworkqueue -lrt -L../../lib 5 | 6 | noinst_bin_PROGRAMS = high_load_test 7 | noinst_bindir = $(abs_top_builddir)/example_progs 8 | 9 | high_load_test_SOURCES = high_load_test.c 10 | high_load_test_CFLAGS = $(AM_CFLAGS) $(WORKQUEUE_CFLAGS) 11 | high_load_test_LDFLAGS = $(WORKQUEUE_LDLAGS) 12 | -------------------------------------------------------------------------------- /examples/high_load_test/high_load_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file high test example 3 | * @author Karl Hiramoto 4 | * @brief high load with lots of threads and lots of jobs 5 | * 6 | * Example code is Distributed under Dual BSD / LGPL licence 7 | * Copyright 2009 Karl Hiramoto 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 14 | 15 | #if !defined(WINDOWS) 16 | #define WINDOWS 17 | #endif 18 | 19 | #pragma once 20 | #include "windows.h" // big fat windows lib 21 | 22 | #define ENOMEM ERROR_NOT_ENOUGH_MEMORY 23 | #define EBUSY ERROR_BUSY 24 | 25 | 26 | #define sleep(x) Sleep(x*1000) 27 | #else 28 | #include 29 | #include 30 | 31 | #endif 32 | 33 | #include "workqueue.h" 34 | 35 | 36 | struct prg_ctx 37 | { 38 | struct workqueue_ctx *ctx; 39 | int counter; 40 | }; 41 | 42 | void callback_func(void *data) 43 | { 44 | struct prg_ctx *prg = (struct prg_ctx *) data; 45 | int ret; 46 | int i; 47 | 48 | for (i = 0; i < 123456789; i++) { 49 | ret += i; 50 | } 51 | if (ret) 52 | prg->counter++; 53 | } 54 | 55 | int main(int argc, char *argv[]) { 56 | struct prg_ctx prg; 57 | int i; 58 | int num_jobs=512; 59 | int ret; 60 | printf("starting\n"); 61 | prg.counter = 0; 62 | prg.ctx = workqueue_init(512 , 32, NULL); 63 | 64 | for (i = 0; i < num_jobs; i++) { 65 | ret = workqueue_add_work(prg.ctx, 2, 0, 66 | callback_func, &prg); 67 | 68 | if (ret >= 0) { 69 | /* Added job ok */ 70 | } else if (ret == -EBUSY){ 71 | printf("busy adding work %d of %d\n", i, num_jobs); 72 | sleep(1); 73 | } else { 74 | printf("Error adding job err=%d\n", ret); 75 | workqueue_show_status(prg.ctx, stdout); 76 | } 77 | } 78 | 79 | for (i = 0; i < num_jobs/2; i++) { 80 | ret = workqueue_add_work(prg.ctx, 5, 0, 81 | callback_func, &prg); 82 | 83 | if (ret >= 0) { 84 | /* Added job ok */ 85 | } else if (ret == -EBUSY){ 86 | printf("busy adding work %d of %d\n", i, num_jobs); 87 | sleep(1); 88 | } else { 89 | printf("Error adding job err=%d\n", ret); 90 | workqueue_show_status(prg.ctx, stdout); 91 | } 92 | } 93 | workqueue_show_status(prg.ctx, stdout); 94 | 95 | for (i = 0; i < num_jobs/2; i++) { 96 | ret = workqueue_add_work(prg.ctx, 1, 0, 97 | callback_func, &prg); 98 | 99 | if (ret >= 0) { 100 | /* Added job ok */ 101 | } else if (ret == -EBUSY){ 102 | printf("busy adding work %d of %d\n", i, num_jobs); 103 | sleep(1); 104 | } else { 105 | printf("Error adding job err=%d\n", ret); 106 | workqueue_show_status(prg.ctx, stdout); 107 | } 108 | } 109 | workqueue_show_status(prg.ctx, stdout); 110 | 111 | for (i = 20; i && (ret = workqueue_get_queue_len(prg.ctx)); i--) { 112 | printf("waiting for %d jobs \n", ret); 113 | sleep(1); 114 | } 115 | 116 | workqueue_destroy(prg.ctx); 117 | printf("count =%d \n", prg.counter); 118 | #ifdef WINDOWS 119 | system("pause"); 120 | #endif 121 | return 0; 122 | } -------------------------------------------------------------------------------- /examples/high_load_test/high_load_test.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 28 | 31 | 34 | 37 | 40 | 43 | 58 | 61 | 64 | 67 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 98 | 99 | 107 | 110 | 113 | 116 | 119 | 122 | 136 | 139 | 142 | 145 | 156 | 159 | 162 | 165 | 168 | 171 | 174 | 177 | 178 | 179 | 180 | 184 | 185 | 186 | 191 | 194 | 195 | 196 | 201 | 204 | 205 | 206 | 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /examples/job_control/Makefile.am: -------------------------------------------------------------------------------- 1 | WORKQUEUE_CFLAGS = -pthread -g3 -I../../lib 2 | WORKQUEUE_LDLAGS = -pthread -lworkqueue -lrt -L../../lib 3 | 4 | noinst_bin_PROGRAMS = job_control 5 | noinst_bindir = $(abs_top_builddir)/example_progs 6 | 7 | job_control_SOURCES = job_control.c 8 | job_control_CFLAGS = $(AM_CFLAGS) $(WORKQUEUE_CFLAGS) 9 | job_control_LDFLAGS = $(WORKQUEUE_LDLAGS) 10 | -------------------------------------------------------------------------------- /examples/job_control/job_control.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file job_control.c 3 | * @author Karl Hiramoto 4 | * @brief simple example showing how to check if job is running, dequeue, cancel or kill it. 5 | * 6 | * Example code is Distributed under Dual BSD / LGPL licence 7 | * Copyright 2009 Karl Hiramoto 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 15 | 16 | #if !defined(WINDOWS) 17 | #define WINDOWS 18 | #endif 19 | 20 | #pragma once 21 | #include "windows.h" // big fat windows lib 22 | #define sleep(x) Sleep(x*1000) 23 | #else 24 | #include 25 | #include 26 | #endif 27 | 28 | #include "workqueue.h" 29 | 30 | 31 | struct prg_ctx 32 | { 33 | struct workqueue_ctx *ctx; 34 | int counter; 35 | }; 36 | 37 | 38 | static void callback_func(void *data) 39 | { 40 | struct prg_ctx *prg = (struct prg_ctx *) data; 41 | int ret; 42 | 43 | prg->counter++; 44 | printf("callback counter=%d\n", prg->counter); 45 | if (prg->counter % 2) 46 | sleep(1); 47 | 48 | if ((prg->counter % 4) == 0) { 49 | printf("reschedule this job\n"); 50 | ret = workqueue_add_work(prg->ctx, 2, 1234, 51 | callback_func, prg); 52 | 53 | if (ret >= 0) { 54 | printf("Added job %d \n", ret); 55 | workqueue_show_status(prg->ctx, stdout); 56 | } else { 57 | printf("Error adding job err=%d\n", ret); 58 | } 59 | } 60 | printf("work callback returning\n"); 61 | } 62 | 63 | void sighandler_func(int sig) 64 | { 65 | printf("signal=%d recieved\n",sig); 66 | } 67 | 68 | 69 | int main(int argc, char *argv[]) { 70 | struct prg_ctx prg; 71 | int i; 72 | int num_jobs = 3; 73 | int ret; 74 | printf("starting\n"); 75 | 76 | signal(SIGTERM, sighandler_func); 77 | 78 | prg.counter = 0; 79 | prg.ctx = workqueue_init(32, 1, NULL); 80 | 81 | for (i = 0; i < num_jobs; i++) { 82 | ret = workqueue_add_work(prg.ctx, 2, 0, 83 | callback_func, &prg); 84 | 85 | if (ret >= 0) { 86 | printf("Added job %d \n", ret); 87 | } else { 88 | printf("Error adding job err=%d\n", ret); 89 | } 90 | } 91 | workqueue_show_status(prg.ctx, stdout); 92 | 93 | for (i = 0; i < num_jobs; i++) { 94 | printf("job %d is queued=%d running=%d queued_or_running=%d\n", i, 95 | workqueue_job_queued(prg.ctx, i), 96 | workqueue_job_running(prg.ctx, i), 97 | workqueue_job_queued_or_running(prg.ctx, i)); 98 | } 99 | 100 | workqueue_show_status(prg.ctx, stdout); 101 | 102 | for (i = 0; i < num_jobs; i++) { 103 | ret = workqueue_dequeue(prg.ctx, i), 104 | printf(" dequeue job %d ret=%d\n", i , ret); 105 | } 106 | workqueue_show_status(prg.ctx, stdout); 107 | 108 | for (i = 0; i < num_jobs; i++) { 109 | ret = workqueue_add_work(prg.ctx, 2, 0, 110 | callback_func, &prg); 111 | 112 | if (ret >= 0) { 113 | printf("Added job %d \n", ret); 114 | } else { 115 | printf("Error adding job err=%d\n", ret); 116 | } 117 | } 118 | 119 | for (i = 0; i < num_jobs*2; i++) { 120 | ret = workqueue_dequeue(prg.ctx, i), 121 | printf(" dequeue job %d ret=%d\n", i , ret); 122 | } 123 | 124 | 125 | for (i = 20; i && (ret = workqueue_get_queue_len(prg.ctx)); i--) { 126 | printf("waiting for %d jobs \n", ret); 127 | sleep(1); 128 | } 129 | 130 | workqueue_destroy(prg.ctx); 131 | 132 | #ifdef WINDOWS 133 | system("pause"); 134 | #endif 135 | return 0; 136 | } -------------------------------------------------------------------------------- /examples/periodic_test/Makefile.am: -------------------------------------------------------------------------------- 1 | WORKQUEUE_CFLAGS = -pthread -g3 -I../../lib 2 | WORKQUEUE_LDLAGS = -pthread -lworkqueue -lrt -L../../lib 3 | 4 | noinst_bin_PROGRAMS = periodic_test 5 | noinst_bindir = $(abs_top_builddir)/example_progs 6 | 7 | periodic_test_SOURCES = periodic_test.c 8 | periodic_test_CFLAGS = $(AM_CFLAGS) $(WORKQUEUE_CFLAGS) 9 | periodic_test_LDFLAGS = $(WORKQUEUE_LDLAGS) 10 | -------------------------------------------------------------------------------- /examples/periodic_test/periodic_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file simple test example 3 | * @author Karl Hiramoto 4 | * @brief simple example showing how to doing a polling job that reschedules 5 | * @brief itself to do something every X ammount of time. 6 | * 7 | * Example code is Distributed under Dual BSD / LGPL licence 8 | * Copyright 2009 Karl Hiramoto 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 15 | 16 | #if !defined(WINDOWS) 17 | #define WINDOWS 18 | #endif 19 | 20 | #pragma once 21 | #include "windows.h" // big fat windows lib 22 | #define sleep(x) Sleep(x*1000) 23 | #else 24 | #include 25 | #endif 26 | 27 | #include "workqueue.h" 28 | 29 | static struct workqueue_ctx *ctx; 30 | 31 | static int dummy_job(int count) 32 | { 33 | int i; 34 | int ret; 35 | for (i = 123456*count; i; i--) { 36 | ret+=count; 37 | ret *= i; 38 | } 39 | return ret; 40 | } 41 | 42 | void callback_func(void *data) 43 | { 44 | int *counter = (int*) data; 45 | int ret = 0; 46 | (*counter)++; 47 | 48 | if (*counter % 3) 49 | ret = dummy_job(*counter); 50 | 51 | printf("counter=%d job ret=%d\n",*counter, ret); 52 | /* NOTE This kind of function to do polling every X ammount of time */ 53 | 54 | /* reschedule myself */ 55 | if (*counter < 80) 56 | ret = workqueue_add_work(ctx, 2, 1678, 57 | callback_func, counter); 58 | 59 | if (ret >= 0) { 60 | printf("Added job %d \n", ret); 61 | } else { 62 | printf("Error adding job err=%d\n", ret); 63 | } 64 | 65 | } 66 | 67 | int main(int argc, char *argv[]) { 68 | 69 | int counter = 0; 70 | int i; 71 | int ret; 72 | printf("starting\n"); 73 | ctx = workqueue_init(32, 1, NULL); 74 | 75 | ret = workqueue_add_work(ctx, 2, 2000, 76 | callback_func, &counter); 77 | 78 | workqueue_show_status(ctx, stdout); 79 | 80 | sleep(30); 81 | 82 | for (i = 20; i && (ret = workqueue_get_queue_len(ctx)); i--) { 83 | printf("waiting for %d jobs \n", ret); 84 | sleep(1); 85 | } 86 | 87 | workqueue_destroy(ctx); 88 | 89 | #ifdef WINDOWS 90 | system("pause"); 91 | #endif 92 | return 0; 93 | } -------------------------------------------------------------------------------- /examples/periodic_test/periodic_test.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 28 | 31 | 34 | 37 | 40 | 43 | 58 | 61 | 64 | 67 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 98 | 99 | 107 | 110 | 113 | 116 | 119 | 122 | 136 | 139 | 142 | 145 | 156 | 159 | 162 | 165 | 168 | 171 | 174 | 177 | 178 | 179 | 180 | 184 | 185 | 186 | 191 | 194 | 195 | 196 | 201 | 204 | 205 | 206 | 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /examples/pthread_wrap_ex/Makefile.am: -------------------------------------------------------------------------------- 1 | WORKQUEUE_CFLAGS = -pthread -g3 -I../../lib 2 | WORKQUEUE_LDLAGS = -pthread -lworkqueue -lrt -L../../lib 3 | 4 | noinst_bin_PROGRAMS = ex_test_periodic 5 | noinst_bindir = $(abs_top_builddir)/example_progs 6 | 7 | ex_test_periodic_SOURCES = ex_test_periodic.c ex.c pthread_ex.c 8 | ex_test_periodic_CFLAGS = $(AM_CFLAGS) $(WORKQUEUE_CFLAGS) 9 | ex_test_periodic_LDFLAGS = $(WORKQUEUE_LDLAGS) 10 | -------------------------------------------------------------------------------- /examples/pthread_wrap_ex/ex.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** OSSP ex - Exception Handling 3 | ** Copyright (c) 2002-2007 Ralf S. Engelschall 4 | ** Copyright (c) 2002-2007 The OSSP Project 5 | ** 6 | ** This file is part of OSSP ex, an exception handling library 7 | ** which can be found at http://www.ossp.org/pkg/lib/ex/. 8 | ** 9 | ** Permission to use, copy, modify, and distribute this software for 10 | ** any purpose with or without fee is hereby granted, provided that 11 | ** the above copyright notice and this permission notice appear in all 12 | ** copies. 13 | ** 14 | ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 15 | ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR 18 | ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 21 | ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 24 | ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | ** SUCH DAMAGE. 26 | ** 27 | ** ex.c: exception handling (compiler part) 28 | */ 29 | 30 | #include 31 | #include 32 | 33 | #include "ex.h" 34 | 35 | /* default __ex_ctx callback function */ 36 | ex_ctx_t *__ex_ctx_default(void) 37 | { 38 | static ex_ctx_t ctx = EX_CTX_INITIALIZER; 39 | 40 | return &ctx; 41 | } 42 | 43 | /* default __ex_terminate callback function */ 44 | void __ex_terminate_default(ex_t *e) 45 | { 46 | fprintf(stderr, 47 | "**EX: UNCAUGHT EXCEPTION: " 48 | "class=0x%lx object=0x%lx value=0x%lx [%s:%d@%s]\n", 49 | (long)((e)->ex_class), (long)((e)->ex_object), (long)((e)->ex_value), 50 | (e)->ex_file, (e)->ex_line, (e)->ex_func); 51 | abort(); 52 | } 53 | 54 | /* the externally visible API */ 55 | ex_ctx_cb_t __ex_ctx = &__ex_ctx_default; 56 | ex_term_cb_t __ex_terminate = &__ex_terminate_default; 57 | 58 | -------------------------------------------------------------------------------- /examples/pthread_wrap_ex/ex.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** OSSP ex - Exception Handling 3 | ** Copyright (c) 2002-2007 Ralf S. Engelschall 4 | ** Copyright (c) 2002-2007 The OSSP Project 5 | ** 6 | ** This file is part of OSSP ex, an exception handling library 7 | ** which can be found at http://www.ossp.org/pkg/lib/ex/. 8 | ** 9 | ** Permission to use, copy, modify, and distribute this software for 10 | ** any purpose with or without fee is hereby granted, provided that 11 | ** the above copyright notice and this permission notice appear in all 12 | ** copies. 13 | ** 14 | ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 15 | ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR 18 | ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 21 | ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 24 | ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | ** SUCH DAMAGE. 26 | ** 27 | ** ex.h: exception handling (pre-processor part) 28 | */ 29 | 30 | #ifndef __EX_H__ 31 | #define __EX_H__ 32 | 33 | /* required ISO-C standard facilities */ 34 | #include 35 | 36 | /* convenience define */ 37 | #ifndef NULL 38 | #define NULL (void *)0 39 | #endif 40 | 41 | /* determine how the current function name can be fetched */ 42 | #if ( defined(__STDC__) \ 43 | && defined(__STDC_VERSION__) \ 44 | && __STDC_VERSION__ >= 199901L) 45 | #define __EX_FUNC__ __func__ /* ISO-C99 compliant */ 46 | #elif ( defined(__GNUC__) \ 47 | && defined(__GNUC_MINOR__) \ 48 | && ( __GNUC__ > 2 \ 49 | || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))) 50 | #define __EX_FUNC__ __FUNCTION__ /* gcc >= 2.8 */ 51 | #else 52 | #define __EX_FUNC__ "#NA#" /* not available */ 53 | #endif 54 | 55 | /* the machine context */ 56 | #if defined(__EX_MCTX_MCSC__) 57 | #include /* POSIX.1 ucontext(3) */ 58 | #define __ex_mctx_struct ucontext_t uc; 59 | #define __ex_mctx_save(mctx) (getcontext(&(mctx)->uc) == 0) 60 | #define __ex_mctx_restored(mctx) /* noop */ 61 | #define __ex_mctx_restore(mctx) (void)setcontext(&(mctx)->uc) 62 | 63 | #elif defined(__EX_MCTX_SSJLJ__) 64 | #include /* POSIX.1 sigjmp_buf(3) */ 65 | #define __ex_mctx_struct sigjmp_buf jb; 66 | #define __ex_mctx_save(mctx) (sigsetjmp((mctx)->jb, 1) == 0) 67 | #define __ex_mctx_restored(mctx) /* noop */ 68 | #define __ex_mctx_restore(mctx) (void)siglongjmp((mctx)->jb, 1) 69 | 70 | #elif defined(__EX_MCTX_SJLJ__) || !defined(__EX_MCTX_CUSTOM__) 71 | #include /* ISO-C jmp_buf(3) */ 72 | #define __ex_mctx_struct jmp_buf jb; 73 | #define __ex_mctx_save(mctx) (setjmp((mctx)->jb) == 0) 74 | #define __ex_mctx_restored(mctx) /* noop */ 75 | #define __ex_mctx_restore(mctx) (void)longjmp((mctx)->jb, 1) 76 | #endif 77 | 78 | /* declare the machine context type */ 79 | typedef struct { __ex_mctx_struct } __ex_mctx_t; 80 | 81 | /* declare the exception type (public) */ 82 | typedef struct { 83 | /* throw value */ 84 | void *ex_class; 85 | void *ex_object; 86 | void *ex_value; 87 | /* throw point */ 88 | const char *ex_file; 89 | int ex_line; 90 | const char *ex_func; 91 | } ex_t; 92 | 93 | /* declare the context type (private) */ 94 | typedef struct { 95 | __ex_mctx_t *ctx_mctx; /* permanent machine context of enclosing try/catch */ 96 | int ctx_deferred; /* permanent flag whether exception is deferred */ 97 | int ctx_deferring;/* permanent counter of exception deferring level */ 98 | int ctx_defer; /* temporary flag for exception deferring macro */ 99 | int ctx_shielding;/* permanent counter of exception shielding level */ 100 | int ctx_shield; /* temporary flag for exception shielding macro */ 101 | int ctx_caught; /* temporary flag whether exception was caught */ 102 | volatile ex_t ctx_ex; /* temporary exception storage */ 103 | } ex_ctx_t; 104 | 105 | /* the static and dynamic initializers for a context structure */ 106 | #define EX_CTX_INITIALIZER \ 107 | { NULL, 0, 0, 0, 0, 0, 0, { NULL, NULL, NULL, NULL, 0, NULL } } 108 | #define EX_CTX_INITIALIZE(ctx) \ 109 | do { \ 110 | (ctx)->ctx_mctx = NULL; \ 111 | (ctx)->ctx_deferred = 0; \ 112 | (ctx)->ctx_deferring = 0; \ 113 | (ctx)->ctx_defer = 0; \ 114 | (ctx)->ctx_shielding = 0; \ 115 | (ctx)->ctx_shield = 0; \ 116 | (ctx)->ctx_caught = 0; \ 117 | (ctx)->ctx_ex.ex_class = NULL; \ 118 | (ctx)->ctx_ex.ex_object = NULL; \ 119 | (ctx)->ctx_ex.ex_value = NULL; \ 120 | (ctx)->ctx_ex.ex_file = NULL; \ 121 | (ctx)->ctx_ex.ex_line = 0; \ 122 | (ctx)->ctx_ex.ex_func = NULL; \ 123 | } while (0) 124 | 125 | /* the exception context */ 126 | typedef ex_ctx_t *(*ex_ctx_cb_t)(void); 127 | extern ex_ctx_cb_t __ex_ctx; 128 | extern ex_ctx_t *__ex_ctx_default(void); 129 | 130 | /* the termination handler */ 131 | typedef void (*ex_term_cb_t)(ex_t *); 132 | extern ex_term_cb_t __ex_terminate; 133 | extern void __ex_terminate_default(ex_t *e); 134 | 135 | /* the block for trying execution */ 136 | #define ex_try \ 137 | { \ 138 | ex_ctx_t *__ex_ctx_ptr = __ex_ctx(); \ 139 | int __ex_cleanup = 0; \ 140 | __ex_mctx_t *__ex_mctx_en; \ 141 | __ex_mctx_t __ex_mctx_me; \ 142 | __ex_mctx_en = __ex_ctx_ptr->ctx_mctx; \ 143 | __ex_ctx_ptr->ctx_mctx = &__ex_mctx_me; \ 144 | if (__ex_mctx_save(&__ex_mctx_me)) { \ 145 | if (1) 146 | 147 | /* the optional(!) block for cleanup */ 148 | #define ex_cleanup \ 149 | else { \ 150 | } \ 151 | __ex_ctx_ptr->ctx_caught = 0; \ 152 | } \ 153 | else { \ 154 | __ex_mctx_restored(&__ex_mctx_me); \ 155 | __ex_ctx_ptr->ctx_caught = 1; \ 156 | } \ 157 | __ex_ctx_ptr->ctx_mctx = __ex_mctx_en; \ 158 | __ex_cleanup = 1; \ 159 | if (1) { \ 160 | if (1) 161 | 162 | /* the block for catching an exception */ 163 | #define ex_catch(e) \ 164 | else { \ 165 | } \ 166 | if (!(__ex_cleanup)) \ 167 | __ex_ctx_ptr->ctx_caught = 0; \ 168 | } \ 169 | else { \ 170 | if (!(__ex_cleanup)) { \ 171 | __ex_mctx_restored(&__ex_mctx_me); \ 172 | __ex_ctx_ptr->ctx_caught = 1; \ 173 | } \ 174 | } \ 175 | __ex_ctx_ptr->ctx_mctx = __ex_mctx_en; \ 176 | } \ 177 | if ( !(__ex_ctx()->ctx_caught) \ 178 | || ((e) = __ex_ctx()->ctx_ex, 0)) { \ 179 | } \ 180 | else 181 | 182 | /* the throwing of a new exception */ 183 | #define ex_throw(c,o,v) \ 184 | (( __ex_ctx()->ctx_shielding > 0 \ 185 | || (__ex_ctx()->ctx_deferring > 0 && __ex_ctx()->ctx_deferred == 1)) ? 0 : \ 186 | (__ex_ctx()->ctx_ex.ex_class = (void *)(c), \ 187 | __ex_ctx()->ctx_ex.ex_object = (void *)(o), \ 188 | __ex_ctx()->ctx_ex.ex_value = (void *)(v), \ 189 | __ex_ctx()->ctx_ex.ex_file = __FILE__, \ 190 | __ex_ctx()->ctx_ex.ex_line = __LINE__, \ 191 | __ex_ctx()->ctx_ex.ex_func = __EX_FUNC__, \ 192 | __ex_ctx()->ctx_deferred = 1, \ 193 | (__ex_ctx()->ctx_deferring > 0 ? 0 : \ 194 | (__ex_ctx()->ctx_mctx == NULL \ 195 | ? (__ex_terminate((ex_t *)&(__ex_ctx()->ctx_ex)), -1) \ 196 | : (__ex_mctx_restore(__ex_ctx()->ctx_mctx), 1) )))) 197 | 198 | /* the re-throwing of an already caught exception */ 199 | #define ex_rethrow \ 200 | (( __ex_ctx()->ctx_shielding > 0 \ 201 | || __ex_ctx()->ctx_deferring > 0) ? 0 : \ 202 | ( __ex_ctx()->ctx_mctx == NULL \ 203 | ? (__ex_terminate((ex_t *)&(__ex_ctx()->ctx_ex)), -1) \ 204 | : (__ex_mctx_restore(__ex_ctx()->ctx_mctx), 1) )) 205 | 206 | /* shield an operation from exception handling */ 207 | #define ex_shield \ 208 | for (__ex_ctx()->ctx_shielding++, \ 209 | __ex_ctx()->ctx_shield = 1; \ 210 | __ex_ctx()->ctx_shield == 1; \ 211 | __ex_ctx()->ctx_shield = 0, \ 212 | __ex_ctx()->ctx_shielding--) 213 | 214 | /* defer immediate exception handling */ 215 | #define ex_defer \ 216 | for (((__ex_ctx()->ctx_deferring)++ == 0 ? __ex_ctx()->ctx_deferred = 0 : 0), \ 217 | __ex_ctx()->ctx_defer = 1; \ 218 | __ex_ctx()->ctx_defer == 1; \ 219 | __ex_ctx()->ctx_defer = 0, \ 220 | ((--(__ex_ctx()->ctx_deferring) == 0 && __ex_ctx()->ctx_deferred == 1) ? ex_rethrow : 0)) 221 | 222 | /* exception handling tests */ 223 | #define ex_catching \ 224 | (__ex_ctx()->ctx_mctx != NULL) 225 | #define ex_shielding \ 226 | (__ex_ctx()->ctx_shielding > 0) 227 | #define ex_deferring \ 228 | (__ex_ctx()->ctx_deferring > 0) 229 | 230 | /* optional namespace mapping */ 231 | #if defined(__EX_NS_UCCXX__) 232 | #define Try ex_try 233 | #define Cleanup ex_cleanup 234 | #define Catch ex_catch 235 | #define Throw ex_throw 236 | #define Rethrow ex_rethrow 237 | #define Shield ex_shield 238 | #define Defer ex_defer 239 | #elif defined(__EX_NS_CXX__) || (!defined(__cplusplus) && !defined(__EX_NS_CUSTOM__)) 240 | #define try ex_try 241 | #define cleanup ex_cleanup 242 | #define catch ex_catch 243 | #define throw ex_throw 244 | #define rethrow ex_rethrow 245 | #define shield ex_shield 246 | #define defer ex_defer 247 | #endif 248 | 249 | #endif /* __EX_H__ */ 250 | 251 | -------------------------------------------------------------------------------- /examples/pthread_wrap_ex/ex_test_periodic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file simple test example 3 | * @author Karl Hiramoto 4 | * @brief simple example showing how to doing a polling job that reschedules 5 | * @brief itself to do something every X ammount of time. 6 | * 7 | * Example code is Distributed under Dual BSD / LGPL licence 8 | * Copyright 2009 Karl Hiramoto 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include "workqueue.h" 18 | #include "pthread_ex.h" 19 | #include "ex.h" 20 | 21 | static struct workqueue_ctx *ctx = NULL; 22 | 23 | static struct worker_thread_ops ops = { 24 | .worker_constructor = ex_thread_init, 25 | .data = NULL, 26 | }; 27 | 28 | void callback_func(void *data) 29 | { 30 | int *counter = (int*) data; 31 | int ret = 0; 32 | ex_t ex; 33 | 34 | ex_try { 35 | (*counter)++; 36 | printf("starting callback\n"); 37 | 38 | 39 | printf("counter=%d job ret=%d\n",*counter, ret); 40 | /* NOTE This kind of function to do polling every X ammount of time */ 41 | 42 | /* reschedule myself */ 43 | if (*counter < 80) { 44 | ret = workqueue_add_work(ctx, 2, 1678, 45 | callback_func, counter); 46 | } else { 47 | ex_throw(NULL, callback_func, data); 48 | } 49 | 50 | if (ret >= 0) { 51 | printf("Added job %d \n", ret); 52 | } else { 53 | printf("Error adding job err=%d\n", ret); 54 | } 55 | } ex_catch(ex) { 56 | printf("caught exception at %s:%d", ex.ex_func, ex.ex_line); 57 | ex_rethrow; 58 | } 59 | 60 | } 61 | 62 | int main(int argc, char *argv[]) { 63 | 64 | int counter = 0; 65 | int i; 66 | int ret; 67 | printf("starting\n"); 68 | pthread_init_ex(); 69 | ctx = workqueue_init(32, 1, &ops); 70 | 71 | ret = workqueue_add_work(ctx, 2, 12000, 72 | callback_func, &counter); 73 | 74 | printf("waiting for %d jobs \n", ret); 75 | workqueue_show_status(ctx, stdout); 76 | printf("done show status \n"); 77 | sleep(30); 78 | 79 | for (i = 20; i && (ret = workqueue_get_queue_len(ctx)); i--) { 80 | printf("waiting for %d jobs \n", ret); 81 | sleep(1); 82 | } 83 | 84 | workqueue_destroy(ctx); 85 | 86 | return 0; 87 | } -------------------------------------------------------------------------------- /examples/pthread_wrap_ex/pthread_ex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PTHREAD_EX_INTERNAL 5 | #include "pthread_ex.h" 6 | #include "ex.h" 7 | 8 | /* context storage key */ 9 | static pthread_key_t pthread_ex_ctx_key; 10 | 11 | /* context destructor */ 12 | static void pthread_ex_ctx_destroy(void *data) 13 | { 14 | if (data != NULL) 15 | free(data); 16 | return; 17 | } 18 | 19 | /* callback: context fetching */ 20 | static ex_ctx_t *pthread_ex_ctx(void) 21 | { 22 | return (ex_ctx_t *) 23 | pthread_getspecific(pthread_ex_ctx_key); 24 | } 25 | 26 | /* callback: termination */ 27 | static void pthread_ex_terminate(ex_t *e) 28 | { 29 | pthread_exit(e->ex_value); 30 | } 31 | /* pthread init */ 32 | int pthread_init_ex(void) 33 | { 34 | int rc; 35 | 36 | /* additionally create thread data key 37 | and override OSSP ex callbacks */ 38 | pthread_key_create(&pthread_ex_ctx_key, 39 | pthread_ex_ctx_destroy); 40 | __ex_ctx = pthread_ex_ctx; 41 | __ex_terminate = pthread_ex_terminate; 42 | 43 | return rc; 44 | } 45 | 46 | /* internal thread entry wrapper information */ 47 | typedef struct { 48 | void *(*entry)(void *); /* start function */ 49 | void *arg; 50 | } pthread_create_ex_t; 51 | 52 | #if 0 53 | /* internal thread entry wrapper */ 54 | static void *pthread_create_wrapper(void *arg) 55 | { 56 | pthread_create_ex_t *wrapper; 57 | ex_ctx_t *ex_ctx; 58 | 59 | printf("in wrapper\n"); 60 | /* create per-thread exception context */ 61 | wrapper = (pthread_create_ex_t *)arg; 62 | ex_ctx = (ex_ctx_t *)malloc(sizeof(ex_ctx_t)); 63 | EX_CTX_INITIALIZE(ex_ctx); 64 | pthread_setspecific(pthread_ex_ctx_key, ex_ctx); 65 | 66 | /* perform original operation */ 67 | printf("Call original func\n"); 68 | return wrapper->entry(wrapper->arg); 69 | } 70 | 71 | /* pthread_create() wrapper */ 72 | int pthread_create_ex(pthread_t *thread, 73 | const pthread_attr_t *attr, 74 | void *(*entry)(void *), void *arg) 75 | { 76 | pthread_create_ex_t wrapper; 77 | 78 | /* spawn thread but execute start 79 | function through wrapper */ 80 | wrapper.entry = entry; 81 | wrapper.arg = arg; 82 | printf("creating thread\n"); 83 | return pthread_create(thread, attr, 84 | pthread_create_wrapper, &wrapper); 85 | } 86 | #endif 87 | 88 | #if 0 89 | /* internal thread entry wrapper */ 90 | static void *pthread_create_wrapper(void *arg) { 91 | pthread_create_ex_t wrapper; 92 | ex_ctx_t *ex_ctx; 93 | 94 | /* create per-thread exception context */ 95 | wrapper.entry = ((pthread_create_ex_t *)arg)->entry; 96 | wrapper.arg = ((pthread_create_ex_t *)arg)->arg; 97 | free (arg); 98 | 99 | ex_ctx = (ex_ctx_t *) calloc(1, sizeof(ex_ctx_t)); 100 | EX_CTX_INITIALIZE(ex_ctx); 101 | pthread_setspecific(pthread_ex_ctx_key, ex_ctx); 102 | 103 | /* perform original operation */ 104 | return wrapper.entry(wrapper.arg); 105 | } 106 | 107 | /* pthread_create() wrapper */ 108 | int 109 | pthread_create_ex(pthread_t * thread, 110 | const pthread_attr_t * attr, 111 | void *(*entry) (void *), void *arg) { 112 | pthread_create_ex_t *wrapper = calloc(1, sizeof(pthread_create_ex_t)); 113 | /* spawn thread but execute start 114 | function through wrapper */ 115 | wrapper->entry = entry; 116 | wrapper->arg = arg; 117 | return pthread_create(thread, attr, pthread_create_wrapper, 118 | wrapper); 119 | } 120 | #endif 121 | 122 | void ex_thread_init(void *arg) { 123 | ex_ctx_t *ex_ctx; 124 | 125 | ex_ctx = (ex_ctx_t *) calloc(1, sizeof(ex_ctx_t)); 126 | EX_CTX_INITIALIZE(ex_ctx); 127 | pthread_setspecific(pthread_ex_ctx_key, ex_ctx); 128 | } 129 | 130 | -------------------------------------------------------------------------------- /examples/pthread_wrap_ex/pthread_ex.h: -------------------------------------------------------------------------------- 1 | #ifndef __PTHREAD_EX_H__ 2 | #define __PTHREAD_EX_H__ 3 | 4 | #include 5 | #if 0 6 | int pthread_init_ex (void); 7 | int pthread_create_ex (pthread_t *, const pthread_attr_t *, 8 | void *(*)(void *), void *); 9 | 10 | #ifndef PTHREAD_EX_INTERNAL 11 | #define pthread_init pthread_init_ex 12 | #define pthread_create pthread_create_ex 13 | #endif 14 | #endif 15 | 16 | void ex_thread_init(void *arg); 17 | 18 | #endif /* __PTHREAD_EX_H__ */ 19 | -------------------------------------------------------------------------------- /examples/serial_port_test/Makefile.am: -------------------------------------------------------------------------------- 1 | WORKQUEUE_CFLAGS = -pthread -g3 -I../../lib 2 | WORKQUEUE_LDLAGS = -pthread -lworkqueue -lrt -L../../lib 3 | 4 | noinst_bin_PROGRAMS = serial_port_test 5 | noinst_bindir = $(abs_top_builddir)/example_progs 6 | 7 | serial_port_test_SOURCES = serial_port_test.c 8 | serial_port_test_CFLAGS = $(AM_CFLAGS) $(WORKQUEUE_CFLAGS) 9 | serial_port_test_LDFLAGS = $(WORKQUEUE_LDLAGS) 10 | -------------------------------------------------------------------------------- /examples/serial_port_test/serial_port_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file serial port I/O, a hardware queueing example. 3 | * @author Karl Hiramoto 4 | * @brief simple example showing example queueing commands on serial port. 5 | * 6 | * @NOTE this example is meant to be run with a loopback cable. 7 | * Cross RX and TX. Pins 2 and 3 on a DB 9 connector. 8 | * 9 | * 10 | * Example code is Distributed under Dual BSD / LGPL licence 11 | * Copyright 2009 Karl Hiramoto 12 | */ 13 | #define _GNU_SOURCE 14 | 15 | #include /* Standard lib */ 16 | #include /* Standard input/output definitions */ 17 | #include /* String function definitions */ 18 | 19 | 20 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 21 | 22 | #pragma once 23 | 24 | #include "windows.h" // big fat windows lib 25 | 26 | #else // on a unix/linux system 27 | #include // for timeing, timeouts, pselect 28 | #include 29 | #include 30 | #include /* UNIX standard function definitions */ 31 | #include /* File control definitions */ 32 | #include /* Error number definitions */ 33 | #include /* POSIX terminal control definitions */ 34 | 35 | #include 36 | #endif 37 | #include "workqueue.h" 38 | 39 | #define NUM_COMMANDS 5 40 | static const char *port_commands[NUM_COMMANDS+1] = { 41 | "command 0", 42 | "command 1", 43 | "command 2", 44 | "command 3", 45 | "command 4", 46 | "command 5", 47 | }; 48 | 49 | struct prg_ctx 50 | { 51 | struct workqueue_ctx *ctx; 52 | int counter; 53 | int fd; 54 | }; 55 | 56 | 57 | int write_serial_data(struct prg_ctx *prg_ctx, const char *buffer, unsigned int size) 58 | { 59 | 60 | char TempStr[16]; 61 | int ret; 62 | #ifdef WIN32 63 | DWORD Bytes_Written = 0; 64 | ret = WriteFile (prg_ctx->fd, (void *) buffer, size, &Bytes_Written, NULL); 65 | if (ret < 1) 66 | { 67 | perror ("Error Writing to Port WriteBuffer()"); 68 | Error_String = " Error Writing to Port WriteBuffer "; 69 | return false; 70 | } 71 | #else 72 | ret = write (prg_ctx->fd, buffer, size); // send all at once 73 | 74 | if (ret < 1) 75 | { 76 | snprintf (TempStr, 14, "Writing errno=%d", errno); 77 | perror(TempStr); 78 | return -errno; 79 | 80 | } 81 | 82 | if (tcdrain (prg_ctx->fd) < 0) 83 | { 84 | perror("tcdrain"); 85 | return -errno; // error writing. errno set 86 | } 87 | #endif 88 | 89 | return 0; 90 | } 91 | 92 | 93 | int read_serial_data (struct prg_ctx *prg_ctx,char *Buffer, int Buff_Size) 94 | { 95 | 96 | int select_retval = 0; 97 | int ret = 0; 98 | #ifdef WIN32 99 | // debug me. 100 | COMSTAT Win_ComStat; 101 | DWORD Win_BytesRead = 0; 102 | DWORD Win_ErrorMask = 0; 103 | ClearCommError (prg_ctx->fd, &Win_ErrorMask, &Win_ComStat); 104 | if (Win_ComStat.cbInQue && (!ReadFile (prg_ctx->fd, (void *) Buffer, 2048, &Win_BytesRead, NULL) || Win_BytesRead == 0)) 105 | { 106 | //lastErr=E_READ_FAILED; 107 | *Read_Size = -1; 108 | } 109 | else 110 | { 111 | *Read_Size = ((int) Win_BytesRead); 112 | } 113 | if (*Read_Size < 0) 114 | { 115 | Error_String += "Error in SerialClass::Read"; 116 | return false; 117 | } 118 | else 119 | { // no error 120 | // Data=Buffer; 121 | return true; 122 | } 123 | 124 | #else // POSIX linux code 125 | 126 | struct timeval tv; 127 | fd_set read_fileset; 128 | 129 | 130 | // setup timeout 131 | tv.tv_sec = 1; //wait 1 second max 132 | tv.tv_usec = 0; 133 | 134 | FD_ZERO (&read_fileset); 135 | FD_SET (prg_ctx->fd, &read_fileset); 136 | 137 | select_retval = select (prg_ctx->fd + 1, &read_fileset, NULL, NULL, &tv); 138 | 139 | if (select_retval < 0) 140 | { 141 | perror ("ERROR select()"); 142 | return -1; 143 | } 144 | else if (select_retval == 0) 145 | { // no data to read 146 | return -ENODATA; 147 | } 148 | else if (FD_ISSET(prg_ctx->fd, &read_fileset)) 149 | { 150 | ret = read (prg_ctx->fd, Buffer, Buff_Size); 151 | } 152 | 153 | if (ret < 0) 154 | { 155 | perror ("read error"); 156 | return -errno; 157 | } 158 | 159 | return ret; 160 | #endif 161 | 162 | } 163 | 164 | int config_serial_port(struct prg_ctx *prg_ctx,int baud, unsigned char data_bits, char parity, unsigned char stop_bits) 165 | { 166 | // const short int Data_Bits = 8; 167 | // const short int Stop_Bits = 1; 168 | #ifdef WIN32 169 | unsigned long confSize; 170 | 171 | /*configure port settings */ 172 | if (!GetCommConfig (fd, &Win_CommConfig, &confSize)) 173 | { 174 | char TempStr[128]; 175 | sprintf_s (TempStr, "Error Calling GetCommConfig in ConfigurePortDefault Error=%d", GetLastError ()); 176 | Error_String = TempStr; 177 | return false; 178 | } 179 | if (!GetCommState (fd, &(Win_CommConfig.dcb))) 180 | { 181 | char TempStr[128]; 182 | sprintf_s (TempStr, "Error Calling GetCommState in ConfigurePortDefault Error=%d", GetLastError ()); 183 | Error_String = TempStr; 184 | return false; 185 | } 186 | Win_CommConfig.dcb.fBinary = TRUE; // Windows does not support nonbinary mode transfers, so this member must be TRUE. 187 | Win_CommConfig.dcb.fInX = FALSE; // XON/XOFF disabled 188 | Win_CommConfig.dcb.fOutX = FALSE; // XON/XOFF disabled 189 | Win_CommConfig.dcb.fAbortOnError = FALSE; 190 | Win_CommConfig.dcb.fNull = FALSE; 191 | 192 | if (!SetBaudRate (baud)) 193 | { 194 | return false; 195 | } 196 | 197 | if (!SetDataBits (Data_Bits)) 198 | return false; 199 | 200 | if (!SetStopBits (Stop_Bits)) 201 | return false; 202 | 203 | if (!SetParity (parity)) 204 | return false; 205 | 206 | if (!SetFlowControl (FLOW_OFF)) 207 | return false; 208 | 209 | //setTimeout(0,10); 210 | if (SetCommConfig (fd, &Win_CommConfig, sizeof (Win_CommConfig))) 211 | { 212 | return 0; 213 | } 214 | else 215 | { 216 | char TempStr[128]; 217 | sprintf_s (TempStr, " in ConfigurePortDefault SetCommConfig Error: %d ", GetLastError ()); 218 | Error_String += TempStr; 219 | return false; 220 | } 221 | 222 | #else // POSIX linux 223 | struct termios options; 224 | if (tcgetattr (prg_ctx->fd, &options) < 0) // get the opts 225 | { 226 | perror("tcgetattr"); 227 | return -errno; 228 | } 229 | 230 | 231 | if (baud == 1200) 232 | { 233 | cfsetispeed (&options, B1200); 234 | cfsetospeed (&options, B1200); 235 | } 236 | 237 | else if (baud == 2400) 238 | { 239 | cfsetispeed (&options, B2400); 240 | cfsetospeed (&options, B2400); 241 | } 242 | else if (baud == 4800) 243 | { 244 | cfsetispeed (&options, B4800); 245 | cfsetospeed (&options, B4800); 246 | } 247 | else if (baud == 9600) 248 | { 249 | cfsetispeed (&options, B9600); 250 | cfsetospeed (&options, B9600); 251 | } 252 | else if (baud == 19200) 253 | { 254 | cfsetispeed (&options, B19200); 255 | cfsetospeed (&options, B19200); 256 | } 257 | else if (baud == 57600) 258 | { 259 | cfsetispeed (&options, B57600); 260 | cfsetospeed (&options, B57600); 261 | } 262 | else 263 | return -EINVAL; 264 | 265 | // set to no parity 8N1 266 | 267 | if (parity == 'N') 268 | options.c_cflag &= ~PARENB; // no parity clear flag 269 | else 270 | { 271 | options.c_cflag |= PARENB; // set parity flag 272 | 273 | if (parity == 'E') 274 | options.c_cflag &= ~PARODD; // clear odd bit 275 | else if (parity == 'O') 276 | options.c_cflag |= PARODD; // set odd bit 277 | else //unknown opt 278 | return -EINVAL; 279 | } 280 | 281 | if (stop_bits == 1) 282 | options.c_cflag &= ~CSTOPB; // clear flag. one stop bit 283 | else if (stop_bits == 2) 284 | options.c_cflag |= CSTOPB; // set flag. 2 stop bits 285 | else 286 | return -EINVAL; //unknown opt 287 | 288 | 289 | options.c_cflag &= ~CSIZE; // clear data bits mask 290 | 291 | if (data_bits == 8) 292 | options.c_cflag |= CS8; 293 | else if (data_bits == 7) 294 | options.c_cflag |= CS7; 295 | else if (data_bits == 6) 296 | options.c_cflag |= CS6; 297 | else 298 | return -EINVAL; //unknown opt; 299 | 300 | 301 | // options.c_oflag &= ~OPOST; 302 | 303 | // disable flow control 304 | // options.c_cflag &= ~CNEW_RTSCTS; 305 | /* 306 | * Enable the receiver and set local mode... 307 | */ 308 | 309 | options.c_cflag |= (CLOCAL | CREAD); 310 | 311 | // options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // clear these flags. canonical input, echo, echo errase 312 | options.c_lflag = 0; // disable 313 | 314 | // set raw output. don't do any CR LF translations 315 | options.c_oflag &= ~OPOST; // clear post process flag. (raw) 316 | options.c_oflag &= ~OLCUC; // clear 317 | options.c_oflag &= ~ONLCR; 318 | options.c_oflag &= ~OCRNL; 319 | 320 | options.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off flow control 321 | options.c_iflag &= ~(ICRNL | INLCR | IGNCR | IUCLC); // turn off Ignore CR, Map CR to NL, Map NL to CR 322 | 323 | 324 | options.c_cc[VMIN] = 0; // minimum number of chars to read() 325 | options.c_cc[VTIME] = 10; // time to wait for first char. in 10'ths of seconds 326 | 327 | 328 | options.c_cflag &= ~CRTSCTS; // disable flow control 329 | 330 | // cfmakeraw( &options); // set in raw mode 331 | 332 | 333 | // Set the new options for the port... 334 | if (tcsetattr (prg_ctx->fd, TCSANOW, &options) < 0) 335 | { 336 | perror("tcsetattr"); 337 | return -errno; 338 | } 339 | 340 | return 0; 341 | #endif 342 | 343 | } 344 | 345 | int open_port (struct prg_ctx *prg_ctx, const char *dev_name) 346 | { 347 | 348 | #ifdef WIN32 349 | prg_ctx->fd = CreateFileA (dev_name.c_str (), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 350 | if (fd == INVALID_HANDLE_VALUE) 351 | { // Could not open the port. 352 | printf ("CreateFile failed with error %d.\n", GetLastError ()); 353 | #else 354 | /*POSIX */ 355 | prg_ctx->fd = open (dev_name, O_RDWR | O_NOCTTY | O_NDELAY); 356 | if (prg_ctx->fd == -1) 357 | { // Could not open the port. 358 | 359 | #endif 360 | char err_str[128]; 361 | snprintf (err_str, 127, "open_port: Unable to open %s", dev_name); 362 | perror (err_str); 363 | return -errno; 364 | } 365 | else 366 | { 367 | // fcntl(fd, F_SETFL, 0); //restore blocking read 368 | 369 | #ifdef WIN32 370 | // FIX ME add non blocking flags for windows 371 | #else 372 | // fcntl (prg_ctx->fd, F_SETFL, O_NDELAY);// no delay on read. no block 373 | #endif 374 | 375 | } 376 | return 0; 377 | } 378 | 379 | void do_cmd(struct prg_ctx *prg, unsigned int i) 380 | { 381 | int ret = 0; 382 | unsigned int len = 0; 383 | char buff[256]; 384 | if (i < NUM_COMMANDS) { 385 | printf("sending cmd='%s'\n", port_commands[i]); 386 | len = strlen(port_commands[i]) +1; 387 | ret = write_serial_data(prg, port_commands[i], len); 388 | if (ret < 0) { 389 | fprintf(stderr, "error writing cmd %d\n", i); 390 | return; 391 | } 392 | usleep(12345); 393 | ret = read_serial_data (prg, buff, 255); 394 | 395 | if (ret < 0) { 396 | printf("error reading cmd %d : %d=%s \n", 397 | i, ret, strerror_r(-ret, buff, 255) ); 398 | return; 399 | } 400 | printf("Read cmd %d ='%s'\n",i, buff); 401 | } else { 402 | fprintf(stderr, "Invalid command"); 403 | } 404 | 405 | } 406 | 407 | static void callback_func0(void *data) 408 | { 409 | struct prg_ctx *prg = (struct prg_ctx *) data; 410 | do_cmd(prg, 0); 411 | } 412 | 413 | static void callback_func1(void *data) 414 | { 415 | struct prg_ctx *prg = (struct prg_ctx *) data; 416 | do_cmd(prg, 1); 417 | } 418 | static void callback_func2(void *data) 419 | { 420 | struct prg_ctx *prg = (struct prg_ctx *) data; 421 | do_cmd(prg, 2); 422 | } 423 | 424 | 425 | static void callback_func3(void *data) 426 | { 427 | struct prg_ctx *prg = (struct prg_ctx *) data; 428 | do_cmd(prg, 3); 429 | } 430 | static void callback_func4(void *data) 431 | { 432 | struct prg_ctx *prg = (struct prg_ctx *) data; 433 | do_cmd(prg, 4); 434 | } 435 | 436 | 437 | /** 438 | * 439 | * @param argc 440 | * @param argv[] 441 | * @return 442 | */ 443 | int main(int argc, char *argv[]) { 444 | struct prg_ctx prg = { .counter = 0}; 445 | int ret; 446 | int i; 447 | printf("starting argc=%d\n", argc); 448 | if (argc < 2) { 449 | printf("usage %s \n", argv[0]); 450 | return -1; 451 | } 452 | 453 | prg.ctx = workqueue_init(32, 1, NULL); 454 | 455 | 456 | ret = open_port (&prg, argv[1]); 457 | 458 | ret = config_serial_port(&prg, 9600, 8, 'N', 1); 459 | 460 | ret = workqueue_add_work(prg.ctx, 5, 0, 461 | callback_func0, &prg); 462 | 463 | if (ret >= 0) { 464 | printf("Added job %d \n", ret); 465 | } else { 466 | printf("Error adding job err=%d\n", ret); 467 | } 468 | 469 | ret = workqueue_add_work(prg.ctx, 5, 0, 470 | callback_func1, &prg); 471 | 472 | if (ret >= 0) { 473 | printf("Added job %d \n", ret); 474 | } else { 475 | printf("Error adding job err=%d\n", ret); 476 | } 477 | 478 | ret = workqueue_add_work(prg.ctx, 1, 0, 479 | callback_func2, &prg); 480 | 481 | if (ret >= 0) { 482 | printf("Added job %d \n", ret); 483 | } else { 484 | printf("Error adding job err=%d\n", ret); 485 | } 486 | 487 | ret = workqueue_add_work(prg.ctx, 1, 0, 488 | callback_func3, &prg); 489 | 490 | if (ret >= 0) { 491 | printf("Added job %d \n", ret); 492 | } else { 493 | printf("Error adding job err=%d\n", ret); 494 | } 495 | 496 | ret = workqueue_add_work(prg.ctx, 1, 0, 497 | callback_func4, &prg); 498 | 499 | if (ret >= 0) { 500 | printf("Added job %d \n", ret); 501 | } else { 502 | printf("Error adding job err=%d\n", ret); 503 | } 504 | 505 | workqueue_show_status(prg.ctx, stdout); 506 | 507 | 508 | workqueue_show_status(prg.ctx, stdout); 509 | 510 | 511 | 512 | for (i = 20; i && (ret = workqueue_get_queue_len(prg.ctx)); i--) { 513 | printf("waiting for %d jobs \n", ret); 514 | sleep(1); 515 | } 516 | sleep(2); 517 | workqueue_destroy(prg.ctx); 518 | 519 | return 0; 520 | } -------------------------------------------------------------------------------- /examples/simple_cpp/Makefile.am: -------------------------------------------------------------------------------- 1 | WORKQUEUE_CXXFLAGS = -pthread -g3 -I../../lib 2 | WORKQUEUE_LDLAGS = -lworkqueue -lpthread -lrt -pthread -L../../lib 3 | 4 | noinst_bin_PROGRAMS = simple 5 | noinst_bindir = $(abs_top_builddir)/example_progs 6 | 7 | simple_SOURCES = simple.cpp 8 | simple_CXXFLAGS = $(AM_CFLAGS) $(WORKQUEUE_CXXFLAGS) 9 | simple_LDFLAGS = $(WORKQUEUE_LDLAGS) 10 | -------------------------------------------------------------------------------- /examples/simple_cpp/simple.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file simple test example 3 | * @author Karl Hiramoto 4 | * @brief simple example showing how to enqueue worker jobs 5 | * 6 | * Example code is Distributed under Dual BSD / LGPL licence 7 | * Copyright 2009 Karl Hiramoto 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 15 | 16 | #if !defined(WINDOWS) 17 | #define WINDOWS 18 | #endif 19 | 20 | #pragma once 21 | #include "windows.h" // big fat windows lib 22 | #define sleep(x) Sleep(x*1000) 23 | #else 24 | #include 25 | #endif 26 | 27 | #include "workqueue.h" 28 | 29 | 30 | class prg_ctx 31 | { 32 | public: 33 | work_queue_class *wq; 34 | int counter; 35 | prg_ctx(unsigned int queue_size, unsigned int num_worker_threads) { 36 | 37 | wq = new work_queue_class(queue_size, num_worker_threads); 38 | counter = 0; 39 | } 40 | ~prg_ctx(void) { 41 | delete wq; 42 | } 43 | }; 44 | 45 | 46 | static void callback_func(void *data) 47 | { 48 | struct prg_ctx *prg = (struct prg_ctx *) data; 49 | int ret; 50 | 51 | prg->counter++; 52 | printf("counter=%d\n", prg->counter); 53 | if (prg->counter % 2) 54 | sleep(1); 55 | 56 | if ((prg->counter % 4) == 0) { 57 | printf("reschedule this job\n"); 58 | ret = prg->wq->add_work(2, 1234, 59 | callback_func, prg); 60 | 61 | if (ret >= 0) { 62 | printf("Added job %d \n", ret); 63 | prg->wq->show_status(stdout); 64 | } else { 65 | printf("Error adding job err=%d\n", ret); 66 | } 67 | } 68 | } 69 | 70 | int main(int argc, char *argv[]) { 71 | struct prg_ctx prg(32,1); 72 | int i; 73 | int num_jobs=6; 74 | int ret; 75 | printf("starting\n"); 76 | 77 | for (i = 0; i < num_jobs; i++) { 78 | ret = prg.wq->add_work(2, 0, 79 | callback_func, &prg); 80 | 81 | if (ret >= 0) { 82 | printf("Added job %d \n", ret); 83 | } else { 84 | printf("Error adding job err=%d\n", ret); 85 | } 86 | } 87 | prg.wq->show_status(stdout); 88 | 89 | for (i = 0; i < num_jobs; i++) { 90 | printf("job %d is queued=%d running=%d queued_or_running=%d\n", i, 91 | prg.wq->job_queued(i), 92 | prg.wq->job_running(i), 93 | prg.wq->job_queued_or_running(i)); 94 | } 95 | 96 | for (i = 0; i < num_jobs/2; i++) { 97 | ret = prg.wq->add_work(5, 0, 98 | callback_func, &prg); 99 | 100 | if (ret >= 0) { 101 | printf("Added job %d \n", ret); 102 | } else { 103 | printf("Error adding job err=%d\n", ret); 104 | } 105 | } 106 | prg.wq->show_status(stdout); 107 | 108 | for (i = 0; i < num_jobs/2; i++) { 109 | ret = prg.wq->add_work(1, 0, 110 | callback_func, &prg); 111 | 112 | if (ret >= 0) { 113 | printf("Added job %d \n", ret); 114 | } else { 115 | printf("Error adding job err=%d\n", ret); 116 | } 117 | } 118 | prg.wq->show_status(stdout); 119 | 120 | for (i = 20; i && (ret = prg.wq->get_queue_len()); i--) { 121 | printf("waiting for %d jobs \n", ret); 122 | sleep(1); 123 | } 124 | 125 | #ifdef WINDOWS 126 | system("pause"); 127 | #endif 128 | return 0; 129 | } -------------------------------------------------------------------------------- /examples/simple_test/Makefile.am: -------------------------------------------------------------------------------- 1 | WORKQUEUE_CFLAGS = -pthread -g3 -I../../lib 2 | WORKQUEUE_LDLAGS = -pthread -lworkqueue -lrt -L../../lib 3 | 4 | noinst_bin_PROGRAMS = simple_test 5 | noinst_bindir = $(abs_top_builddir)/example_progs 6 | 7 | simple_test_SOURCES = simple_test.c 8 | simple_test_CFLAGS = $(AM_CFLAGS) $(WORKQUEUE_CFLAGS) 9 | simple_test_LDFLAGS = $(WORKQUEUE_LDLAGS) 10 | -------------------------------------------------------------------------------- /examples/simple_test/simple_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file simple test example 3 | * @author Karl Hiramoto 4 | * @brief simple example showing how to enqueue worker jobs 5 | * 6 | * Example code is Distributed under Dual BSD / LGPL licence 7 | * Copyright 2009 Karl Hiramoto 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 15 | 16 | #if !defined(WINDOWS) 17 | #define WINDOWS 18 | #endif 19 | 20 | #pragma once 21 | #include "windows.h" // big fat windows lib 22 | #define sleep(x) Sleep(x*1000) 23 | #else 24 | #include 25 | #endif 26 | 27 | #include "workqueue.h" 28 | 29 | 30 | struct prg_ctx 31 | { 32 | struct workqueue_ctx *ctx; 33 | int counter; 34 | }; 35 | 36 | 37 | static void callback_func(void *data) 38 | { 39 | struct prg_ctx *prg = (struct prg_ctx *) data; 40 | int ret; 41 | 42 | prg->counter++; 43 | printf("counter=%d\n", prg->counter); 44 | if (prg->counter % 2) 45 | sleep(1); 46 | 47 | if ((prg->counter % 4) == 0) { 48 | printf("reschedule this job\n"); 49 | ret = workqueue_add_work(prg->ctx, 2, 1234, 50 | callback_func, prg); 51 | 52 | if (ret >= 0) { 53 | printf("Added job %d \n", ret); 54 | workqueue_show_status(prg->ctx, stdout); 55 | } else { 56 | printf("Error adding job err=%d\n", ret); 57 | } 58 | } 59 | } 60 | 61 | int main(int argc, char *argv[]) { 62 | struct prg_ctx prg; 63 | int i; 64 | int num_jobs=6; 65 | int ret; 66 | printf("starting\n"); 67 | prg.counter = 0; 68 | prg.ctx = workqueue_init(32, 1, NULL); 69 | 70 | for (i = 0; i < num_jobs; i++) { 71 | ret = workqueue_add_work(prg.ctx, 2, 0, 72 | callback_func, &prg); 73 | 74 | if (ret >= 0) { 75 | printf("Added job %d \n", ret); 76 | } else { 77 | printf("Error adding job err=%d\n", ret); 78 | } 79 | } 80 | workqueue_show_status(prg.ctx, stdout); 81 | 82 | for (i = 0; i < num_jobs; i++) { 83 | printf("job %d is queued=%d running=%d queued_or_running=%d\n", i, 84 | workqueue_job_queued(prg.ctx, i), 85 | workqueue_job_running(prg.ctx, i), 86 | workqueue_job_queued_or_running(prg.ctx, i)); 87 | } 88 | 89 | for (i = 0; i < num_jobs/2; i++) { 90 | ret = workqueue_add_work(prg.ctx, 5, 0, 91 | callback_func, &prg); 92 | 93 | if (ret >= 0) { 94 | printf("Added job %d \n", ret); 95 | } else { 96 | printf("Error adding job err=%d\n", ret); 97 | } 98 | } 99 | workqueue_show_status(prg.ctx, stdout); 100 | 101 | for (i = 0; i < num_jobs/2; i++) { 102 | ret = workqueue_add_work(prg.ctx, 1, 0, 103 | callback_func, &prg); 104 | 105 | if (ret >= 0) { 106 | printf("Added job %d \n", ret); 107 | } else { 108 | printf("Error adding job err=%d\n", ret); 109 | } 110 | } 111 | workqueue_show_status(prg.ctx, stdout); 112 | 113 | for (i = 20; i && (ret = workqueue_get_queue_len(prg.ctx)) > 5; i--) { 114 | printf("waiting for %d jobs \n", ret); 115 | sleep(1); 116 | } 117 | 118 | // empty out remaining jobs and wait for running job to finish 119 | workqueue_empty_wait(prg.ctx); 120 | 121 | workqueue_destroy(prg.ctx); 122 | 123 | #ifdef WINDOWS 124 | system("pause"); 125 | #endif 126 | return 0; 127 | } -------------------------------------------------------------------------------- /examples/simple_test/simple_test.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 28 | 31 | 34 | 37 | 40 | 43 | 58 | 61 | 64 | 67 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 98 | 99 | 107 | 110 | 113 | 116 | 119 | 122 | 136 | 139 | 142 | 145 | 156 | 159 | 162 | 165 | 168 | 171 | 174 | 177 | 178 | 179 | 180 | 184 | 185 | 186 | 191 | 194 | 195 | 196 | 201 | 204 | 205 | 206 | 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /examples/time_sort/Makefile.am: -------------------------------------------------------------------------------- 1 | WORKQUEUE_CFLAGS = -pthread -g3 -I../../lib 2 | WORKQUEUE_LDLAGS = -pthread -lworkqueue -lrt -L../../lib 3 | 4 | noinst_bin_PROGRAMS = time_sort 5 | noinst_bindir = $(abs_top_builddir)/example_progs 6 | 7 | time_sort_SOURCES = time_sort.c 8 | time_sort_CFLAGS = $(AM_CFLAGS) $(WORKQUEUE_CFLAGS) 9 | time_sort_LDFLAGS = $(WORKQUEUE_LDLAGS) 10 | -------------------------------------------------------------------------------- /examples/time_sort/time_sort.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file simple test example 3 | * @author Karl Hiramoto 4 | * @brief simple example showing how to enqueue worker jobs 5 | * 6 | * Example code is Distributed under Dual BSD / LGPL licence 7 | * Copyright 2009 Karl Hiramoto 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 15 | 16 | #if !defined(WINDOWS) 17 | #define WINDOWS 18 | #endif 19 | 20 | #pragma once 21 | #include "windows.h" // big fat windows lib 22 | #define sleep(x) Sleep(x*1000) 23 | #else 24 | #include 25 | #endif 26 | 27 | #include "workqueue.h" 28 | 29 | 30 | struct prg_ctx 31 | { 32 | struct workqueue_ctx *ctx; 33 | int counter; 34 | }; 35 | 36 | 37 | static void callback_func(void *data) 38 | { 39 | struct prg_ctx *prg = (struct prg_ctx *) data; 40 | int ret; 41 | 42 | prg->counter++; 43 | printf("counter=%d\n", prg->counter); 44 | if (prg->counter % 2) 45 | sleep(1); 46 | 47 | if ((prg->counter % 4) == 0) { 48 | printf("reschedule this job\n"); 49 | ret = workqueue_add_work(prg->ctx, 2, 1234, 50 | callback_func, prg); 51 | 52 | if (ret >= 0) { 53 | printf("Added job %d \n", ret); 54 | workqueue_show_status(prg->ctx, stdout); 55 | } else { 56 | printf("Error adding job err=%d\n", ret); 57 | } 58 | } 59 | } 60 | 61 | int main(int argc, char *argv[]) { 62 | struct prg_ctx prg; 63 | int i; 64 | int num_jobs = 32; 65 | int ret; 66 | printf("starting\n"); 67 | prg.counter = 0; 68 | prg.ctx = workqueue_init(32, 1, NULL); 69 | 70 | for (i = num_jobs; i ; i--) { 71 | ret = workqueue_add_work(prg.ctx, 2, i*1234, 72 | callback_func, &prg); 73 | 74 | if (ret >= 0) { 75 | printf("Added job %d \n", ret); 76 | } else { 77 | printf("Error adding job err=%d\n", ret); 78 | } 79 | workqueue_show_status(prg.ctx, stdout); 80 | } 81 | 82 | 83 | for (i = 0; i < num_jobs; i++) { 84 | printf("job %d is queued=%d running=%d queued_or_running=%d\n", i, 85 | workqueue_job_queued(prg.ctx, i), 86 | workqueue_job_running(prg.ctx, i), 87 | workqueue_job_queued_or_running(prg.ctx, i)); 88 | } 89 | 90 | for (i = 90; i && (ret = workqueue_get_queue_len(prg.ctx)) > 3; i--) { 91 | printf("waiting for %d jobs \n", ret); 92 | sleep(1); 93 | } 94 | 95 | // empty out remaining jobs and wait for running job to finish 96 | workqueue_empty_wait(prg.ctx); 97 | 98 | workqueue_destroy(prg.ctx); 99 | 100 | #ifdef WINDOWS 101 | system("pause"); 102 | #endif 103 | return 0; 104 | } -------------------------------------------------------------------------------- /lib/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = . 2 | 3 | # CURRENT_USER=$(shell whoami) 4 | # CURRENT_HOST=$(shell hostname) 5 | 6 | 7 | lib_LTLIBRARIES = libworkqueue.la 8 | 9 | include_HEADERS = workqueue.h 10 | libworkqueue_la_SOURCES = workqueue.c 11 | libworkqueue_la_LDFLAGS = -version-info 0:6:0 12 | -------------------------------------------------------------------------------- /lib/win32/stdbool.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2001-2002 Free Software Foundation, Inc. 2 | Written by Bruno Haible , 2001. 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2, or (at your option) 7 | any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software Foundation, 16 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 17 | 18 | #ifndef _STDBOOL_H 19 | #define _STDBOOL_H 20 | 21 | /* ISO C 99 for platforms that lack it. */ 22 | 23 | /* 7.16. Boolean type and values */ 24 | 25 | /* BeOS already #defines false 0, true 1. We use the same 26 | definitions below, but temporarily we have to #undef them. */ 27 | #ifdef __BEOS__ 28 | # undef false 29 | # undef true 30 | #endif 31 | 32 | /* For the sake of symbolic names in gdb, define _Bool as an enum type. */ 33 | #ifndef __cplusplus 34 | # if !0 35 | typedef enum { false = 0, true = 1 } _Bool; 36 | # endif 37 | #else 38 | typedef bool _Bool; 39 | #endif 40 | #define bool _Bool 41 | 42 | /* The other macros must be usable in preprocessor directives. */ 43 | #define false 0 44 | #define true 1 45 | #define __bool_true_false_are_defined 1 46 | 47 | #endif /* _STDBOOL_H */ 48 | -------------------------------------------------------------------------------- /lib/workqueue.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Workqueue.c 3 | * @author Karl Hiramoto 4 | * @brief Library for priority work queues. 5 | * 6 | * Distributed under LGPL see COPYING.LGPL 7 | * Copyright 2009 Karl Hiramoto 8 | */ 9 | 10 | // #define DEBUG 11 | 12 | #include 13 | #include 14 | 15 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 16 | 17 | 18 | #pragma once 19 | #include "windows.h" // big fat windows lib 20 | 21 | #include 22 | #include 23 | #include "win32/stdbool.h" 24 | 25 | #if !defined(WINDOWS) 26 | #define WINDOWS 27 | #endif 28 | 29 | #ifdef DEBUG 30 | #define DEBUG_MSG(fmt, ...) { printf("%s:%d " fmt, __FUNCTION__, __LINE__, __VA_ARGS__); } 31 | #else 32 | #define DEBUG_MSG(fmt, ...) 33 | #endif 34 | 35 | #define assert(x) 36 | #define ENOMEM ERROR_NOT_ENOUGH_MEMORY 37 | #define EBUSY ERROR_BUSY 38 | #define ENOENT ERROR_NOT_FOUND 39 | 40 | #define ERROR_MSG(fmt, ...) { printf("%s:%d " fmt, __FUNCTION__, __LINE__, __VA_ARGS__); } 41 | 42 | #define GET_TIME(x) _ftime_s(&x) 43 | #define TIME_STRUCT_TYPE _timeb 44 | 45 | #define LOCK_MUTEX(mutex) EnterCriticalSection(mutex) 46 | #define TRY_LOCK_MUTEX(mutex, r) r = TryEnterCriticalSection(mutex); 47 | #define UNLOCK_MUTEX(x) LeaveCriticalSection(x) 48 | #define pthread_join(A,B) \ 49 | ((WaitForSingleObject((A), INFINITE) != WAIT_OBJECT_0) || !CloseHandle(A)) 50 | 51 | 52 | /* if time X is > y*/ 53 | //#define TIME_GT(x,y) (x.time > y->time || (x.time == y->time && x.millitm > y->millitm) ) 54 | #define TIME_SEC(x) x.time 55 | #define TIME_SECP(x) x->time 56 | #define TIME_MSEC(x) x.millitm 57 | #define TIME_MSECP(x) x->millitm 58 | 59 | 60 | 61 | #else // on a unix/linux system 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | #ifdef DEBUG 71 | #define DEBUG_MSG(fmt, s...) { printf("%s:%d " fmt, __FUNCTION__,__LINE__, ## s); } 72 | #else 73 | #define DEBUG_MSG(fmt, s...) 74 | #endif 75 | #define ERROR_MSG(fmt, s...) { fprintf(stderr, "ERROR %s:%d " fmt, __FUNCTION__,__LINE__, ## s); } 76 | 77 | #define GET_TIME(x) clock_gettime(CLOCK_REALTIME, &x) 78 | #define TIME_STRUCT_TYPE timespec 79 | // #define LOCK_MUTEX(mutex) pthread_mutex_lock(mutex) 80 | // #define UNLOCK_MUTEX(x) pthread_mutex_unlock(x) 81 | #define LOCK_MUTEX(mutex) { DEBUG_MSG("LOCKING " #mutex " get %s:%d\n" , __FUNCTION__,__LINE__); pthread_mutex_lock(mutex); DEBUG_MSG("LOCKED " #mutex " got %s:%d \n" , __FUNCTION__,__LINE__); } 82 | 83 | #define TRY_LOCK_MUTEX(mutex, r) { DEBUG_MSG("TRYLOCK " #mutex " get %s:%d\n" , __FUNCTION__,__LINE__); r = pthread_mutex_trylock(mutex); DEBUG_MSG ("TRYLOCK " #mutex " got %s:%d r=%d \n" , __FUNCTION__,__LINE__,r); } 84 | 85 | #define UNLOCK_MUTEX(x) { DEBUG_MSG("UNLOCK " #x " %s:%d\n" , __FUNCTION__,__LINE__); pthread_mutex_unlock(x); } 86 | 87 | #define TIME_SEC(x) x.tv_sec 88 | #define TIME_SECP(x) x->tv_sec 89 | #define TIME_MSEC(x) (x.tv_nsec / 1000000) 90 | #define TIME_MSECP(x) (x->tv_nsec / 1000000) 91 | 92 | #endif 93 | 94 | 95 | #include "workqueue.h" 96 | 97 | 98 | 99 | /** 100 | * @struct workqueue_job 101 | * @brief Every scheduled or running job has a instance of this struct 102 | * @brief This data is private to the library 103 | */ 104 | struct workqueue_job 105 | { 106 | int priority; /** Job priority. Lower number is higher priority as on all UNIX OS's */ 107 | unsigned int job_id; /** Job ID 1st job is 1 then goes up */ 108 | struct TIME_STRUCT_TYPE start_time; /** Time the job was started */ 109 | workqueue_func_t func; /** Callback function pointer*/ 110 | void * data; /** Data to pass to callback pointer */ 111 | }; 112 | 113 | /** 114 | * @struct workqueue_thread 115 | * @brief Every worker thread has an instance of this struct. 116 | * @brief This data is private to the library. 117 | */ 118 | struct workqueue_thread 119 | { 120 | 121 | #ifdef WINDOWS 122 | CRITICAL_SECTION mutex; /** used to lock this struct and thread*/ 123 | CRITICAL_SECTION job_mutex; /** locked while job is running */ 124 | HANDLE thread_id; /* handle returned by CreateThread() */ 125 | #else 126 | pthread_mutex_t mutex; /** used to lock this struct and thread*/ 127 | pthread_mutex_t job_mutex; /** locked while job is running */ 128 | pthread_t thread_id; /** ID returned by pthread_create() */ 129 | #endif 130 | int thread_num; /** Application-defined thread # */ 131 | bool keep_running; /** while true schedule next job */ 132 | struct workqueue_ctx *ctx; /** parent context*/ 133 | struct workqueue_job *job; /** Currently running job or NULL if no job*/ 134 | }; 135 | 136 | /** 137 | * @struct workqueue_ctx 138 | * @brief This the the context of the library. Multiple contexts are permited. 139 | * @brief This data is private to the library. 140 | */ 141 | 142 | struct workqueue_ctx 143 | { 144 | #ifdef WINDOWS 145 | CRITICAL_SECTION mutex; /** used to lock this struct */ 146 | HANDLE work_ready_cond; /** used to signal waiting threads that new work is ready */ 147 | CRITICAL_SECTION cond_mutex; /** lock condition. TODO NOT needed on windows? */ 148 | #else 149 | pthread_mutex_t mutex; /** used to lock this struct */ 150 | pthread_cond_t work_ready_cond; /** used to signal waiting threads that new work is ready */ 151 | pthread_mutex_t cond_mutex; /** used to lock condition variable*/ 152 | #endif 153 | struct worker_thread_ops *ops; /** worker init cleanup functions */ 154 | int num_worker_threads; /** Number of worker threads this context has */ 155 | int job_count; /** starts at 0 and goes to 2^31 then back to 0 */ 156 | int queue_size; /** max number of jobs that can be queued */ 157 | int waiting_jobs; /** current number of jobs in queue */ 158 | struct workqueue_thread **thread; /** array of num_worker_threads */ 159 | struct workqueue_job **queue; /** array of queue_size */ 160 | }; 161 | 162 | /* if time X is > y*/ 163 | static int _time_gt (struct TIME_STRUCT_TYPE *x, struct TIME_STRUCT_TYPE *y) 164 | { 165 | #ifdef WINDOWS 166 | if (x->time > y->time || (x->time == y->time && x->millitm > y->millitm) ) 167 | return 1; 168 | 169 | #else 170 | if (x->tv_sec > y->tv_sec || (x->tv_sec == y->tv_sec && x->tv_nsec > y->tv_nsec) ) 171 | return 1; 172 | #endif 173 | return 0; 174 | } 175 | 176 | /** 177 | * @brief Compare function for qsort() 178 | * @param ptr1 pointer to a workqueue_job 179 | * @param ptr2 pointer to a workqueue_job 180 | * @return 0 if jobs equal or both null. -1 if ptr1 < ptr2 181 | */ 182 | static int job_compare(const void *ptr1, const void *ptr2) 183 | { 184 | struct workqueue_job **j1, **j2; 185 | struct workqueue_job *job1, *job2; 186 | 187 | // DEBUG_MSG("p1=%p p2=%p \n", ptr1, ptr2); 188 | 189 | /* dereference job pointers*/ 190 | j1 = (struct workqueue_job **) ptr1; 191 | j2 = (struct workqueue_job **) ptr2; 192 | job1 = *j1; 193 | job2 = *j2; 194 | 195 | // DEBUG_MSG("job1=%p job2=%p \n", job1, job2); 196 | 197 | /* check for null pointers*/ 198 | if ( job1 == NULL && job2 == NULL) 199 | return 0; 200 | else if ( job1 == NULL) 201 | return 1; /* j2 is not null*/ 202 | else if (job2 == NULL) 203 | return -1; /* j1 is null */ 204 | 205 | // DEBUG_MSG("pri1=%d pri2=%d id1=%d id2=%d\n",job1->priority, job2->priority, job1->job_id, job2->job_id); 206 | 207 | /* check jobs for priority order */ 208 | if (job1->priority < job2->priority) 209 | return -1; 210 | else if (job1->priority > job2->priority) 211 | return 1; 212 | #ifdef WINDOWS 213 | //FIXME 214 | #else 215 | /* check jobs for scheduled time */ 216 | if (job1->start_time.tv_sec < job2->start_time.tv_sec) 217 | return -1; 218 | else if (job1->start_time.tv_sec > job2->start_time.tv_sec) 219 | return 1; 220 | 221 | /* seconds must be equal so compare nanoseconds */ 222 | if (job1->start_time.tv_nsec < job2->start_time.tv_nsec) 223 | return -1; 224 | else if (job1->start_time.tv_nsec > job2->start_time.tv_nsec) 225 | return 1; 226 | #endif 227 | 228 | if (job1->job_id < job2->job_id) 229 | return -1; 230 | else if (job1->job_id > job2->job_id) 231 | return 1; 232 | 233 | return 0; 234 | } 235 | 236 | /*time x-y */ 237 | static long long time_diff_ms(struct TIME_STRUCT_TYPE *x, 238 | struct TIME_STRUCT_TYPE *y) 239 | { 240 | long long diff; 241 | diff = (TIME_SECP(x) - TIME_SECP(y))*1000; 242 | 243 | diff += TIME_MSECP(x) - TIME_MSECP(y); 244 | return diff; 245 | } 246 | 247 | // dequeue the next job that needes to run in this thread 248 | static struct workqueue_job* _workqueue_get_job(struct workqueue_thread *thread, 249 | struct TIME_STRUCT_TYPE *wait_time, 250 | long long *wait_ms) 251 | { 252 | int i; 253 | struct workqueue_job *job = NULL; 254 | struct workqueue_ctx *ctx = thread->ctx; 255 | struct TIME_STRUCT_TYPE now; 256 | 257 | if (!thread->keep_running) 258 | return NULL; 259 | 260 | /* init default wait time*/ 261 | GET_TIME(now); 262 | *wait_time = now; 263 | TIME_SECP(wait_time) += 9999; // if no work wait for 9999 sec 264 | *wait_ms = 5000; 265 | 266 | assert(ctx); 267 | DEBUG_MSG("thread %d locking ctx\n",thread->thread_num); 268 | LOCK_MUTEX(&ctx->mutex); 269 | DEBUG_MSG("thread %d got lock\n",thread->thread_num); 270 | assert(ctx->queue); 271 | 272 | /* for each queued job item while keep_running 273 | serach for a job and break out if we find one */ 274 | for(i = 0; thread->keep_running && i < ctx->queue_size; i++) { 275 | 276 | /* if queue pointer not null there is a job in this slot */ 277 | if (ctx->queue[i]) { 278 | 279 | DEBUG_MSG("job %d set wait=%u.%03lu start_time=%u.%03lu now=%u.%03lu\n", ctx->queue[i]->job_id, 280 | (unsigned int) TIME_SECP(wait_time), TIME_MSECP(wait_time), 281 | (unsigned int) TIME_SEC(ctx->queue[i]->start_time), TIME_MSEC(ctx->queue[i]->start_time), 282 | (unsigned int) TIME_SEC(now), TIME_MSEC(now)); 283 | 284 | /* check scheduled time */ 285 | if (_time_gt(&now, &ctx->queue[i]->start_time)) { 286 | /* job found that must start now */ 287 | job = ctx->queue[i]; 288 | ctx->queue[i] = NULL; 289 | DEBUG_MSG("found job %d\n", job->job_id); 290 | ctx->waiting_jobs--; 291 | break; /* found job ready to run */ 292 | } else if (_time_gt(wait_time, &ctx->queue[i]->start_time)) { 293 | /* next job in the queue is not scheduled to be run yet */ 294 | 295 | /* calculate time thread should sleep for */ 296 | *wait_time = ctx->queue[i]->start_time; 297 | *wait_ms = time_diff_ms(&ctx->queue[i]->start_time, &now); 298 | DEBUG_MSG("waiting %lld ms\n", *wait_ms); 299 | DEBUG_MSG("set wait to %u.%03lu for job %d\n", 300 | (unsigned int) TIME_SECP(wait_time), TIME_MSECP(wait_time), ctx->queue[i]->job_id); 301 | } else { 302 | DEBUG_MSG("no other job\n", NULL); 303 | } 304 | } 305 | } 306 | 307 | 308 | DEBUG_MSG("thread %d unlocking ctx job=%p wait=%u.%03lu\n", 309 | thread->thread_num, job, 310 | (unsigned int) TIME_SECP(wait_time), TIME_MSECP(wait_time)); 311 | 312 | UNLOCK_MUTEX(&ctx->mutex); 313 | return job; 314 | } 315 | 316 | // return number of jobs waiting in queue 317 | int workqueue_get_queue_len(struct workqueue_ctx* ctx) 318 | { 319 | int ret; 320 | LOCK_MUTEX(&ctx->mutex); 321 | ret = ctx->waiting_jobs; 322 | UNLOCK_MUTEX(&ctx->mutex); 323 | return ret; 324 | } 325 | 326 | static void * _workqueue_job_scheduler(void *data) 327 | { 328 | struct workqueue_thread *thread = (struct workqueue_thread *) data; 329 | struct workqueue_ctx *ctx; 330 | struct TIME_STRUCT_TYPE wait_time; 331 | int ret; 332 | long long wait_ms = 1000; 333 | 334 | DEBUG_MSG("starting data=%p\n", data); 335 | assert(thread); 336 | ctx = thread->ctx; 337 | DEBUG_MSG("thread %d starting\n",thread->thread_num); 338 | 339 | if (ctx->ops && ctx->ops->worker_constructor) { 340 | DEBUG_MSG("thread %d calling constructor\n",thread->thread_num); 341 | ctx->ops->worker_constructor(ctx->ops->data); 342 | } 343 | LOCK_MUTEX(&thread->mutex); 344 | 345 | while (thread->keep_running) { 346 | 347 | DEBUG_MSG("thread %d looking for work \n",thread->thread_num); 348 | thread->job = _workqueue_get_job(thread, &wait_time, &wait_ms); 349 | 350 | /* is there a job that needs to be run now */ 351 | if (thread->job) { 352 | /* there is work to do */ 353 | DEBUG_MSG("launching job %d\n",thread->job->job_id); 354 | 355 | /* keep job_mutex locked while running to test if running */ 356 | LOCK_MUTEX(&thread->job_mutex); 357 | /* mantain unlocked while running so we can check state. 358 | in workqueue_job_running() */ 359 | UNLOCK_MUTEX(&thread->mutex); 360 | 361 | /* launch worker job */ 362 | thread->job->func(thread->job->data); 363 | 364 | DEBUG_MSG("job %d finished\n", thread->job->job_id); 365 | /* done with job free it */ 366 | free(thread->job); 367 | thread->job = NULL; 368 | 369 | UNLOCK_MUTEX(&thread->job_mutex); 370 | LOCK_MUTEX(&thread->mutex); 371 | 372 | } else { 373 | /* wait until we are signaled that there is new work, or until the wait time is up */ 374 | 375 | 376 | /* we should idle */ 377 | 378 | UNLOCK_MUTEX(&thread->mutex); 379 | 380 | #ifdef WINDOWS 381 | DEBUG_MSG("thread %d going idle\n",thread->thread_num); 382 | ret = WaitForSingleObject(ctx->work_ready_cond, (DWORD) wait_ms); 383 | 384 | #else 385 | DEBUG_MSG("thread %d going idle. %d sec; %ld nsec\n", 386 | thread->thread_num, (int) wait_time.tv_sec, wait_time.tv_nsec); 387 | // note this wait may be a long time, if the system time changes 388 | LOCK_MUTEX(&ctx->cond_mutex); 389 | ret = pthread_cond_timedwait(&ctx->work_ready_cond, &ctx->cond_mutex, &wait_time); 390 | UNLOCK_MUTEX(&ctx->cond_mutex); 391 | #endif 392 | 393 | LOCK_MUTEX(&thread->mutex); 394 | 395 | if (!thread->keep_running) { 396 | DEBUG_MSG("thread %d stopping\n",thread->thread_num); 397 | break; 398 | } 399 | #ifdef WINDOWS 400 | /* check windows error cases*/ 401 | if( !ret && WAIT_TIMEOUT == GetLastError()) { 402 | DEBUG_MSG("thread %d idle timeout\n",thread->thread_num); 403 | continue; /* wait again */ 404 | } if (!ret) { 405 | // other error 406 | } 407 | #else 408 | 409 | if (ret == ETIMEDOUT) { 410 | DEBUG_MSG("thread %d idle timeout lock\n",thread->thread_num); 411 | continue; /* wait again */ 412 | } else if (ret == EINVAL) { 413 | ERROR_MSG("thread %d pthread_cond_timedwait EINVAL\n", thread->thread_num); 414 | usleep(wait_ms); // wait 1000th of time wait 415 | } else if (ret) { 416 | ERROR_MSG("thread %d pthread_cond_timedwait ret =%d\n", thread->thread_num, ret); 417 | } 418 | 419 | #endif 420 | } 421 | } 422 | 423 | UNLOCK_MUTEX(&thread->mutex); 424 | 425 | if (ctx->ops && ctx->ops->worker_destructor) { 426 | DEBUG_MSG("thread %d calling destructor\n",thread->thread_num); 427 | ctx->ops->worker_destructor(ctx->ops->data); 428 | } 429 | return NULL; 430 | } 431 | 432 | static int _empty_queue(struct workqueue_ctx *ctx) 433 | { 434 | int count = 0; 435 | int i; 436 | /* free any remaining jobs left in queue */ 437 | if(ctx->queue) { 438 | for (i = 0; i < ctx->queue_size; i++) { 439 | if (ctx->queue[i]) { 440 | free(ctx->queue[i]); 441 | ctx->queue[i] = NULL; 442 | count++; 443 | } 444 | } 445 | } 446 | return count; 447 | } 448 | 449 | void workqueue_destroy(struct workqueue_ctx *ctx) 450 | { 451 | int i; 452 | 453 | DEBUG_MSG("shutting down ctx=%p\n", ctx); 454 | LOCK_MUTEX(&ctx->mutex); 455 | if (ctx->thread) { 456 | DEBUG_MSG("shutting down %d workers\n", ctx->num_worker_threads); 457 | for (i = 0; i < ctx->num_worker_threads; i++) { 458 | if (ctx->thread[i]) { 459 | ctx->thread[i]->keep_running = false; 460 | } 461 | } 462 | 463 | #ifdef WINDOWS 464 | SetEvent(&ctx->work_ready_cond); 465 | #else 466 | /* send signal to unblock threads */ 467 | pthread_cond_broadcast(&ctx->work_ready_cond); 468 | 469 | #endif 470 | /* Unlock incase the worker callback is makeing its own calls to workqueue_* to avoid deadlock */ 471 | UNLOCK_MUTEX(&ctx->mutex); 472 | for (i = 0; i < ctx->num_worker_threads; i++) { 473 | if (ctx->thread[i]) { 474 | 475 | DEBUG_MSG("joining thread %d\n",ctx->thread[i]->thread_num); 476 | pthread_join(ctx->thread[i]->thread_id, NULL); 477 | 478 | } 479 | } 480 | LOCK_MUTEX(&ctx->mutex); 481 | 482 | /* for each worker thread, clean up it's context */ 483 | for (i = 0; i < ctx->num_worker_threads; i++) { 484 | if (ctx->thread[i]) { 485 | free(ctx->thread[i]); 486 | ctx->thread[i] = NULL; 487 | } 488 | } 489 | free(ctx->thread); /* free pointer list */ 490 | } 491 | 492 | 493 | _empty_queue(ctx); 494 | free(ctx->queue); 495 | ctx->queue = NULL; 496 | 497 | UNLOCK_MUTEX(&ctx->mutex); 498 | 499 | #ifdef WINDOWS 500 | //FIXME test this 501 | #else 502 | pthread_mutex_destroy(&ctx->mutex); 503 | pthread_mutex_destroy(&ctx->cond_mutex); 504 | #endif 505 | 506 | free(ctx); 507 | 508 | } 509 | 510 | static struct workqueue_ctx * 511 | __workqueue_init(struct workqueue_ctx *ctx, unsigned int queue_size, unsigned int num_worker_threads) 512 | { 513 | unsigned int i; 514 | struct workqueue_thread *thread; 515 | int ret = 0; 516 | 517 | if (!ctx) 518 | return NULL; 519 | ctx->queue_size = queue_size; 520 | #ifdef WINDOWS 521 | InitializeCriticalSection(&ctx->mutex); 522 | InitializeCriticalSection(&ctx->cond_mutex); 523 | #else 524 | ret = pthread_mutex_init(&ctx->mutex, NULL); 525 | if (ret) 526 | ERROR_MSG("pthread_mutex_init failed ret=%d\n", ret); 527 | 528 | ret = pthread_mutex_init(&ctx->cond_mutex, NULL); 529 | if (ret) 530 | ERROR_MSG("pthread_mutex_init failed ret=%d\n", ret); 531 | 532 | #endif 533 | /* Allocate pointers for queue */ 534 | ctx->queue = (struct workqueue_job **) calloc( queue_size + 1, sizeof(struct workqueue_job *)); 535 | if (!ctx->queue) { 536 | goto free_ctx; 537 | } 538 | 539 | /* Allocate pointers for threads */ 540 | ctx->thread = (struct workqueue_thread **) calloc( num_worker_threads + 1, sizeof(struct workqueue_thread *)); 541 | if (!ctx->thread) 542 | goto free_queue; 543 | 544 | #ifdef WINDOWS 545 | // Condition variable only work on vista and newer 546 | // InitializeConditionVariable(&ctx->work_ready_cond); 547 | 548 | ctx->work_ready_cond = CreateEvent (NULL, // no security 549 | FALSE, // auto-reset event 550 | FALSE, // non-signaled initially 551 | NULL); // unnamed 552 | 553 | 554 | #else 555 | ret = pthread_cond_init(&ctx->work_ready_cond, NULL); 556 | if (ret) 557 | ERROR_MSG("pthread_cond_init failed ret=%d\n", ret); 558 | #endif 559 | ctx->num_worker_threads = num_worker_threads; 560 | 561 | for (i = 0; i < num_worker_threads; i++) { 562 | ctx->thread[i] = thread = (struct workqueue_thread *) calloc ( 1, sizeof(struct workqueue_thread)); 563 | if (!ctx->thread[i]) { 564 | goto free_threads; 565 | } 566 | thread->thread_num = i; 567 | thread->ctx = ctx; /* point to parent */ 568 | thread->keep_running = true; 569 | #ifdef WINDOWS 570 | InitializeCriticalSection(&thread->mutex); 571 | InitializeCriticalSection(&thread->job_mutex); 572 | 573 | thread->thread_id = CreateThread( 574 | NULL, // default security attributes 575 | 0, // default stack size 576 | (LPTHREAD_START_ROUTINE) _workqueue_job_scheduler, 577 | thread, // data passed to thread 578 | 0, // default creation flags 579 | NULL); // receive thread identifier 580 | 581 | #else 582 | pthread_mutex_init(&thread->mutex, NULL); 583 | if (ret) 584 | ERROR_MSG("pthread_mutex_init failed ret=%d\n", ret); 585 | 586 | ret = pthread_create(&thread->thread_id, NULL, _workqueue_job_scheduler, thread); 587 | 588 | if (ret) 589 | ERROR_MSG("pthread_create failed ret=%d\n", ret); 590 | 591 | #endif 592 | } 593 | 594 | return ctx; 595 | 596 | /* error cases to clean up for*/ 597 | free_threads: 598 | 599 | for (i = 0; i < num_worker_threads; i++) { 600 | if (ctx->thread[i]) { 601 | free(ctx->thread[i]); 602 | } 603 | } 604 | 605 | free_queue: 606 | free(ctx->queue); 607 | 608 | free_ctx: 609 | free(ctx); 610 | fprintf(stderr, "Error initializing\n"); 611 | return NULL; 612 | } 613 | 614 | struct workqueue_ctx * workqueue_init(unsigned int queue_size, 615 | unsigned int num_worker_threads, struct worker_thread_ops *ops) 616 | { 617 | struct workqueue_ctx *ctx; 618 | 619 | DEBUG_MSG("Starting queue_size=%d\n", queue_size); 620 | 621 | /* check for invalid args */ 622 | if (!queue_size || !num_worker_threads) 623 | return NULL; 624 | 625 | ctx = (struct workqueue_ctx *) calloc(1, sizeof (struct workqueue_ctx)); 626 | ctx->ops = ops; 627 | return __workqueue_init(ctx, queue_size, num_worker_threads); 628 | } 629 | 630 | #if 0 631 | 632 | struct workqueue_ctx * workqueue_init_pth_wapper(unsigned int queue_size, unsigned int num_worker_threads, 633 | int (*pthread_create_wrapper)(pthread_t *, const pthread_attr_t *, 634 | void *(*)(void *), void *)) 635 | { 636 | struct workqueue_ctx *ctx; 637 | 638 | DEBUG_MSG("Starting queue_size=%d\n", queue_size); 639 | 640 | /* check for invalid args */ 641 | if (!queue_size || !num_worker_threads) 642 | return NULL; 643 | 644 | ctx = (struct workqueue_ctx *) calloc(1, sizeof (struct workqueue_ctx)); 645 | 646 | DEBUG_MSG("Set wrapper=%p\n", pthread_create_wrapper); 647 | ctx->pthread_create_wrapper = pthread_create_wrapper; 648 | 649 | return __workqueue_init(ctx, queue_size, num_worker_threads); 650 | } 651 | 652 | #endif 653 | 654 | int workqueue_add_work(struct workqueue_ctx* ctx, int priority, 655 | unsigned int miliseconds, 656 | workqueue_func_t callback_fn, void *data) 657 | { 658 | int i; 659 | int ret; 660 | struct workqueue_job *job = NULL; 661 | struct TIME_STRUCT_TYPE sched_time; 662 | 663 | /* get current time time*/ 664 | GET_TIME(sched_time); 665 | 666 | LOCK_MUTEX(&ctx->mutex); 667 | 668 | for (i = 0; i < ctx->queue_size; i++) { 669 | if (ctx->queue[i]) 670 | continue; /* used location */ 671 | 672 | /* found free spot in queue to put job, so allocate memory for it. */ 673 | job = (struct workqueue_job *) calloc(1, sizeof(struct workqueue_job)); 674 | if (!job) { 675 | UNLOCK_MUTEX(&ctx->mutex); 676 | return -ENOMEM; 677 | } 678 | if (miliseconds) { 679 | /* get current time time*/ 680 | GET_TIME(job->start_time); 681 | /* add time */ 682 | #ifdef WINDOWS 683 | job->start_time.time += miliseconds / 1000; 684 | job->start_time.millitm += miliseconds % 1000; 685 | // if milili sec overflow carry over to a second. 686 | if (job->start_time.millitm > 1000) { 687 | job->start_time.millitm -= 1000; 688 | job->start_time.time += 1; 689 | } 690 | #else 691 | job->start_time.tv_sec += miliseconds / 1000; 692 | job->start_time.tv_nsec += (miliseconds % 1000) * 1000000; 693 | // if nano sec overflow carry over to a second. 694 | if (job->start_time.tv_nsec > 1000000000) { 695 | job->start_time.tv_nsec -= 1000000000; 696 | job->start_time.tv_sec += 1; 697 | } 698 | DEBUG_MSG("Start time sec=%d nsec=%ld\n", 699 | (int) job->start_time.tv_sec, job->start_time.tv_nsec); 700 | #endif 701 | } /* else the start_time will be 0, so start ASAP */ 702 | 703 | job->priority = priority; 704 | job->data = data; 705 | job->func = callback_fn; 706 | ret = job->job_id = ctx->job_count++; 707 | if (ctx->job_count < 0) /* overflow case */ 708 | ctx->job_count = 0; 709 | ctx->queue[i] = job; 710 | ctx->waiting_jobs++; 711 | 712 | DEBUG_MSG("Adding job %p to q %p id=%d pri=%d waiting=%d cb=%p data=%p\n", 713 | job, ctx->queue[i], job->job_id, job->priority, 714 | ctx->waiting_jobs, job->func, job->data ); 715 | 716 | qsort(ctx->queue, ctx->queue_size, 717 | sizeof(struct workqueue_job *), /* size of pointer to sort */ 718 | job_compare); 719 | #ifdef WINDOWS 720 | //WakeConditionVariable(&ctx->work_ready_cond); 721 | PulseEvent(ctx->work_ready_cond); 722 | #else 723 | if (pthread_cond_signal(&ctx->work_ready_cond)) { 724 | ERROR_MSG("invalid condition\n"); 725 | } 726 | #endif 727 | 728 | DEBUG_MSG("unlock mutex\n", NULL); 729 | UNLOCK_MUTEX(&ctx->mutex); 730 | return ret; 731 | } 732 | 733 | /* queues are full */ 734 | DEBUG_MSG("Queues are full\n", NULL); 735 | 736 | UNLOCK_MUTEX(&ctx->mutex); 737 | /* no room in queue */ 738 | return -EBUSY; 739 | } 740 | 741 | int workqueue_show_status(struct workqueue_ctx* ctx, FILE *fp) 742 | { 743 | int i; 744 | long long time_ms; 745 | struct TIME_STRUCT_TYPE now_time; 746 | GET_TIME(now_time); 747 | 748 | LOCK_MUTEX(&ctx->mutex); 749 | fprintf(fp, "Number of worker threads=%d \n", ctx->num_worker_threads); 750 | fprintf(fp, "Total jobs added=%d queue_size=%d waiting_jobs=%d \n", ctx->job_count, ctx->queue_size, ctx->waiting_jobs); 751 | fprintf(fp, "\n"); 752 | fprintf(fp, "%3s | %8s | %4s | %6s ms\n", "Qi", "JobID", "Pri", "Time" ); 753 | fprintf(fp, "---------------------------------\n"); 754 | for (i = 0; i < ctx->queue_size; i++) { 755 | if (!ctx->queue[i]) 756 | continue; /* unused location */ 757 | 758 | if (TIME_SEC(ctx->queue[i]->start_time) || 759 | TIME_MSEC(ctx->queue[i]->start_time)) { 760 | // has been scheduled for a time in the future. 761 | time_ms = time_diff_ms(&ctx->queue[i]->start_time, &now_time); 762 | } else { 763 | // will run ASAP 764 | time_ms = 0; 765 | } 766 | 767 | fprintf(fp,"%3d | %8d | %4d | %6lld ms\n", i, 768 | ctx->queue[i]->job_id, 769 | ctx->queue[i]->priority, time_ms); 770 | } 771 | 772 | UNLOCK_MUTEX(&ctx->mutex); 773 | 774 | fflush(fp); 775 | return 0; 776 | } 777 | 778 | static int _is_job_queued(struct workqueue_ctx* ctx, int job_id) 779 | { 780 | int i; 781 | 782 | if(ctx->queue) { 783 | for (i = 0; i < ctx->queue_size; i++) { 784 | if (ctx->queue[i] && ctx->queue[i]->job_id == job_id) 785 | return 1; 786 | } 787 | } 788 | return 0; 789 | } 790 | 791 | static int _is_job_running(struct workqueue_ctx* ctx, int job_id) 792 | { 793 | int i; 794 | int ret = 0; 795 | int rc; 796 | for (i = 0; i < ctx->num_worker_threads && !ret; i++) { 797 | if (ctx->thread[i]) { 798 | TRY_LOCK_MUTEX(&ctx->thread[i]->mutex, rc); 799 | #ifdef WINDOWS 800 | if (rc) 801 | return -EBUSY; 802 | #else 803 | if (rc == EBUSY) 804 | return -EBUSY; 805 | #endif 806 | if (ctx->thread[i]->job && ctx->thread[i]->job->job_id == job_id) { 807 | ret = 1; 808 | } 809 | UNLOCK_MUTEX(&ctx->thread[i]->mutex); 810 | } 811 | } 812 | 813 | return ret; 814 | } 815 | 816 | int workqueue_job_queued(struct workqueue_ctx* ctx, int job_id) 817 | { 818 | int ret; 819 | 820 | if (!ctx) 821 | return -1; 822 | 823 | LOCK_MUTEX(&ctx->mutex); 824 | ret = _is_job_queued(ctx, job_id); 825 | UNLOCK_MUTEX(&ctx->mutex); 826 | return ret; 827 | } 828 | 829 | int workqueue_job_running(struct workqueue_ctx* ctx, int job_id) 830 | { 831 | int ret = 0; 832 | 833 | if (!ctx) 834 | return -1; 835 | 836 | 837 | do { 838 | LOCK_MUTEX(&ctx->mutex); 839 | ret = _is_job_running(ctx, job_id); 840 | 841 | UNLOCK_MUTEX(&ctx->mutex); 842 | } while (ret == -EBUSY); 843 | 844 | 845 | return ret; 846 | } 847 | 848 | int workqueue_job_queued_or_running(struct workqueue_ctx* ctx, int job_id) 849 | { 850 | int ret; 851 | 852 | if (!ctx) 853 | return -1; 854 | 855 | LOCK_MUTEX(&ctx->mutex); 856 | ret = _is_job_queued(ctx, job_id); 857 | UNLOCK_MUTEX(&ctx->mutex); 858 | 859 | if (!ret) { 860 | do { 861 | LOCK_MUTEX(&ctx->mutex); 862 | ret = _is_job_running(ctx, job_id); 863 | 864 | UNLOCK_MUTEX(&ctx->mutex); 865 | } while (ret == -EBUSY); 866 | } 867 | 868 | 869 | 870 | return ret; 871 | } 872 | 873 | /* private function. NOTE ctx must be locked by caller to avoid race with other dequeue*/ 874 | static int _dequeue(struct workqueue_ctx* ctx, int job_id) 875 | { 876 | int i; 877 | 878 | if(ctx->queue) { 879 | for (i = 0; i < ctx->queue_size; i++) { 880 | if (ctx->queue[i] && ctx->queue[i]->job_id == job_id) { 881 | free(ctx->queue[i]); 882 | ctx->queue[i] = NULL; 883 | ctx->waiting_jobs--; 884 | return 0; 885 | } 886 | } 887 | } 888 | return -ENOENT; 889 | } 890 | 891 | #if 0 /* This probally can't be reliably done. At best we could send a signal */ 892 | static int _kill_job(struct workqueue_ctx* ctx, int job_id) 893 | { 894 | int i; 895 | int ret = -ENOENT; 896 | 897 | for (i = 0; i < ctx->num_worker_threads; i++) { 898 | if (ctx->thread[i]) { 899 | LOCK_MUTEX(&ctx->thread[i]->mutex); 900 | if (ctx->thread[i]->job && ctx->thread[i]->job->job_id == job_id) { 901 | /* FOUND*/ 902 | #ifdef WINDOWS 903 | TerminateThread(thread->thread_id, 0); 904 | 905 | thread->thread_id = CreateThread( 906 | NULL, // default security attributes 907 | 0, // default stack size 908 | (LPTHREAD_START_ROUTINE) _workqueue_job_scheduler, 909 | thread, // data passed to thread 910 | 0, // default creation flags 911 | NULL); // receive thread identifier 912 | 913 | #else /*POSIX */ 914 | if ( (ret = pthread_kill(ctx->thread[i]->thread_id , SIGTERM)) ) 915 | ERROR_MSG("pthread_kill err = %d\n,", ret); 916 | 917 | /* recreate worker thread */ 918 | pthread_create(&ctx->thread[i]->thread_id, NULL, 919 | _workqueue_job_scheduler, ctx->thread[i]); 920 | #endif 921 | 922 | UNLOCK_MUTEX(&ctx->thread[i]->mutex); 923 | return 0; 924 | } 925 | UNLOCK_MUTEX(&ctx->thread[i]->mutex); 926 | } 927 | } 928 | 929 | 930 | return -ENOENT; 931 | } 932 | 933 | int workqueue_kill(struct workqueue_ctx* ctx, int job_id) 934 | { 935 | int ret; 936 | LOCK_MUTEX(&ctx->mutex); 937 | 938 | ret = _kill_job(ctx, job_id); 939 | 940 | UNLOCK_MUTEX(&ctx->mutex); 941 | return ret; 942 | } 943 | 944 | int workqueue_cancel(struct workqueue_ctx* ctx, int job_id) 945 | { 946 | 947 | int ret; 948 | LOCK_MUTEX(&ctx->mutex); 949 | ret = _dequeue(ctx, job_id); 950 | 951 | if (ret == -ENOENT) { 952 | /* kill any running thread that has this job id */ 953 | ret = _kill_job(ctx, job_id); 954 | } 955 | UNLOCK_MUTEX(&ctx->mutex); 956 | return ret; 957 | } 958 | #endif 959 | 960 | int workqueue_dequeue(struct workqueue_ctx* ctx, int job_id) 961 | { 962 | int ret; 963 | LOCK_MUTEX(&ctx->mutex); 964 | ret = _dequeue(ctx, job_id); 965 | 966 | UNLOCK_MUTEX(&ctx->mutex); 967 | return ret; 968 | } 969 | 970 | 971 | int workqueue_empty(struct workqueue_ctx *ctx) 972 | { 973 | int count; 974 | LOCK_MUTEX(&ctx->mutex); 975 | 976 | count = _empty_queue(ctx); 977 | 978 | UNLOCK_MUTEX(&ctx->mutex); 979 | return count; 980 | } 981 | 982 | int workqueue_empty_wait(struct workqueue_ctx *ctx) 983 | { 984 | int count; 985 | int i; 986 | int num_workers = ctx->num_worker_threads; 987 | 988 | LOCK_MUTEX(&ctx->mutex); 989 | count = _empty_queue(ctx); 990 | num_workers = ctx->num_worker_threads; 991 | UNLOCK_MUTEX(&ctx->mutex); 992 | 993 | 994 | 995 | for (i = 0; i < num_workers; i++) { 996 | if (ctx->thread[i]) { 997 | 998 | LOCK_MUTEX(&ctx->thread[i]->mutex); 999 | LOCK_MUTEX(&ctx->thread[i]->job_mutex); 1000 | if (ctx->thread[i]->job) { 1001 | ERROR_MSG("no job should be running\n"); 1002 | } 1003 | UNLOCK_MUTEX(&ctx->thread[i]->job_mutex); 1004 | UNLOCK_MUTEX(&ctx->thread[i]->mutex); 1005 | 1006 | } 1007 | } 1008 | 1009 | 1010 | 1011 | 1012 | return count; 1013 | } -------------------------------------------------------------------------------- /lib/workqueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file workqueue.h 3 | * @brief public include header for priority work queues.. 4 | * @author Karl Hiramoto 5 | * 6 | * Distributed under LGPL see COPYING.LGPL 7 | * Copyright 2009 Karl Hiramoto 8 | */ 9 | 10 | #ifndef WORKQUEUE_H 11 | #define WORKQUEUE_H 1 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | 18 | #include 19 | 20 | /* forward declaration for struct workqueue_ctx*/ 21 | struct workqueue_ctx; 22 | 23 | /** callback function format for each work task */ 24 | typedef void (*workqueue_func_t)(void *data); 25 | 26 | struct worker_thread_ops 27 | { 28 | /** 29 | * Optional callback to init/allocate any private data. 30 | * This is called once on initialization of each worker thread 31 | */ 32 | void (*worker_constructor)(void *data); 33 | 34 | /** 35 | * Optional callback to free/cleanup any private data, allocated by 36 | * worker_create this will be called before the worker thread exits 37 | * this is only called when workqueue_destroy() is called 38 | */ 39 | void (*worker_destructor)(void *data); 40 | 41 | /** optional data that may be passed to constructor/destructor */ 42 | void *data; 43 | }; 44 | 45 | /** 46 | * @fn struct workqueue_ctx* workqueue_init(unsigned int queue_size, unsigned int num_worker_threads); 47 | * @brief Initialize work context 48 | * @param queue_size size of queue. Maximum number of jobs you can queue. 49 | * @param num_worker_threads Number of threads to do the work. 50 | * @param worker_thread_ops optional callbacks to initialize and cleanup worker threads 51 | * if this is NULL, no special init/cleanup is done. 52 | * @returns pointer to context data. This data is private to the library and may not be used externally. Free the context with workqueue_destroy 53 | */ 54 | 55 | struct workqueue_ctx * workqueue_init(unsigned int queue_size, unsigned int num_worker_threads, 56 | struct worker_thread_ops *ops); 57 | 58 | /** 59 | * @fn workqueue_add_work 60 | * @brief Enqueue work 61 | * @param workqueue_ctx context 62 | * @param priority 0 is highest. 63 | * @param when_milisec milliseconds in the future to schedule. 0 is now. 64 | * @param callback_fn function pointer for callback 65 | * @param data data to pass to work callback function. 66 | * @returns positive Job ID or negative -errno; -EBUSY when queues are full 67 | */ 68 | int workqueue_add_work(struct workqueue_ctx* ctx, 69 | int priority, unsigned int when_milisec, 70 | workqueue_func_t callback_fn, void *data); 71 | 72 | /** 73 | * @fn workqueue_show_status 74 | * @brief Print out status, usefull for debug 75 | * @param workqueue_ctx context 76 | * @param fp file pointer of where to print may be stdout or stderr, or file if you want. 77 | * @returns 0 for OK or -errno 78 | */ 79 | int workqueue_show_status(struct workqueue_ctx* ctx, FILE *fp); 80 | 81 | /** 82 | * @fn workqueue_get_queue_len 83 | * @brief Get the current queue length 84 | * @param workqueue_ctx context 85 | * @returns Number of jobs currently waiting in queue. 86 | * Does not count job if it's currently execuing. 87 | */ 88 | int workqueue_get_queue_len(struct workqueue_ctx* ctx); 89 | 90 | /** 91 | * @fn workqueue_job_queued 92 | * @brief Check if job is currently queued 93 | * @param workqueue_ctx context 94 | * @returns 1 if Job is queued. 0 if not queued. or -error number. 95 | */ 96 | int workqueue_job_queued(struct workqueue_ctx* ctx, int job_id); 97 | 98 | /** 99 | * @fn workqueue_job_running 100 | * @brief Check if job is running 101 | * @param workqueue_ctx context 102 | * @returns 1 if Job is running. 0 if not running. or -error number. 103 | */ 104 | int workqueue_job_running(struct workqueue_ctx* ctx, int job_id); 105 | 106 | /** 107 | * @fn workqueue_job_queued_or_running 108 | * @brief Check if job is queued or running 109 | * @param workqueue_ctx context 110 | * @returns 1 if Job is running or in queue. 0 if not running or in queue. or -error number. 111 | */ 112 | 113 | int workqueue_job_queued_or_running(struct workqueue_ctx* ctx, int job_id); 114 | 115 | 116 | /** 117 | * @fn workqueue_dequeue 118 | * @brief If this job in queued but not yet running, dequeue it. cancel the work. 119 | * @param workqueue_ctx context 120 | * @param job_id ID returned from workqueue_add_work 121 | * @returns 0 for OK or -error number. 122 | */ 123 | int workqueue_dequeue(struct workqueue_ctx* ctx, int job_id); 124 | 125 | /** 126 | * @fn workqueue_destroy 127 | * @brief free context, releases all memory. Any jobs in queue are dequed. 128 | * @brief Will wait for any currently running jobs to finish. 129 | * @param workqueue_ctx context to free 130 | * @returns void 131 | */ 132 | void workqueue_destroy(struct workqueue_ctx *ctx); 133 | 134 | /** 135 | * @fn workqueue_empty_wait 136 | * @brief Empty and reset the queue. Cancel all queued work 137 | * @param workqueue_ctx context to free 138 | * @returns number of entries removed or -errno 139 | */ 140 | int workqueue_empty(struct workqueue_ctx *ctx); 141 | 142 | /** 143 | * @fn workqueue_empty_wait 144 | * @brief Empty and reset the queue 145 | * @brief Will wait for any currently running jobs to finish. 146 | * @param workqueue_ctx context to free 147 | * @returns number of entries removed or -errno 148 | */ 149 | int workqueue_empty_wait(struct workqueue_ctx *ctx); 150 | 151 | 152 | /** 153 | * @fn workqueue_init 154 | * @brief to be used instead of workqueue_init, to be used to install a pthread_create wrapper 155 | * @returns number of entries removed or -errno 156 | */ 157 | 158 | 159 | #ifdef __cplusplus 160 | } 161 | 162 | /* C++ wrapper of C functions */ 163 | class work_queue_class 164 | { 165 | private: 166 | struct workqueue_ctx *ctx; 167 | public: 168 | work_queue_class(unsigned int queue_size, unsigned int num_worker_threads) { 169 | ctx = workqueue_init(queue_size, num_worker_threads, NULL); 170 | } 171 | 172 | ~work_queue_class(void) { 173 | workqueue_destroy(ctx); 174 | } 175 | 176 | int dequeue(int job_id) { 177 | return workqueue_dequeue(ctx, job_id); 178 | } 179 | 180 | int add_work(int priority, unsigned int when_milisec, 181 | workqueue_func_t callback_fn, void *data) { 182 | 183 | return workqueue_add_work(ctx, 184 | priority, when_milisec, callback_fn, data); 185 | } 186 | 187 | int show_status(FILE *fp) { 188 | return workqueue_show_status(ctx, fp); 189 | } 190 | 191 | int get_queue_len(void) { 192 | return workqueue_get_queue_len(ctx); 193 | } 194 | 195 | int job_queued(int job_id) { 196 | return workqueue_job_queued(ctx, job_id); 197 | } 198 | 199 | int job_running(int job_id) { 200 | return workqueue_job_running(ctx, job_id); 201 | } 202 | 203 | int job_queued_or_running(int job_id) { 204 | return workqueue_job_queued_or_running(ctx, job_id); 205 | } 206 | 207 | int empty(void) { 208 | return workqueue_empty(ctx); 209 | } 210 | 211 | int empty_wait(void) { 212 | return workqueue_empty_wait(ctx); 213 | } 214 | }; 215 | 216 | #endif /*cplusplus*/ 217 | 218 | #endif /*WORKQUEUE_H */ 219 | -------------------------------------------------------------------------------- /libworkqueue.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libworkqueue", "libworkqueue.vcproj", "{B6A500A3-DDAC-4053-991E-0089687DC316}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simple_test", "examples\simple_test\simple_test.vcproj", "{B4F1A7E8-4E8A-4D6E-A0C8-ECFBA2633214}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "periodic_test", "examples\periodic_test\periodic_test.vcproj", "{E0578D3F-4904-45AF-B1DA-91683EF9F4C2}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "high_load_test", "examples\high_load_test\high_load_test.vcproj", "{19975A23-03E1-4EA4-9A9F-A0B7D645C3B5}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Win32 = Debug|Win32 15 | Release|Win32 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {B6A500A3-DDAC-4053-991E-0089687DC316}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {B6A500A3-DDAC-4053-991E-0089687DC316}.Debug|Win32.Build.0 = Debug|Win32 20 | {B6A500A3-DDAC-4053-991E-0089687DC316}.Release|Win32.ActiveCfg = Release|Win32 21 | {B6A500A3-DDAC-4053-991E-0089687DC316}.Release|Win32.Build.0 = Release|Win32 22 | {B4F1A7E8-4E8A-4D6E-A0C8-ECFBA2633214}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {B4F1A7E8-4E8A-4D6E-A0C8-ECFBA2633214}.Debug|Win32.Build.0 = Debug|Win32 24 | {B4F1A7E8-4E8A-4D6E-A0C8-ECFBA2633214}.Release|Win32.ActiveCfg = Release|Win32 25 | {B4F1A7E8-4E8A-4D6E-A0C8-ECFBA2633214}.Release|Win32.Build.0 = Release|Win32 26 | {E0578D3F-4904-45AF-B1DA-91683EF9F4C2}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {E0578D3F-4904-45AF-B1DA-91683EF9F4C2}.Debug|Win32.Build.0 = Debug|Win32 28 | {E0578D3F-4904-45AF-B1DA-91683EF9F4C2}.Release|Win32.ActiveCfg = Release|Win32 29 | {E0578D3F-4904-45AF-B1DA-91683EF9F4C2}.Release|Win32.Build.0 = Release|Win32 30 | {19975A23-03E1-4EA4-9A9F-A0B7D645C3B5}.Debug|Win32.ActiveCfg = Debug|Win32 31 | {19975A23-03E1-4EA4-9A9F-A0B7D645C3B5}.Debug|Win32.Build.0 = Debug|Win32 32 | {19975A23-03E1-4EA4-9A9F-A0B7D645C3B5}.Release|Win32.ActiveCfg = Release|Win32 33 | {19975A23-03E1-4EA4-9A9F-A0B7D645C3B5}.Release|Win32.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /libworkqueue.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/karlhiramoto/libworkqueue/7ec2a7099b25a841beb05e1b5abaca922932e3bd/libworkqueue.suo -------------------------------------------------------------------------------- /libworkqueue.vcproj: -------------------------------------------------------------------------------- 1 |  2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 24 | 27 | 30 | 33 | 36 | 39 | 53 | 56 | 59 | 62 | 65 | 68 | 71 | 74 | 77 | 80 | 81 | 87 | 90 | 93 | 96 | 99 | 102 | 111 | 114 | 117 | 120 | 123 | 126 | 129 | 132 | 135 | 138 | 139 | 140 | 141 | 142 | 143 | 148 | 151 | 152 | 153 | 158 | 159 | 164 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | libtool.m4 2 | lt~obsolete.m4 3 | ltoptions.m4 4 | ltsugar.m4 5 | ltversion.m4 6 | -------------------------------------------------------------------------------- /m4/ax_prog_doxygen.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.nongnu.org/autoconf-archive/ax_prog_doxygen.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # DX_INIT_DOXYGEN(PROJECT-NAME, DOXYFILE-PATH, [OUTPUT-DIR]) 8 | # DX_DOXYGEN_FEATURE(ON|OFF) 9 | # DX_DOT_FEATURE(ON|OFF) 10 | # DX_HTML_FEATURE(ON|OFF) 11 | # DX_CHM_FEATURE(ON|OFF) 12 | # DX_CHI_FEATURE(ON|OFF) 13 | # DX_MAN_FEATURE(ON|OFF) 14 | # DX_RTF_FEATURE(ON|OFF) 15 | # DX_XML_FEATURE(ON|OFF) 16 | # DX_PDF_FEATURE(ON|OFF) 17 | # DX_PS_FEATURE(ON|OFF) 18 | # 19 | # DESCRIPTION 20 | # 21 | # The DX_*_FEATURE macros control the default setting for the given 22 | # Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for 23 | # generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML 24 | # help (for MS users), 'CHI' for generating a seperate .chi file by the 25 | # .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate 26 | # output formats. The environment variable DOXYGEN_PAPER_SIZE may be 27 | # specified to override the default 'a4wide' paper size. 28 | # 29 | # By default, HTML, PDF and PS documentation is generated as this seems to 30 | # be the most popular and portable combination. MAN pages created by 31 | # Doxygen are usually problematic, though by picking an appropriate subset 32 | # and doing some massaging they might be better than nothing. CHM and RTF 33 | # are specific for MS (note that you can't generate both HTML and CHM at 34 | # the same time). The XML is rather useless unless you apply specialized 35 | # post-processing to it. 36 | # 37 | # The macros mainly control the default state of the feature. The use can 38 | # override the default by specifying --enable or --disable. The macros 39 | # ensure that contradictory flags are not given (e.g., 40 | # --enable-doxygen-html and --enable-doxygen-chm, 41 | # --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each 42 | # feature will be automatically disabled (with a warning) if the required 43 | # programs are missing. 44 | # 45 | # Once all the feature defaults have been specified, call DX_INIT_DOXYGEN 46 | # with the following parameters: a one-word name for the project for use 47 | # as a filename base etc., an optional configuration file name (the 48 | # default is 'Doxyfile', the same as Doxygen's default), and an optional 49 | # output directory name (the default is 'doxygen-doc'). 50 | # 51 | # Automake Support 52 | # 53 | # The following is a template aminclude.am file for use with Automake. 54 | # Make targets and variables values are controlled by the various 55 | # DX_COND_* conditionals set by autoconf. 56 | # 57 | # The provided targets are: 58 | # 59 | # doxygen-doc: Generate all doxygen documentation. 60 | # 61 | # doxygen-run: Run doxygen, which will generate some of the 62 | # documentation (HTML, CHM, CHI, MAN, RTF, XML) 63 | # but will not do the post processing required 64 | # for the rest of it (PS, PDF, and some MAN). 65 | # 66 | # doxygen-man: Rename some doxygen generated man pages. 67 | # 68 | # doxygen-ps: Generate doxygen PostScript documentation. 69 | # 70 | # doxygen-pdf: Generate doxygen PDF documentation. 71 | # 72 | # Note that by default these are not integrated into the automake targets. 73 | # If doxygen is used to generate man pages, you can achieve this 74 | # integration by setting man3_MANS to the list of man pages generated and 75 | # then adding the dependency: 76 | # 77 | # $(man3_MANS): doxygen-doc 78 | # 79 | # This will cause make to run doxygen and generate all the documentation. 80 | # 81 | # The following variable is intended for use in Makefile.am: 82 | # 83 | # DX_CLEANFILES = everything to clean. 84 | # 85 | # Then add this variable to MOSTLYCLEANFILES. 86 | # 87 | # ----- begin aminclude.am ------------------------------------- 88 | # 89 | # ## --------------------------------- ## 90 | # ## Format-independent Doxygen rules. ## 91 | # ## --------------------------------- ## 92 | # 93 | # if DX_COND_doc 94 | # 95 | # ## ------------------------------- ## 96 | # ## Rules specific for HTML output. ## 97 | # ## ------------------------------- ## 98 | # 99 | # if DX_COND_html 100 | # 101 | # DX_CLEAN_HTML = @DX_DOCDIR@/html 102 | # 103 | # endif DX_COND_html 104 | # 105 | # ## ------------------------------ ## 106 | # ## Rules specific for CHM output. ## 107 | # ## ------------------------------ ## 108 | # 109 | # if DX_COND_chm 110 | # 111 | # DX_CLEAN_CHM = @DX_DOCDIR@/chm 112 | # 113 | # if DX_COND_chi 114 | # 115 | # DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi 116 | # 117 | # endif DX_COND_chi 118 | # 119 | # endif DX_COND_chm 120 | # 121 | # ## ------------------------------ ## 122 | # ## Rules specific for MAN output. ## 123 | # ## ------------------------------ ## 124 | # 125 | # if DX_COND_man 126 | # 127 | # DX_CLEAN_MAN = @DX_DOCDIR@/man 128 | # 129 | # endif DX_COND_man 130 | # 131 | # ## ------------------------------ ## 132 | # ## Rules specific for RTF output. ## 133 | # ## ------------------------------ ## 134 | # 135 | # if DX_COND_rtf 136 | # 137 | # DX_CLEAN_RTF = @DX_DOCDIR@/rtf 138 | # 139 | # endif DX_COND_rtf 140 | # 141 | # ## ------------------------------ ## 142 | # ## Rules specific for XML output. ## 143 | # ## ------------------------------ ## 144 | # 145 | # if DX_COND_xml 146 | # 147 | # DX_CLEAN_XML = @DX_DOCDIR@/xml 148 | # 149 | # endif DX_COND_xml 150 | # 151 | # ## ----------------------------- ## 152 | # ## Rules specific for PS output. ## 153 | # ## ----------------------------- ## 154 | # 155 | # if DX_COND_ps 156 | # 157 | # DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps 158 | # 159 | # DX_PS_GOAL = doxygen-ps 160 | # 161 | # doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps 162 | # 163 | # @DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag 164 | # cd @DX_DOCDIR@/latex; \ 165 | # rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ 166 | # $(DX_LATEX) refman.tex; \ 167 | # $(MAKEINDEX_PATH) refman.idx; \ 168 | # $(DX_LATEX) refman.tex; \ 169 | # countdown=5; \ 170 | # while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ 171 | # refman.log > /dev/null 2>&1 \ 172 | # && test $$countdown -gt 0; do \ 173 | # $(DX_LATEX) refman.tex; \ 174 | # countdown=`expr $$countdown - 1`; \ 175 | # done; \ 176 | # $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi 177 | # 178 | # endif DX_COND_ps 179 | # 180 | # ## ------------------------------ ## 181 | # ## Rules specific for PDF output. ## 182 | # ## ------------------------------ ## 183 | # 184 | # if DX_COND_pdf 185 | # 186 | # DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf 187 | # 188 | # DX_PDF_GOAL = doxygen-pdf 189 | # 190 | # doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf 191 | # 192 | # @DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag 193 | # cd @DX_DOCDIR@/latex; \ 194 | # rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ 195 | # $(DX_PDFLATEX) refman.tex; \ 196 | # $(DX_MAKEINDEX) refman.idx; \ 197 | # $(DX_PDFLATEX) refman.tex; \ 198 | # countdown=5; \ 199 | # while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ 200 | # refman.log > /dev/null 2>&1 \ 201 | # && test $$countdown -gt 0; do \ 202 | # $(DX_PDFLATEX) refman.tex; \ 203 | # countdown=`expr $$countdown - 1`; \ 204 | # done; \ 205 | # mv refman.pdf ../@PACKAGE@.pdf 206 | # 207 | # endif DX_COND_pdf 208 | # 209 | # ## ------------------------------------------------- ## 210 | # ## Rules specific for LaTeX (shared for PS and PDF). ## 211 | # ## ------------------------------------------------- ## 212 | # 213 | # if DX_COND_latex 214 | # 215 | # DX_CLEAN_LATEX = @DX_DOCDIR@/latex 216 | # 217 | # endif DX_COND_latex 218 | # 219 | # .PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL) 220 | # 221 | # .INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) 222 | # 223 | # doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag 224 | # 225 | # doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) 226 | # 227 | # @DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS) 228 | # rm -rf @DX_DOCDIR@ 229 | # $(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG) 230 | # 231 | # DX_CLEANFILES = \ 232 | # @DX_DOCDIR@/@PACKAGE@.tag \ 233 | # -r \ 234 | # $(DX_CLEAN_HTML) \ 235 | # $(DX_CLEAN_CHM) \ 236 | # $(DX_CLEAN_CHI) \ 237 | # $(DX_CLEAN_MAN) \ 238 | # $(DX_CLEAN_RTF) \ 239 | # $(DX_CLEAN_XML) \ 240 | # $(DX_CLEAN_PS) \ 241 | # $(DX_CLEAN_PDF) \ 242 | # $(DX_CLEAN_LATEX) 243 | # 244 | # endif DX_COND_doc 245 | # 246 | # ----- end aminclude.am --------------------------------------- 247 | # 248 | # LICENSE 249 | # 250 | # Copyright (c) 2009 Oren Ben-Kiki 251 | # 252 | # Copying and distribution of this file, with or without modification, are 253 | # permitted in any medium without royalty provided the copyright notice 254 | # and this notice are preserved. 255 | 256 | ## ----------## 257 | ## Defaults. ## 258 | ## ----------## 259 | 260 | DX_ENV="" 261 | AC_DEFUN([DX_FEATURE_doc], ON) 262 | AC_DEFUN([DX_FEATURE_dot], ON) 263 | AC_DEFUN([DX_FEATURE_man], OFF) 264 | AC_DEFUN([DX_FEATURE_html], ON) 265 | AC_DEFUN([DX_FEATURE_chm], OFF) 266 | AC_DEFUN([DX_FEATURE_chi], OFF) 267 | AC_DEFUN([DX_FEATURE_rtf], OFF) 268 | AC_DEFUN([DX_FEATURE_xml], OFF) 269 | AC_DEFUN([DX_FEATURE_pdf], ON) 270 | AC_DEFUN([DX_FEATURE_ps], ON) 271 | 272 | ## --------------- ## 273 | ## Private macros. ## 274 | ## --------------- ## 275 | 276 | # DX_ENV_APPEND(VARIABLE, VALUE) 277 | # ------------------------------ 278 | # Append VARIABLE="VALUE" to DX_ENV for invoking doxygen. 279 | AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])]) 280 | 281 | # DX_DIRNAME_EXPR 282 | # --------------- 283 | # Expand into a shell expression prints the directory part of a path. 284 | AC_DEFUN([DX_DIRNAME_EXPR], 285 | [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']]) 286 | 287 | # DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF) 288 | # ------------------------------------- 289 | # Expands according to the M4 (static) status of the feature. 290 | AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])]) 291 | 292 | # DX_REQUIRE_PROG(VARIABLE, PROGRAM) 293 | # ---------------------------------- 294 | # Require the specified program to be found for the DX_CURRENT_FEATURE to work. 295 | AC_DEFUN([DX_REQUIRE_PROG], [ 296 | AC_PATH_TOOL([$1], [$2]) 297 | if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then 298 | AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION]) 299 | AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0) 300 | fi 301 | ]) 302 | 303 | # DX_TEST_FEATURE(FEATURE) 304 | # ------------------------ 305 | # Expand to a shell expression testing whether the feature is active. 306 | AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1]) 307 | 308 | # DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE) 309 | # ------------------------------------------------- 310 | # Verify that a required features has the right state before trying to turn on 311 | # the DX_CURRENT_FEATURE. 312 | AC_DEFUN([DX_CHECK_DEPEND], [ 313 | test "$DX_FLAG_$1" = "$2" \ 314 | || AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1, 315 | requires, contradicts) doxygen-DX_CURRENT_FEATURE]) 316 | ]) 317 | 318 | # DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE) 319 | # ---------------------------------------------------------- 320 | # Turn off the DX_CURRENT_FEATURE if the required feature is off. 321 | AC_DEFUN([DX_CLEAR_DEPEND], [ 322 | test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0) 323 | ]) 324 | 325 | # DX_FEATURE_ARG(FEATURE, DESCRIPTION, 326 | # CHECK_DEPEND, CLEAR_DEPEND, 327 | # REQUIRE, DO-IF-ON, DO-IF-OFF) 328 | # -------------------------------------------- 329 | # Parse the command-line option controlling a feature. CHECK_DEPEND is called 330 | # if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND), 331 | # otherwise CLEAR_DEPEND is called to turn off the default state if a required 332 | # feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional 333 | # requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and 334 | # DO-IF-ON or DO-IF-OFF are called according to the final state of the feature. 335 | AC_DEFUN([DX_ARG_ABLE], [ 336 | AC_DEFUN([DX_CURRENT_FEATURE], [$1]) 337 | AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2]) 338 | AC_ARG_ENABLE(doxygen-$1, 339 | [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1], 340 | [--enable-doxygen-$1]), 341 | DX_IF_FEATURE([$1], [don't $2], [$2]))], 342 | [ 343 | case "$enableval" in 344 | #( 345 | y|Y|yes|Yes|YES) 346 | AC_SUBST([DX_FLAG_$1], 1) 347 | $3 348 | ;; #( 349 | n|N|no|No|NO) 350 | AC_SUBST([DX_FLAG_$1], 0) 351 | ;; #( 352 | *) 353 | AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1]) 354 | ;; 355 | esac 356 | ], [ 357 | AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)]) 358 | $4 359 | ]) 360 | if DX_TEST_FEATURE([$1]); then 361 | $5 362 | : 363 | fi 364 | if DX_TEST_FEATURE([$1]); then 365 | AM_CONDITIONAL(DX_COND_$1, :) 366 | $6 367 | : 368 | else 369 | AM_CONDITIONAL(DX_COND_$1, false) 370 | $7 371 | : 372 | fi 373 | ]) 374 | 375 | ## -------------- ## 376 | ## Public macros. ## 377 | ## -------------- ## 378 | 379 | # DX_XXX_FEATURE(DEFAULT_STATE) 380 | # ----------------------------- 381 | AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])]) 382 | AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])]) 383 | AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])]) 384 | AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])]) 385 | AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])]) 386 | AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])]) 387 | AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) 388 | AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) 389 | AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])]) 390 | AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])]) 391 | 392 | # DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR]) 393 | # --------------------------------------------------------- 394 | # PROJECT also serves as the base name for the documentation files. 395 | # The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc". 396 | AC_DEFUN([DX_INIT_DOXYGEN], [ 397 | 398 | # Files: 399 | AC_SUBST([DX_PROJECT], [$1]) 400 | AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])]) 401 | AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])]) 402 | 403 | # Environment variables used inside doxygen.cfg: 404 | DX_ENV_APPEND(SRCDIR, $srcdir) 405 | DX_ENV_APPEND(PROJECT, $DX_PROJECT) 406 | DX_ENV_APPEND(DOCDIR, $DX_DOCDIR) 407 | DX_ENV_APPEND(VERSION, $PACKAGE_VERSION) 408 | 409 | # Doxygen itself: 410 | DX_ARG_ABLE(doc, [generate any doxygen documentation], 411 | [], 412 | [], 413 | [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen) 414 | DX_REQUIRE_PROG([DX_PERL], perl)], 415 | [DX_ENV_APPEND(PERL_PATH, $DX_PERL)]) 416 | 417 | # Dot for graphics: 418 | DX_ARG_ABLE(dot, [generate graphics for doxygen documentation], 419 | [DX_CHECK_DEPEND(doc, 1)], 420 | [DX_CLEAR_DEPEND(doc, 1)], 421 | [DX_REQUIRE_PROG([DX_DOT], dot)], 422 | [DX_ENV_APPEND(HAVE_DOT, YES) 423 | DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])], 424 | [DX_ENV_APPEND(HAVE_DOT, NO)]) 425 | 426 | # Man pages generation: 427 | DX_ARG_ABLE(man, [generate doxygen manual pages], 428 | [DX_CHECK_DEPEND(doc, 1)], 429 | [DX_CLEAR_DEPEND(doc, 1)], 430 | [], 431 | [DX_ENV_APPEND(GENERATE_MAN, YES)], 432 | [DX_ENV_APPEND(GENERATE_MAN, NO)]) 433 | 434 | # RTF file generation: 435 | DX_ARG_ABLE(rtf, [generate doxygen RTF documentation], 436 | [DX_CHECK_DEPEND(doc, 1)], 437 | [DX_CLEAR_DEPEND(doc, 1)], 438 | [], 439 | [DX_ENV_APPEND(GENERATE_RTF, YES)], 440 | [DX_ENV_APPEND(GENERATE_RTF, NO)]) 441 | 442 | # XML file generation: 443 | DX_ARG_ABLE(xml, [generate doxygen XML documentation], 444 | [DX_CHECK_DEPEND(doc, 1)], 445 | [DX_CLEAR_DEPEND(doc, 1)], 446 | [], 447 | [DX_ENV_APPEND(GENERATE_XML, YES)], 448 | [DX_ENV_APPEND(GENERATE_XML, NO)]) 449 | 450 | # (Compressed) HTML help generation: 451 | DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation], 452 | [DX_CHECK_DEPEND(doc, 1)], 453 | [DX_CLEAR_DEPEND(doc, 1)], 454 | [DX_REQUIRE_PROG([DX_HHC], hhc)], 455 | [DX_ENV_APPEND(HHC_PATH, $DX_HHC) 456 | DX_ENV_APPEND(GENERATE_HTML, YES) 457 | DX_ENV_APPEND(GENERATE_HTMLHELP, YES)], 458 | [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)]) 459 | 460 | # Seperate CHI file generation. 461 | DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file], 462 | [DX_CHECK_DEPEND(chm, 1)], 463 | [DX_CLEAR_DEPEND(chm, 1)], 464 | [], 465 | [DX_ENV_APPEND(GENERATE_CHI, YES)], 466 | [DX_ENV_APPEND(GENERATE_CHI, NO)]) 467 | 468 | # Plain HTML pages generation: 469 | DX_ARG_ABLE(html, [generate doxygen plain HTML documentation], 470 | [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)], 471 | [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)], 472 | [], 473 | [DX_ENV_APPEND(GENERATE_HTML, YES)], 474 | [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)]) 475 | 476 | # PostScript file generation: 477 | DX_ARG_ABLE(ps, [generate doxygen PostScript documentation], 478 | [DX_CHECK_DEPEND(doc, 1)], 479 | [DX_CLEAR_DEPEND(doc, 1)], 480 | [DX_REQUIRE_PROG([DX_LATEX], latex) 481 | DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) 482 | DX_REQUIRE_PROG([DX_DVIPS], dvips) 483 | DX_REQUIRE_PROG([DX_EGREP], egrep)]) 484 | 485 | # PDF file generation: 486 | DX_ARG_ABLE(pdf, [generate doxygen PDF documentation], 487 | [DX_CHECK_DEPEND(doc, 1)], 488 | [DX_CLEAR_DEPEND(doc, 1)], 489 | [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex) 490 | DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) 491 | DX_REQUIRE_PROG([DX_EGREP], egrep)]) 492 | 493 | # LaTeX generation for PS and/or PDF: 494 | if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then 495 | AM_CONDITIONAL(DX_COND_latex, :) 496 | DX_ENV_APPEND(GENERATE_LATEX, YES) 497 | else 498 | AM_CONDITIONAL(DX_COND_latex, false) 499 | DX_ENV_APPEND(GENERATE_LATEX, NO) 500 | fi 501 | 502 | # Paper size for PS and/or PDF: 503 | AC_ARG_VAR(DOXYGEN_PAPER_SIZE, 504 | [a4wide (default), a4, letter, legal or executive]) 505 | case "$DOXYGEN_PAPER_SIZE" in 506 | #( 507 | "") 508 | AC_SUBST(DOXYGEN_PAPER_SIZE, "") 509 | ;; #( 510 | a4wide|a4|letter|legal|executive) 511 | DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE) 512 | ;; #( 513 | *) 514 | AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE']) 515 | ;; 516 | esac 517 | 518 | #For debugging: 519 | #echo DX_FLAG_doc=$DX_FLAG_doc 520 | #echo DX_FLAG_dot=$DX_FLAG_dot 521 | #echo DX_FLAG_man=$DX_FLAG_man 522 | #echo DX_FLAG_html=$DX_FLAG_html 523 | #echo DX_FLAG_chm=$DX_FLAG_chm 524 | #echo DX_FLAG_chi=$DX_FLAG_chi 525 | #echo DX_FLAG_rtf=$DX_FLAG_rtf 526 | #echo DX_FLAG_xml=$DX_FLAG_xml 527 | #echo DX_FLAG_pdf=$DX_FLAG_pdf 528 | #echo DX_FLAG_ps=$DX_FLAG_ps 529 | #echo DX_ENV=$DX_ENV 530 | ]) 531 | --------------------------------------------------------------------------------