Changeset 988 for vendor/current/lib/tevent
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- Location:
- vendor/current/lib/tevent
- Files:
-
- 31 added
- 2 deleted
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/lib/tevent/bindings.py
r740 r988 23 23 24 24 import signal 25 from unittest import TestCase, TestProgram 26 import gc 27 25 28 import _tevent 26 from unittest import TestCase27 29 28 30 class BackendListTests(TestCase): … … 61 63 sig = self.ctx.add_signal(signal.SIGINT, 0, lambda callback: None) 62 64 self.assertTrue(isinstance(sig, _tevent.Signal)) 65 66 def test_timer(self): 67 """Test a timer is can be scheduled""" 68 collecting_list = [] 69 # time "0" has already passed, callback will be scheduled immediately 70 timer = self.ctx.add_timer(0, lambda t: collecting_list.append(True)) 71 self.assertTrue(timer.active) 72 self.assertEqual(collecting_list, []) 73 self.ctx.loop_once() 74 self.assertFalse(timer.active) 75 self.assertEqual(collecting_list, [True]) 76 77 def test_timer_deallocate_timer(self): 78 """Test timer is scheduled even if reference to it isn't held""" 79 collecting_list = [] 80 def callback(t): 81 collecting_list.append(True) 82 timer = self.ctx.add_timer(0, lambda t: collecting_list.append(True)) 83 gc.collect() 84 self.assertEqual(collecting_list, []) 85 self.ctx.loop_once() 86 self.assertEqual(collecting_list, [True]) 87 88 def test_timer_deallocate_context(self): 89 """Test timer is unscheduled when context is freed""" 90 collecting_list = [] 91 def callback(t): 92 collecting_list.append(True) 93 timer = self.ctx.add_timer(0, lambda t: collecting_list.append(True)) 94 self.assertTrue(timer.active) 95 del self.ctx 96 gc.collect() 97 self.assertEqual(collecting_list, []) 98 self.assertFalse(timer.active) 99 100 def test_timer_offset(self): 101 """Test scheduling timer with an offset""" 102 collecting_list = [] 103 self.ctx.add_timer_offset(0.2, lambda t: collecting_list.append(2)) 104 self.ctx.add_timer_offset(0.1, lambda t: collecting_list.append(1)) 105 self.assertEqual(collecting_list, []) 106 self.ctx.loop_once() 107 self.assertEqual(collecting_list, [1]) 108 self.ctx.loop_once() 109 self.assertEqual(collecting_list, [1, 2]) 110 111 if __name__ == '__main__': 112 TestProgram() -
vendor/current/lib/tevent/doc/mainpage.dox
r740 r988 11 11 * tevent_req (tevent request) functions. 12 12 * 13 * @section tevent_download Download 13 * @section main_tevent_tutorial Tutorial 14 * 15 * You should start by reading @subpage tevent_tutorial, then reading the 16 * documentation of the interesting functions as you go. 17 * 18 * @section main_tevent_download Download 14 19 * 15 20 * You can download the latest releases of tevent from the … … 17 22 * on the samba public source archive. 18 23 * 19 * @section tevent_bugs Discussion and bug reports24 * @section main_tevent_bugs Discussion and bug reports 20 25 * 21 26 * tevent does not currently have its own mailing list or bug tracking system. … … 26 31 * bug tracking system. 27 32 * 28 * @section tevent_devel Development33 * @section main_tevent_devel Development 29 34 * You can download the latest code either via git or rsync. 30 35 * -
vendor/current/lib/tevent/doxy.config
r740 r988 1 # Doxyfile 1. 6.11 # Doxyfile 1.8.4 2 2 3 3 # This file describes the settings to be used by the documentation system 4 # doxygen (www.doxygen.org) for a project 4 # doxygen (www.doxygen.org) for a project. 5 5 # 6 # All text after a hash (#) is considered a comment and will be ignored 6 # All text after a double hash (##) is considered a comment and is placed 7 # in front of the TAG it is preceding . 8 # All text after a hash (#) is considered a comment and will be ignored. 7 9 # The format is: 8 10 # TAG = value [value, ...] 9 11 # For lists items can also be appended using: 10 12 # TAG += value [value, ...] 11 # Values that contain spaces should be placed between quotes (" ") 13 # Values that contain spaces should be placed between quotes (" "). 12 14 13 15 #--------------------------------------------------------------------------- … … 23 25 DOXYFILE_ENCODING = UTF-8 24 26 25 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded 26 # by quotes) that should identify the project. 27 # The PROJECT_NAME tag is a single word (or sequence of words) that should 28 # identify the project. Note that if you do not use Doxywizard you need 29 # to put quotes around the project name if it contains spaces. 27 30 28 31 PROJECT_NAME = tevent … … 33 36 34 37 PROJECT_NUMBER = 0.9.8 38 39 # Using the PROJECT_BRIEF tag one can provide an optional one line description 40 # for a project that appears at the top of each page and should give viewer 41 # a quick idea about the purpose of the project. Keep the description short. 42 43 PROJECT_BRIEF = 44 45 # With the PROJECT_LOGO tag one can specify an logo or icon that is 46 # included in the documentation. The maximum height of the logo should not 47 # exceed 55 pixels and the maximum width should not exceed 200 pixels. 48 # Doxygen will copy the logo to the output directory. 49 50 PROJECT_LOGO = 35 51 36 52 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) … … 57 73 # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 58 74 # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 59 # messages), Korean, Korean-en, L ithuanian, Norwegian, Macedonian, Persian,60 # P olish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,61 # Slov ene, Spanish, Swedish, Ukrainian, and Vietnamese.75 # messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, 76 # Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, 77 # Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. 62 78 63 79 OUTPUT_LANGUAGE = English … … 123 139 # the path. The tag can be used to show relative paths in the file list. 124 140 # If left blank the directory from which doxygen is run is used as the 125 # path to strip. 141 # path to strip. Note that you specify absolute paths here, but also 142 # relative paths, which will be relative from the directory where doxygen is 143 # started. 126 144 127 145 STRIP_FROM_PATH = … … 137 155 138 156 # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 139 # (but less readable) file names. This can be useful i s your file systems157 # (but less readable) file names. This can be useful if your file system 140 158 # doesn't support long names like on DOS, Mac, or CD-ROM. 141 159 … … 192 210 ALIASES = 193 211 212 # This tag can be used to specify a number of word-keyword mappings (TCL only). 213 # A mapping has the form "name=value". For example adding 214 # "class=itcl::class" will allow you to use the command class in the 215 # itcl::class meaning. 216 217 TCL_SUBST = 218 194 219 # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 195 220 # sources only. Doxygen will then generate output that is more tailored for C. … … 218 243 OPTIMIZE_OUTPUT_VHDL = NO 219 244 220 # Doxygen selects the parser to use depending on the extension of the files it parses. 221 # With this tag you can assign which parser to use for a given extension. 222 # Doxygen has a built-in mapping, but you can override or extend it using this tag. 223 # The format is ext=language, where ext is a file extension, and language is one of 224 # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, 225 # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat 226 # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), 227 # use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. 245 # Doxygen selects the parser to use depending on the extension of the files it 246 # parses. With this tag you can assign which parser to use for a given 247 # extension. Doxygen has a built-in mapping, but you can override or extend it 248 # using this tag. The format is ext=language, where ext is a file extension, 249 # and language is one of the parsers supported by doxygen: IDL, Java, 250 # Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, 251 # C++. For instance to make doxygen treat .inc files as Fortran files (default 252 # is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note 253 # that for custom extensions you also need to set FILE_PATTERNS otherwise the 254 # files are not read by doxygen. 228 255 229 256 EXTENSION_MAPPING = 257 258 # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all 259 # comments according to the Markdown format, which allows for more readable 260 # documentation. See http://daringfireball.net/projects/markdown/ for details. 261 # The output of markdown processing is further processed by doxygen, so you 262 # can mix doxygen, HTML, and XML commands with Markdown formatting. 263 # Disable only in case of backward compatibilities issues. 264 265 MARKDOWN_SUPPORT = YES 266 267 # When enabled doxygen tries to link words that correspond to documented 268 # classes, or namespaces to their corresponding documentation. Such a link can 269 # be prevented in individual cases by by putting a % sign in front of the word 270 # or globally by setting AUTOLINK_SUPPORT to NO. 271 272 AUTOLINK_SUPPORT = YES 230 273 231 274 # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want … … 233 276 # set this tag to YES in order to let doxygen match functions declarations and 234 277 # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 235 # func(std::string) {}). This also make the inheritance and collaboration278 # func(std::string) {}). This also makes the inheritance and collaboration 236 279 # diagrams that involve STL classes more complete and accurate. 237 280 … … 249 292 SIP_SUPPORT = NO 250 293 251 # For Microsoft's IDL there are propget and propput attributes to indicate getter252 # and setter methods for a property. Setting this option to YES (the default)253 # will make doxygen to replace the get and set methods by a property in the254 # documentation. This will only work if the methods are indeed getting or294 # For Microsoft's IDL there are propget and propput attributes to indicate 295 # getter and setter methods for a property. Setting this option to YES (the 296 # default) will make doxygen replace the get and set methods by a property in 297 # the documentation. This will only work if the methods are indeed getting or 255 298 # setting a simple type. If this is not the case, or you want to show the 256 299 # methods anyway, you should set this option to NO. … … 272 315 273 316 SUBGROUPING = YES 317 318 # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 319 # unions are shown inside the group in which they are included (e.g. using 320 # @ingroup) instead of on a separate page (for HTML and Man pages) or 321 # section (for LaTeX and RTF). 322 323 INLINE_GROUPED_CLASSES = NO 324 325 # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 326 # unions with only public data fields or simple typedef fields will be shown 327 # inline in the documentation of the scope in which they are defined (i.e. file, 328 # namespace, or group documentation), provided this scope is documented. If set 329 # to NO (the default), structs, classes, and unions are shown on a separate 330 # page (for HTML and Man pages) or section (for LaTeX and RTF). 331 332 INLINE_SIMPLE_STRUCTS = NO 274 333 275 334 # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum … … 283 342 TYPEDEF_HIDES_STRUCT = NO 284 343 285 # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 286 # determine which symbols to keep in memory and which to flush to disk. 287 # When the cache is full, less often used symbols will be written to disk. 288 # For small to medium size projects (<1000 input files) the default value is 289 # probably good enough. For larger projects a too small cache size can cause 290 # doxygen to be busy swapping symbols to and from disk most of the time 291 # causing a significant performance penality. 292 # If the system has enough physical memory increasing the cache will improve the 293 # performance by keeping more symbols in memory. Note that the value works on 294 # a logarithmic scale so increasing the size by one will rougly double the 295 # memory usage. The cache size is given by this formula: 296 # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 297 # corresponding to a cache size of 2^16 = 65536 symbols 298 299 SYMBOL_CACHE_SIZE = 0 344 # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This 345 # cache is used to resolve symbols given their name and scope. Since this can 346 # be an expensive process and often the same symbol appear multiple times in 347 # the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too 348 # small doxygen will become slower. If the cache is too large, memory is wasted. 349 # The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid 350 # range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 351 # symbols. 352 353 LOOKUP_CACHE_SIZE = 0 300 354 301 355 #--------------------------------------------------------------------------- … … 306 360 # documentation are documented, even if no documentation was available. 307 361 # Private class members and static file members will be hidden unless 308 # the EXTRACT_PRIVATE andEXTRACT_STATIC tags are set to YES362 # the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES 309 363 310 364 EXTRACT_ALL = NO … … 314 368 315 369 EXTRACT_PRIVATE = NO 370 371 # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal 372 # scope will be included in the documentation. 373 374 EXTRACT_PACKAGE = NO 316 375 317 376 # If the EXTRACT_STATIC tag is set to YES all static members of a file … … 337 396 # 'anonymous_namespace{file}', where file will be replaced with the base 338 397 # name of the file that contains the anonymous namespace. By default 339 # anonymous namespace are hidden.398 # anonymous namespaces are hidden. 340 399 341 400 EXTRACT_ANON_NSPACES = NO … … 397 456 SHOW_INCLUDE_FILES = YES 398 457 458 # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 459 # will list include files with double quotes in the documentation 460 # rather than with sharp brackets. 461 462 FORCE_LOCAL_INCLUDES = NO 463 399 464 # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 400 465 # is inserted in the documentation for inline members. … … 416 481 SORT_BRIEF_DOCS = NO 417 482 418 # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. 483 # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 484 # will sort the (brief and detailed) documentation of class members so that 485 # constructors and destructors are listed first. If set to NO (the default) 486 # the constructors will appear in the respective orders defined by 487 # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 488 # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 489 # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. 419 490 420 491 SORT_MEMBERS_CTORS_1ST = NO … … 436 507 SORT_BY_SCOPE_NAME = NO 437 508 509 # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 510 # do proper type resolution of all parameters of a function it will reject a 511 # match between the prototype and the implementation of a member function even 512 # if there is only one candidate or it is obvious which candidate to choose 513 # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 514 # will still accept a match between prototype and implementation in such cases. 515 516 STRICT_PROTO_MATCHING = NO 517 438 518 # The GENERATE_TODOLIST tag can be used to enable (YES) or 439 519 # disable (NO) the todo list. This list is created by putting \todo … … 461 541 462 542 # The ENABLED_SECTIONS tag can be used to enable conditional 463 # documentation sections, marked by \if sectionname ... \endif. 543 # documentation sections, marked by \if section-label ... \endif 544 # and \cond section-label ... \endcond blocks. 464 545 465 546 ENABLED_SECTIONS = 466 547 467 548 # The MAX_INITIALIZER_LINES tag determines the maximum number of lines 468 # the initial value of a variable or defineconsists of for it to appear in549 # the initial value of a variable or macro consists of for it to appear in 469 550 # the documentation. If the initializer consists of more lines than specified 470 551 # here it will be hidden. Use a value of 0 to hide initializers completely. 471 # The appearance of the initializer of individual variables and defines in the552 # The appearance of the initializer of individual variables and macros in the 472 553 # documentation can be controlled using \showinitializer or \hideinitializer 473 554 # command in the documentation regardless of this setting. … … 480 561 481 562 SHOW_USED_FILES = YES 482 483 # If the sources in your project are distributed over multiple directories484 # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy485 # in the documentation. The default is NO.486 487 SHOW_DIRECTORIES = NO488 563 489 564 # Set the SHOW_FILES tag to NO to disable the generation of the Files page. … … 510 585 FILE_VERSION_FILTER = 511 586 512 # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by513 # doxygen. The layout file controls the global structure of the generated output files514 # in an output format independent way. The create the layout file that represents515 # doxygen's defaults, run doxygen with the -l option. You can optionally specify a516 # file name after the option, if omitted DoxygenLayout.xml will be used as the name517 # of the layout file.587 # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 588 # by doxygen. The layout file controls the global structure of the generated 589 # output files in an output format independent way. To create the layout file 590 # that represents doxygen's defaults, run doxygen with the -l option. 591 # You can optionally specify a file name after the option, if omitted 592 # DoxygenLayout.xml will be used as the name of the layout file. 518 593 519 594 LAYOUT_FILE = 595 596 # The CITE_BIB_FILES tag can be used to specify one or more bib files 597 # containing the references data. This must be a list of .bib files. The 598 # .bib extension is automatically appended if omitted. Using this command 599 # requires the bibtex tool to be installed. See also 600 # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 601 # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 602 # feature you need bibtex and perl available in the search path. Do not use 603 # file names with spaces, bibtex cannot handle them. 604 605 CITE_BIB_FILES = 520 606 521 607 #--------------------------------------------------------------------------- … … 547 633 WARN_IF_DOC_ERROR = YES 548 634 549 # Th is WARN_NO_PARAMDOC option can beabled to get warnings for635 # The WARN_NO_PARAMDOC option can be enabled to get warnings for 550 636 # functions that are documented, but have no documentation for their parameters 551 637 # or return value. If set to NO (the default) doxygen will only warn about … … 579 665 # with spaces. 580 666 581 INPUT = . doc 667 INPUT = . \ 668 doc 582 669 583 670 # This tag can be used to specify the character encoding of the source files … … 593 680 # and *.h) to filter out the source-files in the directories. If left 594 681 # blank the following patterns are tested: 595 # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 596 # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 682 # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 683 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 684 # *.f90 *.f *.for *.vhd *.vhdl 597 685 598 686 FILE_PATTERNS = *.cpp \ … … 610 698 RECURSIVE = NO 611 699 612 # The EXCLUDE tag can be used to specify files and/or directories that should 700 # The EXCLUDE tag can be used to specify files and/or directories that should be 613 701 # excluded from the INPUT source files. This way you can easily exclude a 614 702 # subdirectory from a directory tree whose root is specified with the INPUT tag. 703 # Note that relative paths are relative to the directory from which doxygen is 704 # run. 615 705 616 706 EXCLUDE = 617 707 618 # The EXCLUDE_SYMLINKS tag can be used select whether or not files or619 # directories that are symbolic links (a Unix file system feature) are excluded708 # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 709 # directories that are symbolic links (a Unix file system feature) are excluded 620 710 # from the input. 621 711 … … 628 718 # for example use the pattern */test/* 629 719 630 EXCLUDE_PATTERNS = */.git/* \ 631 */.svn/* \ 632 */cmake/* \ 633 */build/* 720 EXCLUDE_PATTERNS = */.git/* 634 721 635 722 # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names … … 665 752 # the \image command). 666 753 667 IMAGE_PATH = 754 IMAGE_PATH = doc/img 668 755 669 756 # The INPUT_FILTER tag can be used to specify a program that doxygen should … … 673 760 # input file. Doxygen will then use the output that the filter program writes 674 761 # to standard output. 675 # If FILTER_PATTERNS is specified, this tag will be 676 # ignored. 762 # If FILTER_PATTERNS is specified, this tag will be ignored. 763 # Note that the filter must not add or remove lines; it is applied before the 764 # code is scanned, but not when the output code is generated. If lines are added 765 # or removed, the anchors will not be placed correctly. 677 766 678 767 INPUT_FILTER = … … 684 773 # The filters are a list of the form: 685 774 # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 686 # info on how filters are used. If FILTER_PATTERNS is empty , INPUT_FILTER687 # is applied to all files.775 # info on how filters are used. If FILTER_PATTERNS is empty or if 776 # non of the patterns match the file name, INPUT_FILTER is applied. 688 777 689 778 FILTER_PATTERNS = … … 694 783 695 784 FILTER_SOURCE_FILES = NO 785 786 # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 787 # pattern. A pattern will override the setting for FILTER_PATTERN (if any) 788 # and it is also possible to disable source filtering for a specific pattern 789 # using *.ext= (so without naming a filter). This option only has effect when 790 # FILTER_SOURCE_FILES is enabled. 791 792 FILTER_SOURCE_PATTERNS = 793 794 # If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that 795 # is part of the input, its contents will be placed on the main page 796 # (index.html). This can be useful if you have a project on for instance GitHub 797 # and want reuse the introduction page also for the doxygen output. 798 799 USE_MDFILE_AS_MAINPAGE = 696 800 697 801 #--------------------------------------------------------------------------- … … 713 817 # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 714 818 # doxygen to hide any special comment blocks from generated source code 715 # fragments. Normal C and C++comments will always remain visible.819 # fragments. Normal C, C++ and Fortran comments will always remain visible. 716 820 717 821 STRIP_CODE_COMMENTS = YES … … 783 887 GENERATE_HTML = YES 784 888 785 # If the HTML_FOOTER_DESCRIPTION tag is set to YES, Doxygen will786 # add generated date, project name and doxygen version to HTML footer.787 788 HTML_FOOTER_DESCRIPTION= NO789 790 889 # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 791 890 # If a relative path is entered the value of OUTPUT_DIRECTORY will be … … 802 901 # The HTML_HEADER tag can be used to specify a personal HTML header for 803 902 # each generated HTML page. If it is left blank doxygen will generate a 804 # standard header. 903 # standard header. Note that when using a custom header you are responsible 904 # for the proper inclusion of any scripts and style sheets that doxygen 905 # needs, which is dependent on the configuration options used. 906 # It is advised to generate a default header using "doxygen -w html 907 # header.html footer.html stylesheet.css YourConfigFile" and then modify 908 # that header. Note that the header is subject to change so you typically 909 # have to redo this when upgrading to a newer version of doxygen or when 910 # changing the value of configuration settings such as GENERATE_TREEVIEW! 805 911 806 912 HTML_HEADER = … … 814 920 # The HTML_STYLESHEET tag can be used to specify a user-defined cascading 815 921 # style sheet that is used by each HTML page. It can be used to 816 # fine-tune the look of the HTML output. If the tag is left blank doxygen817 # will generate a default style sheet. Note that doxygen will try to copy818 # the style sheet file to the HTML output directory, so don't put your own819 # stylesheet in the HTML output directory as well, or it will be erased!922 # fine-tune the look of the HTML output. If left blank doxygen will 923 # generate a default style sheet. Note that it is recommended to use 924 # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this 925 # tag will in the future become obsolete. 820 926 821 927 HTML_STYLESHEET = 822 928 823 # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 824 # files or namespaces will be aligned in HTML using tables. If set to 825 # NO a bullet list will be used. 826 827 HTML_ALIGN_MEMBERS = YES 929 # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional 930 # user-defined cascading style sheet that is included after the standard 931 # style sheets created by doxygen. Using this option one can overrule 932 # certain style aspects. This is preferred over using HTML_STYLESHEET 933 # since it does not replace the standard style sheet and is therefor more 934 # robust against future updates. Doxygen will copy the style sheet file to 935 # the output directory. 936 937 HTML_EXTRA_STYLESHEET = 938 939 # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 940 # other source files which should be copied to the HTML output directory. Note 941 # that these files will be copied to the base HTML output directory. Use the 942 # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 943 # files. In the HTML_STYLESHEET file, use the file name only. Also note that 944 # the files will be copied as-is; there are no commands or markers available. 945 946 HTML_EXTRA_FILES = 947 948 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 949 # Doxygen will adjust the colors in the style sheet and background images 950 # according to this color. Hue is specified as an angle on a colorwheel, 951 # see http://en.wikipedia.org/wiki/Hue for more information. 952 # For instance the value 0 represents red, 60 is yellow, 120 is green, 953 # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 954 # The allowed range is 0 to 359. 955 956 HTML_COLORSTYLE_HUE = 220 957 958 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 959 # the colors in the HTML output. For a value of 0 the output will use 960 # grayscales only. A value of 255 will produce the most vivid colors. 961 962 HTML_COLORSTYLE_SAT = 100 963 964 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 965 # the luminance component of the colors in the HTML output. Values below 966 # 100 gradually make the output lighter, whereas values above 100 make 967 # the output darker. The value divided by 100 is the actual gamma applied, 968 # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 969 # and 100 does not change the gamma. 970 971 HTML_COLORSTYLE_GAMMA = 80 972 973 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 974 # page will contain the date and time when the page was generated. Setting 975 # this to NO can help when comparing the output of multiple runs. 976 977 HTML_TIMESTAMP = NO 828 978 829 979 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 830 980 # documentation will contain sections that can be hidden and shown after the 831 # page has loaded. For this to work a browser that supports 832 # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 833 # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). 981 # page has loaded. 834 982 835 983 HTML_DYNAMIC_SECTIONS = NO 984 985 # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of 986 # entries shown in the various tree structured indices initially; the user 987 # can expand and collapse entries dynamically later on. Doxygen will expand 988 # the tree to such a level that at most the specified number of entries are 989 # visible (unless a fully collapsed tree already exceeds this amount). 990 # So setting the number of entries 1 will produce a full collapsed tree by 991 # default. 0 is a special value representing an infinite number of entries 992 # and will result in a full expanded tree by default. 993 994 HTML_INDEX_NUM_ENTRIES = 100 836 995 837 996 # If the GENERATE_DOCSET tag is set to YES, additional index files … … 843 1002 # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 844 1003 # it at startup. 845 # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. 1004 # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 1005 # for more information. 846 1006 847 1007 GENERATE_DOCSET = NO … … 861 1021 DOCSET_BUNDLE_ID = org.doxygen.Project 862 1022 1023 # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely 1024 # identify the documentation publisher. This should be a reverse domain-name 1025 # style string, e.g. com.mycompany.MyDocSet.documentation. 1026 1027 DOCSET_PUBLISHER_ID = org.doxygen.Publisher 1028 1029 # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. 1030 1031 DOCSET_PUBLISHER_NAME = Publisher 1032 863 1033 # If the GENERATE_HTMLHELP tag is set to YES, additional index files 864 1034 # will be generated that can be used as input for tools like the … … 905 1075 TOC_EXPAND = NO 906 1076 907 # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER908 # are set, an additional index file will be generated that can be used as input for909 # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated910 # HTML documentation.1077 # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 1078 # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 1079 # that can be used as input for Qt's qhelpgenerator to generate a 1080 # Qt Compressed Help (.qch) of the generated HTML documentation. 911 1081 912 1082 GENERATE_QHP = NO … … 930 1100 QHP_VIRTUAL_FOLDER = doc 931 1101 932 # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.933 # For more information please see1102 # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 1103 # add. For more information please see 934 1104 # http://doc.trolltech.com/qthelpproject.html#custom-filters 935 1105 936 1106 QHP_CUST_FILTER_NAME = 937 1107 938 # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see 939 # <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. 1108 # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 1109 # custom filter to add. For more information please see 1110 # <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> 1111 # Qt Help Project / Custom Filters</a>. 940 1112 941 1113 QHP_CUST_FILTER_ATTRS = 942 1114 943 # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's 1115 # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 1116 # project's 944 1117 # filter section matches. 945 # <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>. 1118 # <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> 1119 # Qt Help Project / Filter Attributes</a>. 946 1120 947 1121 QHP_SECT_FILTER_ATTRS = … … 954 1128 QHG_LOCATION = 955 1129 956 # The DISABLE_INDEX tag can be used to turn on/off the condensed index at 957 # top of each HTML page. The value NO (the default) enables the index and 958 # the value YES disables it. 1130 # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files 1131 # will be generated, which together with the HTML files, form an Eclipse help 1132 # plugin. To install this plugin and make it available under the help contents 1133 # menu in Eclipse, the contents of the directory containing the HTML and XML 1134 # files needs to be copied into the plugins directory of eclipse. The name of 1135 # the directory within the plugins directory should be the same as 1136 # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 1137 # the help appears. 1138 1139 GENERATE_ECLIPSEHELP = NO 1140 1141 # A unique identifier for the eclipse help plugin. When installing the plugin 1142 # the directory name containing the HTML and XML files should also have 1143 # this name. 1144 1145 ECLIPSE_DOC_ID = org.doxygen.Project 1146 1147 # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 1148 # at top of each HTML page. The value NO (the default) enables the index and 1149 # the value YES disables it. Since the tabs have the same information as the 1150 # navigation tree you can set this option to NO if you already set 1151 # GENERATE_TREEVIEW to YES. 959 1152 960 1153 DISABLE_INDEX = NO 961 962 # This tag can be used to set the number of enum values (range [1..20])963 # that doxygen will group on one line in the generated HTML documentation.964 965 ENUM_VALUES_PER_LINE = 4966 1154 967 1155 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index … … 972 1160 # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 973 1161 # Windows users are probably better off using the HTML help feature. 1162 # Since the tree basically has the same information as the tab index you 1163 # could consider to set DISABLE_INDEX to NO when enabling this option. 974 1164 975 1165 GENERATE_TREEVIEW = NONE 976 1166 977 # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, 978 # and Class Hierarchy pages using a tree view instead of an ordered list. 979 980 USE_INLINE_TREES = NO 1167 # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 1168 # (range [0,1..20]) that doxygen will group on one line in the generated HTML 1169 # documentation. Note that a value of 0 will completely suppress the enum 1170 # values from appearing in the overview section. 1171 1172 ENUM_VALUES_PER_LINE = 4 981 1173 982 1174 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be … … 985 1177 986 1178 TREEVIEW_WIDTH = 250 1179 1180 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 1181 # links to external symbols imported via tag files in a separate window. 1182 1183 EXT_LINKS_IN_WINDOW = NO 987 1184 988 1185 # Use this tag to change the font size of Latex formulas included … … 994 1191 FORMULA_FONTSIZE = 10 995 1192 996 # When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript 997 # and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) 998 # there is already a search function so this one should typically 999 # be disabled. 1193 # Use the FORMULA_TRANPARENT tag to determine whether or not the images 1194 # generated for formulas are transparent PNGs. Transparent PNGs are 1195 # not supported properly for IE 6.0, but are supported on all modern browsers. 1196 # Note that when changing this option you need to delete any form_*.png files 1197 # in the HTML output before the changes have effect. 1198 1199 FORMULA_TRANSPARENT = YES 1200 1201 # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 1202 # (see http://www.mathjax.org) which uses client side Javascript for the 1203 # rendering instead of using prerendered bitmaps. Use this if you do not 1204 # have LaTeX installed or if you want to formulas look prettier in the HTML 1205 # output. When enabled you may also need to install MathJax separately and 1206 # configure the path to it using the MATHJAX_RELPATH option. 1207 1208 USE_MATHJAX = NO 1209 1210 # When MathJax is enabled you can set the default output format to be used for 1211 # the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and 1212 # SVG. The default value is HTML-CSS, which is slower, but has the best 1213 # compatibility. 1214 1215 MATHJAX_FORMAT = HTML-CSS 1216 1217 # When MathJax is enabled you need to specify the location relative to the 1218 # HTML output directory using the MATHJAX_RELPATH option. The destination 1219 # directory should contain the MathJax.js script. For instance, if the mathjax 1220 # directory is located at the same level as the HTML output directory, then 1221 # MATHJAX_RELPATH should be ../mathjax. The default value points to 1222 # the MathJax Content Delivery Network so you can quickly see the result without 1223 # installing MathJax. 1224 # However, it is strongly recommended to install a local 1225 # copy of MathJax from http://www.mathjax.org before deployment. 1226 1227 MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 1228 1229 # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 1230 # names that should be enabled during MathJax rendering. 1231 1232 MATHJAX_EXTENSIONS = 1233 1234 # The MATHJAX_CODEFILE tag can be used to specify a file with javascript 1235 # pieces of code that will be used on startup of the MathJax code. 1236 1237 MATHJAX_CODEFILE = 1238 1239 # When the SEARCHENGINE tag is enabled doxygen will generate a search box 1240 # for the HTML output. The underlying search engine uses javascript 1241 # and DHTML and should work on any modern browser. Note that when using 1242 # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 1243 # (GENERATE_DOCSET) there is already a search function so this one should 1244 # typically be disabled. For large projects the javascript based search engine 1245 # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. 1000 1246 1001 1247 SEARCHENGINE = NO 1248 1249 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be 1250 # implemented using a web server instead of a web client using Javascript. 1251 # There are two flavours of web server based search depending on the 1252 # EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for 1253 # searching and an index file used by the script. When EXTERNAL_SEARCH is 1254 # enabled the indexing and searching needs to be provided by external tools. 1255 # See the manual for details. 1256 1257 SERVER_BASED_SEARCH = NO 1258 1259 # When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP 1260 # script for searching. Instead the search results are written to an XML file 1261 # which needs to be processed by an external indexer. Doxygen will invoke an 1262 # external search engine pointed to by the SEARCHENGINE_URL option to obtain 1263 # the search results. Doxygen ships with an example indexer (doxyindexer) and 1264 # search engine (doxysearch.cgi) which are based on the open source search 1265 # engine library Xapian. See the manual for configuration details. 1266 1267 EXTERNAL_SEARCH = NO 1268 1269 # The SEARCHENGINE_URL should point to a search engine hosted by a web server 1270 # which will returned the search results when EXTERNAL_SEARCH is enabled. 1271 # Doxygen ships with an example search engine (doxysearch) which is based on 1272 # the open source search engine library Xapian. See the manual for configuration 1273 # details. 1274 1275 SEARCHENGINE_URL = 1276 1277 # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed 1278 # search data is written to a file for indexing by an external tool. With the 1279 # SEARCHDATA_FILE tag the name of this file can be specified. 1280 1281 SEARCHDATA_FILE = searchdata.xml 1282 1283 # When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the 1284 # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is 1285 # useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple 1286 # projects and redirect the results back to the right project. 1287 1288 EXTERNAL_SEARCH_ID = 1289 1290 # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen 1291 # projects other than the one defined by this configuration file, but that are 1292 # all added to the same external search index. Each project needs to have a 1293 # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id 1294 # of to a relative location where the documentation can be found. 1295 # The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... 1296 1297 EXTRA_SEARCH_MAPPINGS = 1002 1298 1003 1299 #--------------------------------------------------------------------------- … … 1018 1314 # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 1019 1315 # invoked. If left blank `latex' will be used as the default command name. 1316 # Note that when enabling USE_PDFLATEX this option is only used for 1317 # generating bitmaps for formulas in the HTML output, but not in the 1318 # Makefile that is written to the output directory. 1020 1319 1021 1320 LATEX_CMD_NAME = latex … … 1034 1333 1035 1334 # The PAPER_TYPE tag can be used to set the paper type that is used 1036 # by the printer. Possible values are: a4, a4wide,letter, legal and1037 # executive. If left blank a4 widewill be used.1335 # by the printer. Possible values are: a4, letter, legal and 1336 # executive. If left blank a4 will be used. 1038 1337 1039 1338 PAPER_TYPE = a4wide … … 1051 1350 LATEX_HEADER = 1052 1351 1352 # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 1353 # the generated latex document. The footer should contain everything after 1354 # the last chapter. If it is left blank doxygen will generate a 1355 # standard footer. Notice: only use this tag if you know what you are doing! 1356 1357 LATEX_FOOTER = 1358 1359 # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images 1360 # or other source files which should be copied to the LaTeX output directory. 1361 # Note that the files will be copied as-is; there are no commands or markers 1362 # available. 1363 1364 LATEX_EXTRA_FILES = 1365 1053 1366 # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 1054 1367 # is prepared for conversion to pdf (using ps2pdf). The pdf file will … … 1077 1390 LATEX_HIDE_INDICES = NO 1078 1391 1079 # If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. 1392 # If LATEX_SOURCE_CODE is set to YES then doxygen will include 1393 # source code with syntax highlighting in the LaTeX output. 1394 # Note that which sources are shown also depends on other settings 1395 # such as SOURCE_BROWSER. 1080 1396 1081 1397 LATEX_SOURCE_CODE = NO 1398 1399 # The LATEX_BIB_STYLE tag can be used to specify the style to use for the 1400 # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 1401 # http://en.wikipedia.org/wiki/BibTeX for more info. 1402 1403 LATEX_BIB_STYLE = plain 1082 1404 1083 1405 #--------------------------------------------------------------------------- … … 1112 1434 RTF_HYPERLINKS = NO 1113 1435 1114 # Load style sheet definitions from file. Syntax is similar to doxygen's1436 # Load style sheet definitions from file. Syntax is similar to doxygen's 1115 1437 # config file, i.e. a series of assignments. You only have to provide 1116 1438 # replacements, missing definitions are set to their default value. … … 1185 1507 1186 1508 XML_PROGRAMLISTING = YES 1509 1510 #--------------------------------------------------------------------------- 1511 # configuration options related to the DOCBOOK output 1512 #--------------------------------------------------------------------------- 1513 1514 # If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files 1515 # that can be used to generate PDF. 1516 1517 GENERATE_DOCBOOK = NO 1518 1519 # The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. 1520 # If a relative path is entered the value of OUTPUT_DIRECTORY will be put in 1521 # front of it. If left blank docbook will be used as the default path. 1522 1523 DOCBOOK_OUTPUT = docbook 1187 1524 1188 1525 #--------------------------------------------------------------------------- … … 1257 1594 1258 1595 # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 1259 # in the INCLUDE_PATH (see below) will be search ifa #include is found.1596 # pointed to by INCLUDE_PATH will be searched when a #include is found. 1260 1597 1261 1598 SEARCH_INCLUDES = YES … … 1282 1619 # instead of the = operator. 1283 1620 1284 PREDEFINED = DOXYGEN PRINTF_ATTRIBUTE(x,y)= 1621 PREDEFINED = DOXYGEN \ 1622 PRINTF_ATTRIBUTE(x,y)= 1285 1623 1286 1624 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 1287 1625 # this tag can be used to specify a list of macro names that should be expanded. 1288 1626 # The macro definition that is found in the sources will be used. 1289 # Use the PREDEFINED tag if you want to use a different macro definition. 1627 # Use the PREDEFINED tag if you want to use a different macro definition that 1628 # overrules the definition found in the source code. 1290 1629 1291 1630 EXPAND_AS_DEFINED = 1292 1631 1293 1632 # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 1294 # doxygen's preprocessor will remove all function-like macros that are alone 1295 # on a line, have an all uppercase name, and do not end with a semicolon. Such 1296 # function macros are typically used for boiler-plate code, and will confuse 1297 # the parser if not removed. 1633 # doxygen's preprocessor will remove all references to function-like macros 1634 # that are alone on a line, have an all uppercase name, and do not end with a 1635 # semicolon, because these will confuse the parser if not removed. 1298 1636 1299 1637 SKIP_FUNCTION_MACROS = YES … … 1303 1641 #--------------------------------------------------------------------------- 1304 1642 1305 # The TAGFILES option can be used to specify one or more tagfiles. 1306 # Optionally an initial location of the external documentation 1307 # can be added for each tagfile. The format of a tag file without 1308 # this location is as follows: 1643 # The TAGFILES option can be used to specify one or more tagfiles. For each 1644 # tag file the location of the external documentation should be added. The 1645 # format of a tag file without this location is as follows: 1309 1646 # 1310 1647 # TAGFILES = file1 file2 ... … … 1312 1649 # 1313 1650 # TAGFILES = file1=loc1 "file2 = loc2" ... 1314 # where "loc1" and "loc2" can be relative or absolute paths or 1315 # URLs. If a location is present for each tag, the installdox tool 1316 # does not have to be run to correct the links. 1317 # Note that each tag file must have a unique name 1318 # (where the name does NOT include the path) 1319 # If a tag file is not located in the directory in which doxygen 1320 # is run, you must also specify the path to the tagfile here. 1651 # where "loc1" and "loc2" can be relative or absolute paths 1652 # or URLs. Note that each tag file must have a unique name (where the name does 1653 # NOT include the path). If a tag file is not located in the directory in which 1654 # doxygen is run, you must also specify the path to the tagfile here. 1321 1655 1322 1656 TAGFILES = … … 1339 1673 EXTERNAL_GROUPS = YES 1340 1674 1675 # If the EXTERNAL_PAGES tag is set to YES all external pages will be listed 1676 # in the related pages index. If set to NO, only the current project's 1677 # pages will be listed. 1678 1679 EXTERNAL_PAGES = YES 1680 1341 1681 # The PERL_PATH should be the absolute path and name of the perl script 1342 1682 # interpreter (i.e. the result of `which perl'). … … 1351 1691 # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 1352 1692 # or super classes. Setting the tag to NO turns the diagrams off. Note that 1353 # this option is superseded by the HAVE_DOT option below. This is only a 1354 # fallback. It is recommended to install and use dot, since it yields more 1355 # powerful graphs. 1693 # this option also works with HAVE_DOT disabled, but it is recommended to 1694 # install and use dot, since it yields more powerful graphs. 1356 1695 1357 1696 CLASS_DIAGRAMS = YES … … 1379 1718 HAVE_DOT = NO 1380 1719 1381 # By default doxygen will write a font called FreeSans.ttf to the output 1382 # directory and reference it in all dot files that doxygen generates. This 1383 # font does not include all possible unicode characters however, so when you need 1384 # these (or just want a differently looking font) you can specify the font name 1385 # using DOT_FONTNAME. You need need to make sure dot is able to find the font, 1386 # which can be done by putting it in a standard location or by setting the 1387 # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 1388 # containing the font. 1720 # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 1721 # allowed to run in parallel. When set to 0 (the default) doxygen will 1722 # base this on the number of processors available in the system. You can set it 1723 # explicitly to a value larger than 0 to get control over the balance 1724 # between CPU load and processing speed. 1725 1726 DOT_NUM_THREADS = 0 1727 1728 # By default doxygen will use the Helvetica font for all dot files that 1729 # doxygen generates. When you want a differently looking font you can specify 1730 # the font name using DOT_FONTNAME. You need to make sure dot is able to find 1731 # the font, which can be done by putting it in a standard location or by setting 1732 # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 1733 # directory containing the font. 1389 1734 1390 1735 DOT_FONTNAME = FreeSans … … 1395 1740 DOT_FONTSIZE = 10 1396 1741 1397 # By default doxygen will tell dot to use the output directory to look for the 1398 # FreeSans.ttf font (which doxygen will put there itself). If you specify a 1399 # different font using DOT_FONTNAME you can set the path where dot 1400 # can find it using this tag. 1742 # By default doxygen will tell dot to use the Helvetica font. 1743 # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 1744 # set the path where dot can find it. 1401 1745 1402 1746 DOT_FONTPATH = … … 1405 1749 # will generate a graph for each documented class showing the direct and 1406 1750 # indirect inheritance relations. Setting this tag to YES will force the 1407 # theCLASS_DIAGRAMS tag to NO.1751 # CLASS_DIAGRAMS tag to NO. 1408 1752 1409 1753 CLASS_GRAPH = YES … … 1426 1770 1427 1771 UML_LOOK = NO 1772 1773 # If the UML_LOOK tag is enabled, the fields and methods are shown inside 1774 # the class node. If there are many fields or methods and many nodes the 1775 # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 1776 # threshold limits the number of items for each type to make the size more 1777 # manageable. Set this to 0 for no limit. Note that the threshold may be 1778 # exceeded by 50% before the limit is enforced. 1779 1780 UML_LIMIT_NUM_FIELDS = 10 1428 1781 1429 1782 # If set to YES, the inheritance and collaboration graphs will show the … … 1463 1816 1464 1817 # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 1465 # will g raphical hierarchy of all classes instead of a textual one.1818 # will generate a graphical hierarchy of all classes instead of a textual one. 1466 1819 1467 1820 GRAPHICAL_HIERARCHY = YES 1468 1821 1469 # If the DIRECTORY_GRAPH , SHOW_DIRECTORIESand HAVE_DOT tags are set to YES1822 # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES 1470 1823 # then doxygen will show the dependencies a directory has on other directories 1471 1824 # in a graphical way. The dependency relations are determined by the #include … … 1475 1828 1476 1829 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 1477 # generated by dot. Possible values are png, jpg, or gif 1478 # If left blank png will be used. 1830 # generated by dot. Possible values are svg, png, jpg, or gif. 1831 # If left blank png will be used. If you choose svg you need to set 1832 # HTML_FILE_EXTENSION to xhtml in order to make the SVG files 1833 # visible in IE 9+ (other browsers do not have this requirement). 1479 1834 1480 1835 DOT_IMAGE_FORMAT = png 1836 1837 # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 1838 # enable generation of interactive SVG images that allow zooming and panning. 1839 # Note that this requires a modern browser other than Internet Explorer. 1840 # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 1841 # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 1842 # visible. Older versions of IE do not have SVG support. 1843 1844 INTERACTIVE_SVG = NO 1481 1845 1482 1846 # The tag DOT_PATH can be used to specify the path where the dot tool can be … … 1490 1854 1491 1855 DOTFILE_DIRS = 1856 1857 # The MSCFILE_DIRS tag can be used to specify one or more directories that 1858 # contain msc files that are included in the documentation (see the 1859 # \mscfile command). 1860 1861 MSCFILE_DIRS = 1492 1862 1493 1863 # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -
vendor/current/lib/tevent/pytevent.c
r740 r988 24 24 25 25 #include <Python.h> 26 #include "replace.h" 26 27 #include <tevent.h> 28 29 #if PY_MAJOR_VERSION >= 3 30 #define PyStr_Check PyUnicode_Check 31 #define PyStr_FromString PyUnicode_FromString 32 #define PyStr_AsUTF8 PyUnicode_AsUTF8 33 #define PyInt_FromLong PyLong_FromLong 34 #else 35 #define PyStr_Check PyString_Check 36 #define PyStr_FromString PyString_FromString 37 #define PyStr_AsUTF8 PyString_AsString 38 #endif 39 40 void init_tevent(void); 27 41 28 42 typedef struct { … … 49 63 PyObject_HEAD 50 64 struct tevent_timer *timer; 65 PyObject *callback; 51 66 } TeventTimer_Object; 52 67 … … 56 71 } TeventFd_Object; 57 72 58 static forwardPyTypeObject TeventContext_Type;59 static forwardPyTypeObject TeventReq_Type;60 static forwardPyTypeObject TeventQueue_Type;61 static forwardPyTypeObject TeventSignal_Type;62 static forwardPyTypeObject TeventTimer_Type;63 static forwardPyTypeObject TeventFd_Type;73 static PyTypeObject TeventContext_Type; 74 static PyTypeObject TeventReq_Type; 75 static PyTypeObject TeventQueue_Type; 76 static PyTypeObject TeventSignal_Type; 77 static PyTypeObject TeventTimer_Type; 78 static PyTypeObject TeventFd_Type; 64 79 65 80 static int py_context_init(struct tevent_context *ev) … … 87 102 } 88 103 89 uint16_t py_get_fd_flags(struct tevent_fd *fde)104 static uint16_t py_get_fd_flags(struct tevent_fd *fde) 90 105 { 91 106 /* FIXME */ … … 174 189 } 175 190 176 if (!PyStr ing_Check(name)) {191 if (!PyStr_Check(name)) { 177 192 PyErr_SetNone(PyExc_TypeError); 178 return NULL; 179 } 180 181 if (!tevent_register_backend(PyString_AsString(name), &py_tevent_ops)) { /* FIXME: What to do with backend */ 193 Py_DECREF(name); 194 return NULL; 195 } 196 197 if (!tevent_register_backend(PyStr_AsUTF8(name), &py_tevent_ops)) { /* FIXME: What to do with backend */ 182 198 PyErr_SetNone(PyExc_RuntimeError); 183 return NULL; 184 } 199 Py_DECREF(name); 200 return NULL; 201 } 202 203 Py_DECREF(name); 185 204 186 205 Py_RETURN_NONE; … … 213 232 PyObject *callback = private_data, *ret; 214 233 215 ret = PyObject_CallFunction(callback, "");234 ret = PyObject_CallFunction(callback, discard_const_p(char, "")); 216 235 Py_XDECREF(ret); 217 236 } … … 278 297 } 279 298 280 #ifdef TEVENT_DEPRECATED281 static bool py_tevent_finished(PyObject *callback)282 {283 PyObject *py_ret;284 bool ret;285 286 py_ret = PyObject_CallFunction(callback, "");287 if (py_ret == NULL)288 return true;289 ret = PyObject_IsTrue(py_ret);290 Py_DECREF(py_ret);291 return ret;292 }293 294 static PyObject *py_tevent_context_loop_until(TeventContext_Object *self, PyObject *args)295 {296 PyObject *callback;297 if (!PyArg_ParseTuple(args, "O", &callback))298 return NULL;299 300 if (tevent_loop_until(self->ev, py_tevent_finished, callback) != 0) {301 PyErr_SetNone(PyExc_RuntimeError);302 return NULL;303 }304 305 if (PyErr_Occurred())306 return NULL;307 308 Py_RETURN_NONE;309 }310 #endif311 312 299 static void py_tevent_signal_handler(struct tevent_context *ev, 313 300 struct tevent_signal *se, … … 319 306 PyObject *callback = (PyObject *)private_data, *ret; 320 307 321 ret = PyObject_CallFunction(callback, "ii", signum, count);308 ret = PyObject_CallFunction(callback, discard_const_p(char, "ii"), signum, count); 322 309 Py_XDECREF(ret); 323 310 } … … 330 317 331 318 static PyTypeObject TeventSignal_Type = { 332 .tp_name = " Signal",319 .tp_name = "tevent.Signal", 333 320 .tp_basicsize = sizeof(TeventSignal_Object), 334 321 .tp_dealloc = (destructor)py_tevent_signal_dealloc, … … 367 354 void *private_data) 368 355 { 369 PyObject *callback = private_data, *ret; 370 ret = PyObject_CallFunction(callback, "l", te); 356 TeventTimer_Object *self = private_data; 357 PyObject *ret; 358 359 ret = PyObject_CallFunction(self->callback, discard_const_p(char, "l"), te); 360 if (ret == NULL) { 361 /* No Python stack to propagate exception to; just print traceback */ 362 PyErr_PrintEx(0); 363 } 371 364 Py_XDECREF(ret); 372 365 } 373 366 374 static PyObject *py_tevent_context_add_timer(TeventContext_Object *self, PyObject *args) 375 { 367 static void py_tevent_timer_dealloc(TeventTimer_Object *self) 368 { 369 if (self->timer) { 370 talloc_free(self->timer); 371 } 372 Py_DECREF(self->callback); 373 PyObject_Del(self); 374 } 375 376 static int py_tevent_timer_traverse(TeventTimer_Object *self, visitproc visit, void *arg) 377 { 378 Py_VISIT(self->callback); 379 return 0; 380 } 381 382 static PyObject* py_tevent_timer_get_active(TeventTimer_Object *self) { 383 return PyBool_FromLong(self->timer != NULL); 384 } 385 386 struct PyGetSetDef py_tevent_timer_getset[] = { 387 { 388 .name = discard_const_p(char, "active"), 389 .get = (getter)py_tevent_timer_get_active, 390 .doc = discard_const_p(char, "true if the timer is scheduled to run"), 391 }, 392 {NULL}, 393 }; 394 395 static PyTypeObject TeventTimer_Type = { 396 .tp_name = "tevent.Timer", 397 .tp_basicsize = sizeof(TeventTimer_Object), 398 .tp_dealloc = (destructor)py_tevent_timer_dealloc, 399 .tp_traverse = (traverseproc)py_tevent_timer_traverse, 400 .tp_getset = py_tevent_timer_getset, 401 .tp_flags = Py_TPFLAGS_DEFAULT, 402 }; 403 404 struct TeventTimer_Object_ref { 405 TeventTimer_Object *obj; 406 }; 407 408 static int TeventTimer_Object_ref_destructor(struct TeventTimer_Object_ref *ref) 409 { 410 ref->obj->timer = NULL; 411 Py_DECREF(ref->obj); 412 return 0; 413 } 414 415 static PyObject *py_tevent_context_add_timer_internal(TeventContext_Object *self, 416 struct timeval next_event, 417 PyObject *callback) 418 { 419 /* Ownership notes: 420 * 421 * There are 5 pieces in play; two tevent contexts and 3 Python objects: 422 * - The tevent timer 423 * - The tevent context 424 * - The Python context -- "self" 425 * - The Python timer (TeventTimer_Object) -- "ret" 426 * - The Python callback function -- "callback" 427 * 428 * We only use the Python context for getting the tevent context, 429 * afterwards it can be destroyed. 430 * 431 * The tevent context owns the tevent timer. 432 * 433 * The tevent timer holds a reference to the Python timer, so the Python 434 * timer must always outlive the tevent timer. 435 * The Python timer has a pointer to the tevent timer; a destructor is 436 * used to set this to NULL when the tevent timer is deallocated. 437 * 438 * The tevent timer can be deallocated in these cases: 439 * 1) when the context is destroyed 440 * 2) after the event fires 441 * Posssibly, API might be added to cancel (free the tevent timer). 442 * 443 * The Python timer holds a reference to the callback. 444 */ 376 445 TeventTimer_Object *ret; 377 struct timeval next_event; 378 struct tevent_timer *timer; 379 PyObject *handler; 380 if (!PyArg_ParseTuple(args, "lO", &next_event, &handler)) 381 return NULL; 382 383 timer = tevent_add_timer(self->ev, NULL, next_event, py_timer_handler, 384 handler); 385 if (timer == NULL) { 386 PyErr_SetNone(PyExc_RuntimeError); 387 return NULL; 388 } 446 struct TeventTimer_Object_ref *ref; 389 447 390 448 ret = PyObject_New(TeventTimer_Object, &TeventTimer_Type); 391 449 if (ret == NULL) { 392 450 PyErr_NoMemory(); 393 talloc_free(timer); 394 return NULL; 395 } 396 ret->timer = timer; 451 return NULL; 452 } 453 Py_INCREF(callback); 454 ret->callback = callback; 455 ret->timer = tevent_add_timer(self->ev, NULL, next_event, py_timer_handler, 456 ret); 457 if (ret->timer == NULL) { 458 Py_DECREF(ret); 459 PyErr_SetString(PyExc_RuntimeError, "Could not initialize timer"); 460 return NULL; 461 } 462 ref = talloc(ret->timer, struct TeventTimer_Object_ref); 463 if (ref == NULL) { 464 talloc_free(ret->timer); 465 Py_DECREF(ret); 466 PyErr_SetString(PyExc_RuntimeError, "Could not initialize timer"); 467 return NULL; 468 } 469 Py_INCREF(ret); 470 ref->obj = ret; 471 472 talloc_set_destructor(ref, TeventTimer_Object_ref_destructor); 397 473 398 474 return (PyObject *)ret; 475 } 476 477 static PyObject *py_tevent_context_add_timer(TeventContext_Object *self, PyObject *args) 478 { 479 struct timeval next_event; 480 PyObject *callback; 481 if (!PyArg_ParseTuple(args, "lO", &next_event, &callback)) 482 return NULL; 483 484 return py_tevent_context_add_timer_internal(self, next_event, callback); 485 } 486 487 static PyObject *py_tevent_context_add_timer_offset(TeventContext_Object *self, PyObject *args) 488 { 489 struct timeval next_event; 490 double offset; 491 int seconds; 492 PyObject *callback; 493 if (!PyArg_ParseTuple(args, "dO", &offset, &callback)) 494 return NULL; 495 496 seconds = offset; 497 offset -= seconds; 498 next_event = tevent_timeval_current_ofs(seconds, (int)(offset*1000000)); 499 return py_tevent_context_add_timer_internal(self, next_event, callback); 399 500 } 400 501 … … 406 507 PyObject *callback = private_data, *ret; 407 508 408 ret = PyObject_CallFunction(callback, "i", flags);509 ret = PyObject_CallFunction(callback, discard_const_p(char, "i"), flags); 409 510 Py_XDECREF(ret); 410 511 } 512 513 static void py_tevent_fp_dealloc(TeventFd_Object *self) 514 { 515 talloc_free(self->fd); 516 PyObject_Del(self); 517 } 518 519 static PyTypeObject TeventFd_Type = { 520 .tp_name = "tevent.Fd", 521 .tp_basicsize = sizeof(TeventFd_Object), 522 .tp_dealloc = (destructor)py_tevent_fp_dealloc, 523 .tp_flags = Py_TPFLAGS_DEFAULT, 524 }; 411 525 412 526 static PyObject *py_tevent_context_add_fd(TeventContext_Object *self, PyObject *args) … … 435 549 return (PyObject *)ret; 436 550 } 437 438 #ifdef TEVENT_DEPRECATED439 static PyObject *py_tevent_context_set_allow_nesting(TeventContext_Object *self)440 {441 tevent_loop_allow_nesting(self->ev);442 Py_RETURN_NONE;443 }444 #endif445 551 446 552 static PyMethodDef py_tevent_context_methods[] = { … … 453 559 { "loop_once", (PyCFunction)py_tevent_context_loop_once, 454 560 METH_NOARGS, "S.loop_once()" }, 455 #ifdef TEVENT_DEPRECATED456 { "loop_until", (PyCFunction)py_tevent_context_loop_until,457 METH_VARARGS, "S.loop_until(callback)" },458 #endif459 561 { "add_signal", (PyCFunction)py_tevent_context_add_signal, 460 562 METH_VARARGS, "S.add_signal(signum, sa_flags, handler) -> signal" }, 461 563 { "add_timer", (PyCFunction)py_tevent_context_add_timer, 462 564 METH_VARARGS, "S.add_timer(next_event, handler) -> timer" }, 565 { "add_timer_offset", (PyCFunction)py_tevent_context_add_timer_offset, 566 METH_VARARGS, "S.add_timer(offset_seconds, handler) -> timer" }, 463 567 { "add_fd", (PyCFunction)py_tevent_context_add_fd, 464 568 METH_VARARGS, "S.add_fd(fd, flags, handler) -> fd" }, 465 #ifdef TEVENT_DEPRECATED466 { "allow_nesting", (PyCFunction)py_tevent_context_set_allow_nesting,467 METH_NOARGS, "Whether to allow nested tevent loops." },468 #endif469 569 { NULL }, 470 570 }; … … 501 601 502 602 static PyGetSetDef py_tevent_req_getsetters[] = { 503 { "in_progress", (getter)py_tevent_req_is_in_progress, NULL, 504 "Whether the request is in progress" }, 603 { 604 .name = discard_const_p(char, "in_progress"), 605 .get = (getter)py_tevent_req_is_in_progress, 606 .doc = discard_const_p(char, "Whether the request is in progress"), 607 }, 505 608 { NULL } 506 609 }; … … 590 693 591 694 static PyGetSetDef py_tevent_queue_getsetters[] = { 592 { "length", (getter)py_tevent_queue_get_length, 593 NULL, "The number of elements in the queue." }, 695 { 696 .name = discard_const_p(char, "length"), 697 .get = (getter)py_tevent_queue_get_length, 698 .doc = discard_const_p(char, "The number of elements in the queue."), 699 }, 594 700 { NULL }, 595 701 }; … … 617 723 618 724 static PyGetSetDef py_tevent_context_getsetters[] = { 619 { "signal_support", (getter)py_tevent_context_signal_support, 620 NULL, "if this platform and tevent context support signal handling" }, 725 { 726 .name = discard_const_p(char, "signal_support"), 727 .get = (getter)py_tevent_context_signal_support, 728 .doc = discard_const_p(char, "if this platform and tevent context support signal handling"), 729 }, 621 730 { NULL } 622 731 }; … … 635 744 TeventContext_Object *ret; 636 745 637 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwnames, &name))746 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", discard_const_p(char *, kwnames), &name)) 638 747 return NULL; 639 748 … … 661 770 662 771 static PyTypeObject TeventContext_Type = { 663 .tp_name = " _tevent.Context",772 .tp_name = "tevent.Context", 664 773 .tp_new = py_tevent_context_new, 665 774 .tp_basicsize = sizeof(TeventContext_Object), … … 683 792 static PyObject *py_backend_list(PyObject *self) 684 793 { 685 PyObject *ret; 686 int i; 687 const char **backends; 794 PyObject *ret = NULL; 795 PyObject *string = NULL; 796 int i, result; 797 const char **backends = NULL; 688 798 689 799 ret = PyList_New(0); … … 695 805 if (backends == NULL) { 696 806 PyErr_SetNone(PyExc_RuntimeError); 697 Py_DECREF(ret); 698 return NULL; 807 goto err; 699 808 } 700 809 for (i = 0; backends[i]; i++) { 701 PyList_Append(ret, PyString_FromString(backends[i])); 810 string = PyStr_FromString(backends[i]); 811 if (!string) { 812 goto err; 813 } 814 result = PyList_Append(ret, string); 815 if (result) { 816 goto err; 817 } 818 Py_DECREF(string); 819 string = NULL; 702 820 } 703 821 … … 705 823 706 824 return ret; 825 826 err: 827 Py_XDECREF(ret); 828 Py_XDECREF(string); 829 talloc_free(backends); 830 return NULL; 707 831 } 708 832 … … 717 841 }; 718 842 719 void init_tevent(void) 843 #define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.") 844 845 #if PY_MAJOR_VERSION >= 3 846 static struct PyModuleDef moduledef = { 847 PyModuleDef_HEAD_INIT, 848 .m_name = "_tevent", 849 .m_doc = MODULE_DOC, 850 .m_size = -1, 851 .m_methods = tevent_methods, 852 }; 853 #endif 854 855 PyObject * module_init(void); 856 PyObject * module_init(void) 720 857 { 721 858 PyObject *m; 722 859 723 860 if (PyType_Ready(&TeventContext_Type) < 0) 724 return ;861 return NULL; 725 862 726 863 if (PyType_Ready(&TeventQueue_Type) < 0) 727 return ;864 return NULL; 728 865 729 866 if (PyType_Ready(&TeventReq_Type) < 0) 730 return ;867 return NULL; 731 868 732 869 if (PyType_Ready(&TeventSignal_Type) < 0) 733 return ;870 return NULL; 734 871 735 872 if (PyType_Ready(&TeventTimer_Type) < 0) 736 return ;873 return NULL; 737 874 738 875 if (PyType_Ready(&TeventFd_Type) < 0) 739 return; 740 741 m = Py_InitModule3("_tevent", tevent_methods, "Tevent integration for twisted."); 876 return NULL; 877 878 #if PY_MAJOR_VERSION >= 3 879 m = PyModule_Create(&moduledef); 880 #else 881 m = Py_InitModule3("_tevent", tevent_methods, MODULE_DOC); 882 #endif 742 883 if (m == NULL) 743 return ;884 return NULL; 744 885 745 886 Py_INCREF(&TeventContext_Type); … … 760 901 Py_INCREF(&TeventFd_Type); 761 902 PyModule_AddObject(m, "Fd", (PyObject *)&TeventFd_Type); 762 } 903 904 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); 905 906 return m; 907 } 908 909 #if PY_MAJOR_VERSION >= 3 910 PyMODINIT_FUNC PyInit__tevent(void); 911 PyMODINIT_FUNC PyInit__tevent(void) 912 { 913 return module_init(); 914 } 915 #else 916 void init_tevent(void); 917 void init_tevent(void) 918 { 919 module_init(); 920 } 921 #endif -
vendor/current/lib/tevent/testsuite.c
r740 r988 5 5 6 6 Copyright (C) Stefan Metzmacher 2006-2009 7 Copyright (C) Jeremy Allison 2013 7 8 8 9 ** NOTE! The following LGPL license applies to the tevent … … 25 26 26 27 #include "includes.h" 27 #include "lib/ events/events.h"28 #include "lib/tevent/tevent.h" 28 29 #include "system/filesys.h" 30 #include "system/select.h" 31 #include "system/network.h" 29 32 #include "torture/torture.h" 33 #include "torture/local/proto.h" 34 #ifdef HAVE_PTHREAD 35 #include <pthread.h> 36 #include <assert.h> 37 #endif 30 38 31 39 static int fde_count; 32 40 33 static void fde_handler (struct tevent_context *ev_ctx, struct tevent_fd *f,41 static void fde_handler_read(struct tevent_context *ev_ctx, struct tevent_fd *f, 34 42 uint16_t flags, void *private_data) 35 43 { … … 40 48 #endif 41 49 kill(getpid(), SIGALRM); 50 42 51 read(fd[0], &c, 1); 52 fde_count++; 53 } 54 55 static void fde_handler_write(struct tevent_context *ev_ctx, struct tevent_fd *f, 56 uint16_t flags, void *private_data) 57 { 58 int *fd = (int *)private_data; 59 char c = 0; 43 60 write(fd[1], &c, 1); 61 } 62 63 64 /* This will only fire if the fd's returned from pipe() are bi-directional. */ 65 static void fde_handler_read_1(struct tevent_context *ev_ctx, struct tevent_fd *f, 66 uint16_t flags, void *private_data) 67 { 68 int *fd = (int *)private_data; 69 char c; 70 #ifdef SA_SIGINFO 71 kill(getpid(), SIGUSR1); 72 #endif 73 kill(getpid(), SIGALRM); 74 75 read(fd[1], &c, 1); 44 76 fde_count++; 77 } 78 79 /* This will only fire if the fd's returned from pipe() are bi-directional. */ 80 static void fde_handler_write_1(struct tevent_context *ev_ctx, struct tevent_fd *f, 81 uint16_t flags, void *private_data) 82 { 83 int *fd = (int *)private_data; 84 char c = 0; 85 write(fd[0], &c, 1); 45 86 } 46 87 … … 52 93 } 53 94 54 static void count_handler(struct tevent_context *ev_ctx, struct signal_event*te,95 static void count_handler(struct tevent_context *ev_ctx, struct tevent_signal *te, 55 96 int signum, int count, void *info, void *private_data) 56 97 { … … 66 107 const char *backend = (const char *)test_data; 67 108 int alarm_count=0, info_count=0; 68 struct tevent_fd *fde; 109 struct tevent_fd *fde_read; 110 struct tevent_fd *fde_read_1; 111 struct tevent_fd *fde_write; 112 struct tevent_fd *fde_write_1; 69 113 #ifdef SA_RESTART 70 114 struct tevent_signal *se1 = NULL; 71 115 #endif 116 #ifdef SA_RESETHAND 72 117 struct tevent_signal *se2 = NULL; 118 #endif 73 119 #ifdef SA_SIGINFO 74 120 struct tevent_signal *se3 = NULL; … … 76 122 int finished=0; 77 123 struct timeval t; 78 char c = 0;79 80 ev_ctx = event_context_init_byname(test, backend);124 int ret; 125 126 ev_ctx = tevent_context_init_byname(test, backend); 81 127 if (ev_ctx == NULL) { 82 128 torture_comment(test, "event backend '%s' not supported\n", backend); … … 84 130 } 85 131 86 torture_comment(test, "Testing event backend '%s'\n", backend); 132 torture_comment(test, "backend '%s' - %s\n", 133 backend, __FUNCTION__); 87 134 88 135 /* reset globals */ … … 90 137 91 138 /* create a pipe */ 92 pipe(fd); 93 94 fde = event_add_fd(ev_ctx, ev_ctx, fd[0], EVENT_FD_READ, 95 fde_handler, fd); 96 tevent_fd_set_auto_close(fde); 97 98 event_add_timed(ev_ctx, ev_ctx, timeval_current_ofs(2,0), 99 finished_handler, &finished); 139 ret = pipe(fd); 140 torture_assert_int_equal(test, ret, 0, "pipe failed"); 141 142 fde_read = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ, 143 fde_handler_read, fd); 144 fde_write_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_WRITE, 145 fde_handler_write_1, fd); 146 147 fde_write = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_WRITE, 148 fde_handler_write, fd); 149 fde_read_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_READ, 150 fde_handler_read_1, fd); 151 152 tevent_fd_set_auto_close(fde_read); 153 tevent_fd_set_auto_close(fde_write); 154 155 tevent_add_timer(ev_ctx, ev_ctx, timeval_current_ofs(2,0), 156 finished_handler, &finished); 100 157 101 158 #ifdef SA_RESTART 102 se1 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count); 159 se1 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count); 160 torture_assert(test, se1 != NULL, "failed to setup se1"); 103 161 #endif 104 162 #ifdef SA_RESETHAND 105 se2 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count); 163 se2 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count); 164 torture_assert(test, se2 != NULL, "failed to setup se2"); 106 165 #endif 107 166 #ifdef SA_SIGINFO 108 se3 = event_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count); 109 #endif 110 111 write(fd[1], &c, 1); 167 se3 = tevent_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count); 168 torture_assert(test, se3 != NULL, "failed to setup se3"); 169 #endif 112 170 113 171 t = timeval_current(); 114 172 while (!finished) { 115 173 errno = 0; 116 if ( event_loop_once(ev_ctx) == -1) {174 if (tevent_loop_once(ev_ctx) == -1) { 117 175 talloc_free(ev_ctx); 118 176 torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno))); … … 120 178 } 121 179 122 talloc_free(fde); 123 close(fd[1]); 180 talloc_free(fde_read_1); 181 talloc_free(fde_write_1); 182 talloc_free(fde_read); 183 talloc_free(fde_write); 124 184 125 185 while (alarm_count < fde_count+1) { 126 if ( event_loop_once(ev_ctx) == -1) {186 if (tevent_loop_once(ev_ctx) == -1) { 127 187 break; 128 188 } … … 136 196 137 197 torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch"); 198 199 #ifdef SA_RESETHAND 200 /* 201 * we do not call talloc_free(se2) 202 * because it is already gone, 203 * after triggering the event handler. 204 */ 205 #endif 138 206 139 207 #ifdef SA_SIGINFO … … 147 215 } 148 216 217 struct test_event_fd1_state { 218 struct torture_context *tctx; 219 const char *backend; 220 struct tevent_context *ev; 221 int sock[2]; 222 struct tevent_timer *te; 223 struct tevent_fd *fde0; 224 struct tevent_fd *fde1; 225 bool got_write; 226 bool got_read; 227 bool drain; 228 bool drain_done; 229 unsigned loop_count; 230 bool finished; 231 const char *error; 232 }; 233 234 static void test_event_fd1_fde_handler(struct tevent_context *ev_ctx, 235 struct tevent_fd *fde, 236 uint16_t flags, 237 void *private_data) 238 { 239 struct test_event_fd1_state *state = 240 (struct test_event_fd1_state *)private_data; 241 242 if (state->drain_done) { 243 state->finished = true; 244 state->error = __location__; 245 return; 246 } 247 248 if (state->drain) { 249 ssize_t ret; 250 uint8_t c = 0; 251 252 if (!(flags & TEVENT_FD_READ)) { 253 state->finished = true; 254 state->error = __location__; 255 return; 256 } 257 258 ret = read(state->sock[0], &c, 1); 259 if (ret == 1) { 260 return; 261 } 262 263 /* 264 * end of test... 265 */ 266 tevent_fd_set_flags(fde, 0); 267 state->drain_done = true; 268 return; 269 } 270 271 if (!state->got_write) { 272 uint8_t c = 0; 273 274 if (flags != TEVENT_FD_WRITE) { 275 state->finished = true; 276 state->error = __location__; 277 return; 278 } 279 state->got_write = true; 280 281 /* 282 * we write to the other socket... 283 */ 284 write(state->sock[1], &c, 1); 285 TEVENT_FD_NOT_WRITEABLE(fde); 286 TEVENT_FD_READABLE(fde); 287 return; 288 } 289 290 if (!state->got_read) { 291 if (flags != TEVENT_FD_READ) { 292 state->finished = true; 293 state->error = __location__; 294 return; 295 } 296 state->got_read = true; 297 298 TEVENT_FD_NOT_READABLE(fde); 299 return; 300 } 301 302 state->finished = true; 303 state->error = __location__; 304 return; 305 } 306 307 static void test_event_fd1_finished(struct tevent_context *ev_ctx, 308 struct tevent_timer *te, 309 struct timeval tval, 310 void *private_data) 311 { 312 struct test_event_fd1_state *state = 313 (struct test_event_fd1_state *)private_data; 314 315 if (state->drain_done) { 316 state->finished = true; 317 return; 318 } 319 320 if (!state->got_write) { 321 state->finished = true; 322 state->error = __location__; 323 return; 324 } 325 326 if (!state->got_read) { 327 state->finished = true; 328 state->error = __location__; 329 return; 330 } 331 332 state->loop_count++; 333 if (state->loop_count > 3) { 334 state->finished = true; 335 state->error = __location__; 336 return; 337 } 338 339 state->got_write = false; 340 state->got_read = false; 341 342 tevent_fd_set_flags(state->fde0, TEVENT_FD_WRITE); 343 344 if (state->loop_count > 2) { 345 state->drain = true; 346 TALLOC_FREE(state->fde1); 347 TEVENT_FD_READABLE(state->fde0); 348 } 349 350 state->te = tevent_add_timer(state->ev, state->ev, 351 timeval_current_ofs(0,2000), 352 test_event_fd1_finished, state); 353 } 354 355 static bool test_event_fd1(struct torture_context *tctx, 356 const void *test_data) 357 { 358 struct test_event_fd1_state state; 359 360 ZERO_STRUCT(state); 361 state.tctx = tctx; 362 state.backend = (const char *)test_data; 363 364 state.ev = tevent_context_init_byname(tctx, state.backend); 365 if (state.ev == NULL) { 366 torture_skip(tctx, talloc_asprintf(tctx, 367 "event backend '%s' not supported\n", 368 state.backend)); 369 return true; 370 } 371 372 tevent_set_debug_stderr(state.ev); 373 torture_comment(tctx, "backend '%s' - %s\n", 374 state.backend, __FUNCTION__); 375 376 /* 377 * This tests the following: 378 * 379 * It monitors the state of state.sock[0] 380 * with tevent_fd, but we never read/write on state.sock[0] 381 * while state.sock[1] * is only used to write a few bytes. 382 * 383 * We have a loop: 384 * - we wait only for TEVENT_FD_WRITE on state.sock[0] 385 * - we write 1 byte to state.sock[1] 386 * - we wait only for TEVENT_FD_READ on state.sock[0] 387 * - we disable events on state.sock[0] 388 * - the timer event restarts the loop 389 * Then we close state.sock[1] 390 * We have a loop: 391 * - we wait for TEVENT_FD_READ/WRITE on state.sock[0] 392 * - we try to read 1 byte 393 * - if the read gets an error of returns 0 394 * we disable the event handler 395 * - the timer finishes the test 396 */ 397 state.sock[0] = -1; 398 state.sock[1] = -1; 399 socketpair(AF_UNIX, SOCK_STREAM, 0, state.sock); 400 401 state.te = tevent_add_timer(state.ev, state.ev, 402 timeval_current_ofs(0,1000), 403 test_event_fd1_finished, &state); 404 state.fde0 = tevent_add_fd(state.ev, state.ev, 405 state.sock[0], TEVENT_FD_WRITE, 406 test_event_fd1_fde_handler, &state); 407 /* state.fde1 is only used to auto close */ 408 state.fde1 = tevent_add_fd(state.ev, state.ev, 409 state.sock[1], 0, 410 test_event_fd1_fde_handler, &state); 411 412 tevent_fd_set_auto_close(state.fde0); 413 tevent_fd_set_auto_close(state.fde1); 414 415 while (!state.finished) { 416 errno = 0; 417 if (tevent_loop_once(state.ev) == -1) { 418 talloc_free(state.ev); 419 torture_fail(tctx, talloc_asprintf(tctx, 420 "Failed event loop %s\n", 421 strerror(errno))); 422 } 423 } 424 425 talloc_free(state.ev); 426 427 torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx, 428 "%s", state.error)); 429 430 return true; 431 } 432 433 struct test_event_fd2_state { 434 struct torture_context *tctx; 435 const char *backend; 436 struct tevent_context *ev; 437 struct tevent_timer *te; 438 struct test_event_fd2_sock { 439 struct test_event_fd2_state *state; 440 int fd; 441 struct tevent_fd *fde; 442 size_t num_written; 443 size_t num_read; 444 bool got_full; 445 } sock0, sock1; 446 bool finished; 447 const char *error; 448 }; 449 450 static void test_event_fd2_sock_handler(struct tevent_context *ev_ctx, 451 struct tevent_fd *fde, 452 uint16_t flags, 453 void *private_data) 454 { 455 struct test_event_fd2_sock *cur_sock = 456 (struct test_event_fd2_sock *)private_data; 457 struct test_event_fd2_state *state = cur_sock->state; 458 struct test_event_fd2_sock *oth_sock = NULL; 459 uint8_t v = 0, c; 460 ssize_t ret; 461 462 if (cur_sock == &state->sock0) { 463 oth_sock = &state->sock1; 464 } else { 465 oth_sock = &state->sock0; 466 } 467 468 if (oth_sock->num_written == 1) { 469 if (flags != (TEVENT_FD_READ | TEVENT_FD_WRITE)) { 470 state->finished = true; 471 state->error = __location__; 472 return; 473 } 474 } 475 476 if (cur_sock->num_read == oth_sock->num_written) { 477 state->finished = true; 478 state->error = __location__; 479 return; 480 } 481 482 if (!(flags & TEVENT_FD_READ)) { 483 state->finished = true; 484 state->error = __location__; 485 return; 486 } 487 488 if (oth_sock->num_read >= PIPE_BUF) { 489 /* 490 * On Linux we become writable once we've read 491 * one byte. On Solaris we only become writable 492 * again once we've read 4096 bytes. PIPE_BUF 493 * is probably a safe bet to test against. 494 * 495 * There should be room to write a byte again 496 */ 497 if (!(flags & TEVENT_FD_WRITE)) { 498 state->finished = true; 499 state->error = __location__; 500 return; 501 } 502 } 503 504 if ((flags & TEVENT_FD_WRITE) && !cur_sock->got_full) { 505 v = (uint8_t)cur_sock->num_written; 506 ret = write(cur_sock->fd, &v, 1); 507 if (ret != 1) { 508 state->finished = true; 509 state->error = __location__; 510 return; 511 } 512 cur_sock->num_written++; 513 if (cur_sock->num_written > 0x80000000) { 514 state->finished = true; 515 state->error = __location__; 516 return; 517 } 518 return; 519 } 520 521 if (!cur_sock->got_full) { 522 cur_sock->got_full = true; 523 524 if (!oth_sock->got_full) { 525 /* 526 * cur_sock is full, 527 * lets wait for oth_sock 528 * to be filled 529 */ 530 tevent_fd_set_flags(cur_sock->fde, 0); 531 return; 532 } 533 534 /* 535 * oth_sock waited for cur_sock, 536 * lets restart it 537 */ 538 tevent_fd_set_flags(oth_sock->fde, 539 TEVENT_FD_READ|TEVENT_FD_WRITE); 540 } 541 542 ret = read(cur_sock->fd, &v, 1); 543 if (ret != 1) { 544 state->finished = true; 545 state->error = __location__; 546 return; 547 } 548 c = (uint8_t)cur_sock->num_read; 549 if (c != v) { 550 state->finished = true; 551 state->error = __location__; 552 return; 553 } 554 cur_sock->num_read++; 555 556 if (cur_sock->num_read < oth_sock->num_written) { 557 /* there is more to read */ 558 return; 559 } 560 /* 561 * we read everything, we need to remove TEVENT_FD_WRITE 562 * to avoid spinning 563 */ 564 TEVENT_FD_NOT_WRITEABLE(cur_sock->fde); 565 566 if (oth_sock->num_read == cur_sock->num_written) { 567 /* 568 * both directions are finished 569 */ 570 state->finished = true; 571 } 572 573 return; 574 } 575 576 static void test_event_fd2_finished(struct tevent_context *ev_ctx, 577 struct tevent_timer *te, 578 struct timeval tval, 579 void *private_data) 580 { 581 struct test_event_fd2_state *state = 582 (struct test_event_fd2_state *)private_data; 583 584 /* 585 * this should never be triggered 586 */ 587 state->finished = true; 588 state->error = __location__; 589 } 590 591 static bool test_event_fd2(struct torture_context *tctx, 592 const void *test_data) 593 { 594 struct test_event_fd2_state state; 595 int sock[2]; 596 uint8_t c = 0; 597 598 ZERO_STRUCT(state); 599 state.tctx = tctx; 600 state.backend = (const char *)test_data; 601 602 state.ev = tevent_context_init_byname(tctx, state.backend); 603 if (state.ev == NULL) { 604 torture_skip(tctx, talloc_asprintf(tctx, 605 "event backend '%s' not supported\n", 606 state.backend)); 607 return true; 608 } 609 610 tevent_set_debug_stderr(state.ev); 611 torture_comment(tctx, "backend '%s' - %s\n", 612 state.backend, __FUNCTION__); 613 614 /* 615 * This tests the following 616 * 617 * - We write 1 byte to each socket 618 * - We wait for TEVENT_FD_READ/WRITE on both sockets 619 * - When we get TEVENT_FD_WRITE we write 1 byte 620 * until both socket buffers are full, which 621 * means both sockets only get TEVENT_FD_READ. 622 * - Then we read 1 byte until we have consumed 623 * all bytes the other end has written. 624 */ 625 sock[0] = -1; 626 sock[1] = -1; 627 socketpair(AF_UNIX, SOCK_STREAM, 0, sock); 628 629 /* 630 * the timer should never expire 631 */ 632 state.te = tevent_add_timer(state.ev, state.ev, 633 timeval_current_ofs(600, 0), 634 test_event_fd2_finished, &state); 635 state.sock0.state = &state; 636 state.sock0.fd = sock[0]; 637 state.sock0.fde = tevent_add_fd(state.ev, state.ev, 638 state.sock0.fd, 639 TEVENT_FD_READ | TEVENT_FD_WRITE, 640 test_event_fd2_sock_handler, 641 &state.sock0); 642 state.sock1.state = &state; 643 state.sock1.fd = sock[1]; 644 state.sock1.fde = tevent_add_fd(state.ev, state.ev, 645 state.sock1.fd, 646 TEVENT_FD_READ | TEVENT_FD_WRITE, 647 test_event_fd2_sock_handler, 648 &state.sock1); 649 650 tevent_fd_set_auto_close(state.sock0.fde); 651 tevent_fd_set_auto_close(state.sock1.fde); 652 653 write(state.sock0.fd, &c, 1); 654 state.sock0.num_written++; 655 write(state.sock1.fd, &c, 1); 656 state.sock1.num_written++; 657 658 while (!state.finished) { 659 errno = 0; 660 if (tevent_loop_once(state.ev) == -1) { 661 talloc_free(state.ev); 662 torture_fail(tctx, talloc_asprintf(tctx, 663 "Failed event loop %s\n", 664 strerror(errno))); 665 } 666 } 667 668 talloc_free(state.ev); 669 670 torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx, 671 "%s", state.error)); 672 673 return true; 674 } 675 676 #ifdef HAVE_PTHREAD 677 678 static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER; 679 static bool do_shutdown = false; 680 681 static void test_event_threaded_lock(void) 682 { 683 int ret; 684 ret = pthread_mutex_lock(&threaded_mutex); 685 assert(ret == 0); 686 } 687 688 static void test_event_threaded_unlock(void) 689 { 690 int ret; 691 ret = pthread_mutex_unlock(&threaded_mutex); 692 assert(ret == 0); 693 } 694 695 static void test_event_threaded_trace(enum tevent_trace_point point, 696 void *private_data) 697 { 698 switch (point) { 699 case TEVENT_TRACE_BEFORE_WAIT: 700 test_event_threaded_unlock(); 701 break; 702 case TEVENT_TRACE_AFTER_WAIT: 703 test_event_threaded_lock(); 704 break; 705 case TEVENT_TRACE_BEFORE_LOOP_ONCE: 706 case TEVENT_TRACE_AFTER_LOOP_ONCE: 707 break; 708 } 709 } 710 711 static void test_event_threaded_timer(struct tevent_context *ev, 712 struct tevent_timer *te, 713 struct timeval current_time, 714 void *private_data) 715 { 716 return; 717 } 718 719 static void *test_event_poll_thread(void *private_data) 720 { 721 struct tevent_context *ev = (struct tevent_context *)private_data; 722 723 test_event_threaded_lock(); 724 725 while (true) { 726 int ret; 727 ret = tevent_loop_once(ev); 728 assert(ret == 0); 729 if (do_shutdown) { 730 test_event_threaded_unlock(); 731 return NULL; 732 } 733 } 734 735 } 736 737 static void test_event_threaded_read_handler(struct tevent_context *ev, 738 struct tevent_fd *fde, 739 uint16_t flags, 740 void *private_data) 741 { 742 int *pfd = (int *)private_data; 743 char c; 744 ssize_t nread; 745 746 if ((flags & TEVENT_FD_READ) == 0) { 747 return; 748 } 749 750 do { 751 nread = read(*pfd, &c, 1); 752 } while ((nread == -1) && (errno == EINTR)); 753 754 assert(nread == 1); 755 } 756 757 static bool test_event_context_threaded(struct torture_context *test, 758 const void *test_data) 759 { 760 struct tevent_context *ev; 761 struct tevent_timer *te; 762 struct tevent_fd *fde; 763 pthread_t poll_thread; 764 int fds[2]; 765 int ret; 766 char c = 0; 767 768 ev = tevent_context_init_byname(test, "poll_mt"); 769 torture_assert(test, ev != NULL, "poll_mt not supported"); 770 771 tevent_set_trace_callback(ev, test_event_threaded_trace, NULL); 772 773 te = tevent_add_timer(ev, ev, timeval_current_ofs(5, 0), 774 test_event_threaded_timer, NULL); 775 torture_assert(test, te != NULL, "Could not add timer"); 776 777 ret = pthread_create(&poll_thread, NULL, test_event_poll_thread, ev); 778 torture_assert(test, ret == 0, "Could not create poll thread"); 779 780 ret = pipe(fds); 781 torture_assert(test, ret == 0, "Could not create pipe"); 782 783 poll(NULL, 0, 100); 784 785 test_event_threaded_lock(); 786 787 fde = tevent_add_fd(ev, ev, fds[0], TEVENT_FD_READ, 788 test_event_threaded_read_handler, &fds[0]); 789 torture_assert(test, fde != NULL, "Could not add fd event"); 790 791 test_event_threaded_unlock(); 792 793 poll(NULL, 0, 100); 794 795 write(fds[1], &c, 1); 796 797 poll(NULL, 0, 100); 798 799 test_event_threaded_lock(); 800 do_shutdown = true; 801 test_event_threaded_unlock(); 802 803 write(fds[1], &c, 1); 804 805 ret = pthread_join(poll_thread, NULL); 806 torture_assert(test, ret == 0, "pthread_join failed"); 807 808 return true; 809 } 810 811 #define NUM_TEVENT_THREADS 100 812 813 /* Ugly, but needed for torture_comment... */ 814 static struct torture_context *thread_test_ctx; 815 static pthread_t thread_map[NUM_TEVENT_THREADS]; 816 static unsigned thread_counter; 817 818 /* Called in master thread context */ 819 static void callback_nowait(struct tevent_context *ev, 820 struct tevent_immediate *im, 821 void *private_ptr) 822 { 823 pthread_t *thread_id_ptr = 824 talloc_get_type_abort(private_ptr, pthread_t); 825 unsigned i; 826 827 for (i = 0; i < NUM_TEVENT_THREADS; i++) { 828 if (pthread_equal(*thread_id_ptr, 829 thread_map[i])) { 830 break; 831 } 832 } 833 torture_comment(thread_test_ctx, 834 "Callback %u from thread %u\n", 835 thread_counter, 836 i); 837 thread_counter++; 838 } 839 840 /* Blast the master tevent_context with a callback, no waiting. */ 841 static void *thread_fn_nowait(void *private_ptr) 842 { 843 struct tevent_thread_proxy *master_tp = 844 talloc_get_type_abort(private_ptr, struct tevent_thread_proxy); 845 struct tevent_immediate *im; 846 pthread_t *thread_id_ptr; 847 848 im = tevent_create_immediate(NULL); 849 if (im == NULL) { 850 return NULL; 851 } 852 thread_id_ptr = talloc(NULL, pthread_t); 853 if (thread_id_ptr == NULL) { 854 return NULL; 855 } 856 *thread_id_ptr = pthread_self(); 857 858 tevent_thread_proxy_schedule(master_tp, 859 &im, 860 callback_nowait, 861 &thread_id_ptr); 862 return NULL; 863 } 864 865 static void timeout_fn(struct tevent_context *ev, 866 struct tevent_timer *te, 867 struct timeval tv, void *p) 868 { 869 thread_counter = NUM_TEVENT_THREADS * 10; 870 } 871 872 static bool test_multi_tevent_threaded(struct torture_context *test, 873 const void *test_data) 874 { 875 unsigned i; 876 struct tevent_context *master_ev; 877 struct tevent_thread_proxy *tp; 878 879 talloc_disable_null_tracking(); 880 881 /* Ugly global stuff. */ 882 thread_test_ctx = test; 883 thread_counter = 0; 884 885 master_ev = tevent_context_init(NULL); 886 if (master_ev == NULL) { 887 return false; 888 } 889 tevent_set_debug_stderr(master_ev); 890 891 tp = tevent_thread_proxy_create(master_ev); 892 if (tp == NULL) { 893 torture_fail(test, 894 talloc_asprintf(test, 895 "tevent_thread_proxy_create failed\n")); 896 talloc_free(master_ev); 897 return false; 898 } 899 900 for (i = 0; i < NUM_TEVENT_THREADS; i++) { 901 int ret = pthread_create(&thread_map[i], 902 NULL, 903 thread_fn_nowait, 904 tp); 905 if (ret != 0) { 906 torture_fail(test, 907 talloc_asprintf(test, 908 "Failed to create thread %i, %d\n", 909 i, ret)); 910 return false; 911 } 912 } 913 914 /* Ensure we don't wait more than 10 seconds. */ 915 tevent_add_timer(master_ev, 916 master_ev, 917 timeval_current_ofs(10,0), 918 timeout_fn, 919 NULL); 920 921 while (thread_counter < NUM_TEVENT_THREADS) { 922 int ret = tevent_loop_once(master_ev); 923 torture_assert(test, ret == 0, "tevent_loop_once failed"); 924 } 925 926 torture_assert(test, thread_counter == NUM_TEVENT_THREADS, 927 "thread_counter fail\n"); 928 929 talloc_free(master_ev); 930 return true; 931 } 932 933 struct reply_state { 934 struct tevent_thread_proxy *reply_tp; 935 pthread_t thread_id; 936 int *p_finished; 937 }; 938 939 static void thread_timeout_fn(struct tevent_context *ev, 940 struct tevent_timer *te, 941 struct timeval tv, void *p) 942 { 943 int *p_finished = (int *)p; 944 945 *p_finished = 2; 946 } 947 948 /* Called in child-thread context */ 949 static void thread_callback(struct tevent_context *ev, 950 struct tevent_immediate *im, 951 void *private_ptr) 952 { 953 struct reply_state *rsp = 954 talloc_get_type_abort(private_ptr, struct reply_state); 955 956 talloc_steal(ev, rsp); 957 *rsp->p_finished = 1; 958 } 959 960 /* Called in master thread context */ 961 static void master_callback(struct tevent_context *ev, 962 struct tevent_immediate *im, 963 void *private_ptr) 964 { 965 struct reply_state *rsp = 966 talloc_get_type_abort(private_ptr, struct reply_state); 967 unsigned i; 968 969 talloc_steal(ev, rsp); 970 971 for (i = 0; i < NUM_TEVENT_THREADS; i++) { 972 if (pthread_equal(rsp->thread_id, 973 thread_map[i])) { 974 break; 975 } 976 } 977 torture_comment(thread_test_ctx, 978 "Callback %u from thread %u\n", 979 thread_counter, 980 i); 981 /* Now reply to the thread ! */ 982 tevent_thread_proxy_schedule(rsp->reply_tp, 983 &im, 984 thread_callback, 985 &rsp); 986 987 thread_counter++; 988 } 989 990 static void *thread_fn_1(void *private_ptr) 991 { 992 struct tevent_thread_proxy *master_tp = 993 talloc_get_type_abort(private_ptr, struct tevent_thread_proxy); 994 struct tevent_thread_proxy *tp; 995 struct tevent_immediate *im; 996 struct tevent_context *ev; 997 struct reply_state *rsp; 998 int finished = 0; 999 int ret; 1000 1001 ev = tevent_context_init(NULL); 1002 if (ev == NULL) { 1003 return NULL; 1004 } 1005 1006 tp = tevent_thread_proxy_create(ev); 1007 if (tp == NULL) { 1008 talloc_free(ev); 1009 return NULL; 1010 } 1011 1012 im = tevent_create_immediate(ev); 1013 if (im == NULL) { 1014 talloc_free(ev); 1015 return NULL; 1016 } 1017 1018 rsp = talloc(ev, struct reply_state); 1019 if (rsp == NULL) { 1020 talloc_free(ev); 1021 return NULL; 1022 } 1023 1024 rsp->thread_id = pthread_self(); 1025 rsp->reply_tp = tp; 1026 rsp->p_finished = &finished; 1027 1028 /* Introduce a little randomness into the mix.. */ 1029 usleep(random() % 7000); 1030 1031 tevent_thread_proxy_schedule(master_tp, 1032 &im, 1033 master_callback, 1034 &rsp); 1035 1036 /* Ensure we don't wait more than 10 seconds. */ 1037 tevent_add_timer(ev, 1038 ev, 1039 timeval_current_ofs(10,0), 1040 thread_timeout_fn, 1041 &finished); 1042 1043 while (finished == 0) { 1044 ret = tevent_loop_once(ev); 1045 assert(ret == 0); 1046 } 1047 1048 if (finished > 1) { 1049 /* Timeout ! */ 1050 abort(); 1051 } 1052 1053 /* 1054 * NB. We should talloc_free(ev) here, but if we do 1055 * we currently get hit by helgrind Fix #323432 1056 * "When calling pthread_cond_destroy or pthread_mutex_destroy 1057 * with initializers as argument Helgrind (incorrectly) reports errors." 1058 * 1059 * http://valgrind.10908.n7.nabble.com/Helgrind-3-9-0-false-positive- 1060 * with-pthread-mutex-destroy-td47757.html 1061 * 1062 * Helgrind doesn't understand that the request/reply 1063 * messages provide synchronization between the lock/unlock 1064 * in tevent_thread_proxy_schedule(), and the pthread_destroy() 1065 * when the struct tevent_thread_proxy object is talloc_free'd. 1066 * 1067 * As a work-around for now return ev for the parent thread to free. 1068 */ 1069 return ev; 1070 } 1071 1072 static bool test_multi_tevent_threaded_1(struct torture_context *test, 1073 const void *test_data) 1074 { 1075 unsigned i; 1076 struct tevent_context *master_ev; 1077 struct tevent_thread_proxy *master_tp; 1078 int ret; 1079 1080 talloc_disable_null_tracking(); 1081 1082 /* Ugly global stuff. */ 1083 thread_test_ctx = test; 1084 thread_counter = 0; 1085 1086 master_ev = tevent_context_init(NULL); 1087 if (master_ev == NULL) { 1088 return false; 1089 } 1090 tevent_set_debug_stderr(master_ev); 1091 1092 master_tp = tevent_thread_proxy_create(master_ev); 1093 if (master_tp == NULL) { 1094 torture_fail(test, 1095 talloc_asprintf(test, 1096 "tevent_thread_proxy_create failed\n")); 1097 talloc_free(master_ev); 1098 return false; 1099 } 1100 1101 for (i = 0; i < NUM_TEVENT_THREADS; i++) { 1102 ret = pthread_create(&thread_map[i], 1103 NULL, 1104 thread_fn_1, 1105 master_tp); 1106 if (ret != 0) { 1107 torture_fail(test, 1108 talloc_asprintf(test, 1109 "Failed to create thread %i, %d\n", 1110 i, ret)); 1111 return false; 1112 } 1113 } 1114 1115 while (thread_counter < NUM_TEVENT_THREADS) { 1116 ret = tevent_loop_once(master_ev); 1117 torture_assert(test, ret == 0, "tevent_loop_once failed"); 1118 } 1119 1120 /* Wait for all the threads to finish - join 'em. */ 1121 for (i = 0; i < NUM_TEVENT_THREADS; i++) { 1122 void *retval; 1123 ret = pthread_join(thread_map[i], &retval); 1124 torture_assert(test, ret == 0, "pthread_join failed"); 1125 /* Free the child thread event context. */ 1126 talloc_free(retval); 1127 } 1128 1129 talloc_free(master_ev); 1130 return true; 1131 } 1132 #endif 1133 149 1134 struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx) 150 1135 { 151 1136 struct torture_suite *suite = torture_suite_create(mem_ctx, "event"); 152 const char **list = event_backend_list(suite);1137 const char **list = tevent_backend_list(suite); 153 1138 int i; 154 1139 155 1140 for (i=0;list && list[i];i++) { 156 torture_suite_add_simple_tcase_const(suite, list[i], 1141 struct torture_suite *backend_suite; 1142 1143 backend_suite = torture_suite_create(mem_ctx, list[i]); 1144 1145 torture_suite_add_simple_tcase_const(backend_suite, 1146 "context", 157 1147 test_event_context, 158 1148 (const void *)list[i]); 159 } 1149 torture_suite_add_simple_tcase_const(backend_suite, 1150 "fd1", 1151 test_event_fd1, 1152 (const void *)list[i]); 1153 torture_suite_add_simple_tcase_const(backend_suite, 1154 "fd2", 1155 test_event_fd2, 1156 (const void *)list[i]); 1157 1158 torture_suite_add_suite(suite, backend_suite); 1159 } 1160 1161 #ifdef HAVE_PTHREAD 1162 torture_suite_add_simple_tcase_const(suite, "threaded_poll_mt", 1163 test_event_context_threaded, 1164 NULL); 1165 1166 torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded", 1167 test_multi_tevent_threaded, 1168 NULL); 1169 1170 torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded_1", 1171 test_multi_tevent_threaded_1, 1172 NULL); 1173 1174 #endif 160 1175 161 1176 return suite; -
vendor/current/lib/tevent/tevent.c
r740 r988 113 113 static void tevent_backend_init(void) 114 114 { 115 static bool done; 116 117 if (done) { 118 return; 119 } 120 121 done = true; 122 115 123 tevent_select_init(); 116 124 tevent_poll_init(); 125 tevent_poll_mt_init(); 126 #if defined(HAVE_EPOLL) 127 tevent_epoll_init(); 128 #elif defined(HAVE_SOLARIS_PORTS) 129 tevent_port_init(); 130 #endif 131 117 132 tevent_standard_init(); 118 #ifdef HAVE_EPOLL 119 tevent_epoll_init(); 120 #endif 133 } 134 135 _PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name) 136 { 137 struct tevent_ops_list *e; 138 139 tevent_backend_init(); 140 141 if (name == NULL) { 142 name = tevent_default_backend; 143 } 144 if (name == NULL) { 145 name = "standard"; 146 } 147 148 for (e = tevent_backends; e != NULL; e = e->next) { 149 if (0 == strcmp(e->name, name)) { 150 return e->ops; 151 } 152 } 153 154 return NULL; 121 155 } 122 156 … … 160 194 } 161 195 196 ev->last_zero_timer = NULL; 162 197 for (te = ev->timer_events; te; te = tn) { 163 198 tn = te->next; … … 186 221 } 187 222 223 /* removing nesting hook or we get an abort when nesting is 224 * not allowed. -- SSS 225 * Note that we need to leave the allowed flag at its current 226 * value, otherwise the use in tevent_re_initialise() will 227 * leave the event context with allowed forced to false, which 228 * will break users that expect nesting to be allowed 229 */ 230 ev->nesting.level = 0; 231 ev->nesting.hook_fn = NULL; 232 ev->nesting.hook_private = NULL; 233 188 234 return 0; 189 235 } … … 200 246 NOTE: use tevent_context_init() inside of samba! 201 247 */ 202 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx, 203 const struct tevent_ops *ops) 248 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx, 249 const struct tevent_ops *ops, 250 void *additional_data) 204 251 { 205 252 struct tevent_context *ev; … … 212 259 213 260 ev->ops = ops; 261 ev->additional_data = additional_data; 214 262 215 263 ret = ev->ops->context_init(ev); … … 230 278 const char *name) 231 279 { 232 struct tevent_ops_list *e; 233 234 tevent_backend_init(); 235 236 if (name == NULL) { 237 name = tevent_default_backend; 238 } 239 if (name == NULL) { 240 name = "standard"; 241 } 242 243 for (e=tevent_backends;e;e=e->next) { 244 if (strcmp(name, e->name) == 0) { 245 return tevent_context_init_ops(mem_ctx, e->ops); 246 } 247 } 248 return NULL; 280 const struct tevent_ops *ops; 281 282 ops = tevent_find_ops_byname(name); 283 if (ops == NULL) { 284 return NULL; 285 } 286 287 return tevent_context_init_ops(mem_ctx, ops, NULL); 249 288 } 250 289 … … 392 431 /* 393 432 schedule an immediate event 394 return NULL on failure395 433 */ 396 434 void _tevent_schedule_immediate(struct tevent_immediate *im, … … 492 530 } 493 531 532 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE); 494 533 ret = ev->ops->loop_once(ev, location); 534 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE); 495 535 496 536 if (ev->nesting.level > 0) { … … 552 592 553 593 while (!finished(private_data)) { 594 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE); 554 595 ret = ev->ops->loop_once(ev, location); 596 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE); 555 597 if (ret != 0) { 556 598 break; -
vendor/current/lib/tevent/tevent.h
r740 r988 40 40 struct tevent_immediate; 41 41 struct tevent_signal; 42 struct tevent_thread_proxy; 42 43 43 44 /** … … 112 113 113 114 /** 114 * @brief Create a event_context structure and name it.115 * @brief Create a event_context structure and select a specific backend. 115 116 * 116 117 * This must be the first events call, and all subsequent calls pass this … … 120 121 * @param[in] mem_ctx The memory context to use. 121 122 * 122 * @param[in] name The name for the tevent context.123 * @param[in] name The name of the backend to use. 123 124 * 124 125 * @return An allocated tevent context, NULL on error. 125 126 */ 126 127 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx, const char *name); 128 129 /** 130 * @brief Create a custom event context 131 * 132 * @param[in] mem_ctx The memory context to use. 133 * @param[in] ops The function pointer table of the backend. 134 * @param[in] additional_data The additional/private data to this instance 135 * 136 * @return An allocated tevent context, NULL on error. 137 * 138 */ 139 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx, 140 const struct tevent_ops *ops, 141 void *additional_data); 127 142 128 143 /** … … 137 152 138 153 /** 139 * @brief Set the default tevent backen t.154 * @brief Set the default tevent backend. 140 155 * 141 156 * @param[in] backend The name of the backend to set. … … 163 178 * @note To cancel the monitoring of a file descriptor, call talloc_free() 164 179 * on the object returned by this function. 180 * 181 * @note The caller should avoid closing the file descriptor before 182 * calling talloc_free()! Otherwise the behaviour is undefined which 183 * might result in crashes. See https://bugzilla.samba.org/show_bug.cgi?id=11141 184 * for an example. 165 185 */ 166 186 struct tevent_fd *tevent_add_fd(struct tevent_context *ev, … … 306 326 * @note To cancel a signal handler, call talloc_free() on the event returned 307 327 * from this function. 328 * 329 * @see tevent_num_signals, tevent_sa_info_queue_count 308 330 */ 309 331 struct tevent_signal *tevent_add_signal(struct tevent_context *ev, … … 327 349 #endif 328 350 351 /** 352 * @brief the number of supported signals 353 * 354 * This returns value of the configure time TEVENT_NUM_SIGNALS constant. 355 * 356 * The 'signum' argument of tevent_add_signal() must be less than 357 * TEVENT_NUM_SIGNALS. 358 * 359 * @see tevent_add_signal 360 */ 361 size_t tevent_num_signals(void); 362 363 /** 364 * @brief the number of pending realtime signals 365 * 366 * This returns value of TEVENT_SA_INFO_QUEUE_COUNT. 367 * 368 * The tevent internals remember the last TEVENT_SA_INFO_QUEUE_COUNT 369 * siginfo_t structures for SA_SIGINFO signals. If the system generates 370 * more some signals get lost. 371 * 372 * @see tevent_add_signal 373 */ 374 size_t tevent_sa_info_queue_count(void); 375 329 376 #ifdef DOXYGEN 330 377 /** … … 502 549 int tevent_set_debug_stderr(struct tevent_context *ev); 503 550 551 enum tevent_trace_point { 552 /** 553 * Corresponds to a trace point just before waiting 554 */ 555 TEVENT_TRACE_BEFORE_WAIT, 556 /** 557 * Corresponds to a trace point just after waiting 558 */ 559 TEVENT_TRACE_AFTER_WAIT, 560 #define TEVENT_HAS_LOOP_ONCE_TRACE_POINTS 1 561 /** 562 * Corresponds to a trace point just before calling 563 * the loop_once() backend function. 564 */ 565 TEVENT_TRACE_BEFORE_LOOP_ONCE, 566 /** 567 * Corresponds to a trace point right after the 568 * loop_once() backend function has returned. 569 */ 570 TEVENT_TRACE_AFTER_LOOP_ONCE, 571 }; 572 573 typedef void (*tevent_trace_callback_t)(enum tevent_trace_point, 574 void *private_data); 575 576 /** 577 * Register a callback to be called at certain trace points 578 * 579 * @param[in] ev Event context 580 * @param[in] cb Trace callback 581 * @param[in] private_data Data to be passed to callback 582 * 583 * @note The callback will be called at trace points defined by 584 * tevent_trace_point. Call with NULL to reset. 585 */ 586 void tevent_set_trace_callback(struct tevent_context *ev, 587 tevent_trace_callback_t cb, 588 void *private_data); 589 590 /** 591 * Retrieve the current trace callback 592 * 593 * @param[in] ev Event context 594 * @param[out] cb Registered trace callback 595 * @param[out] private_data Registered data to be passed to callback 596 * 597 * @note This can be used to allow one component that wants to 598 * register a callback to respect the callback that another component 599 * has already registered. 600 */ 601 void tevent_get_trace_callback(struct tevent_context *ev, 602 tevent_trace_callback_t *cb, 603 void *private_data); 604 504 605 /** 505 606 * @} … … 517 618 * are considered too low-level to be used in larger computations. To 518 619 * read and write from and to sockets, Samba provides two calls on top 519 * of tevent_add_fd: read_packet_send/recv and writev_send/recv. These520 * requests are much easier to compose than the low-level event620 * of tevent_add_fd: tstream_read_packet_send/recv and tstream_writev_send/recv. 621 * These requests are much easier to compose than the low-level event 521 622 * handlers called from tevent_add_fd. 522 623 * … … 840 941 #endif 841 942 943 /** 944 * @brief A typedef for a cleanup function for a tevent request. 945 * 946 * @param[in] req The tevent request calling this function. 947 * 948 * @param[in] req_state The current tevent_req_state. 949 * 950 */ 951 typedef void (*tevent_req_cleanup_fn)(struct tevent_req *req, 952 enum tevent_req_state req_state); 953 954 /** 955 * @brief This function sets a cleanup function for the given tevent request. 956 * 957 * This function can be used to setup a cleanup function for the given request. 958 * This will be triggered when the tevent_req_done() or tevent_req_error() 959 * function was called, before notifying the callers callback function, 960 * and also before scheduling the deferred trigger. 961 * 962 * This might be useful if more than one tevent_req belong together 963 * and need to finish both requests at the same time. 964 * 965 * The cleanup function is able to call tevent_req_done() or tevent_req_error() 966 * recursively, the cleanup function is only triggered the first time. 967 * 968 * The cleanup function is also called by tevent_req_received() 969 * (possibly triggered from tevent_req_destructor()) before destroying 970 * the private data of the tevent_req. 971 * 972 * @param[in] req The request to use. 973 * 974 * @param[in] fn A pointer to the cancel function. 975 */ 976 void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn); 977 842 978 #ifdef DOXYGEN 843 979 /** … … 852 988 * @endcode 853 989 * 854 * Tevent_req_create() creates the state variable as a talloc child of855 * its result. The state variable should be used as the talloc parent856 * for all temporary variables that are allocated during the async990 * Tevent_req_create() allocates and zeros the state variable as a talloc 991 * child of its result. The state variable should be used as the talloc 992 * parent for all temporary variables that are allocated during the async 857 993 * computation. This way, when the user of the async computation frees 858 994 * the request, the state as a talloc child will be free'd along with … … 996 1132 #endif 997 1133 1134 #ifdef DOXYGEN 1135 /** 1136 * @brief Indicate out of memory to a request 1137 * 1138 * @param[in] req The request being processed. 1139 */ 1140 void tevent_req_oom(struct tevent_req *req); 1141 #else 1142 void _tevent_req_oom(struct tevent_req *req, 1143 const char *location); 1144 #define tevent_req_oom(req) \ 1145 _tevent_req_oom(req, __location__) 1146 #endif 1147 998 1148 /** 999 1149 * @brief Finish a request before the caller had the change to set the callback. … … 1003 1153 * the engine. To present the illusion of a callback to the user of the API, 1004 1154 * the implementation can call this helper function which triggers an 1005 * immediate timedevent. This way the caller can use the same calling1155 * immediate event. This way the caller can use the same calling 1006 1156 * conventions, independent of whether the request was actually deferred. 1007 1157 * … … 1027 1177 * @param[in] req The finished request. 1028 1178 * 1029 * @param[in] ev The tevent_context for the timedevent.1179 * @param[in] ev The tevent_context for the immediate event. 1030 1180 * 1031 1181 * @return The given request will be returned. … … 1033 1183 struct tevent_req *tevent_req_post(struct tevent_req *req, 1034 1184 struct tevent_context *ev); 1185 1186 /** 1187 * @brief Finish multiple requests within one function 1188 * 1189 * Normally tevent_req_notify_callback() and all wrappers 1190 * (e.g. tevent_req_done() and tevent_req_error()) 1191 * need to be the last thing an event handler should call. 1192 * This is because the callback is likely to destroy the 1193 * context of the current function. 1194 * 1195 * If a function wants to notify more than one caller, 1196 * it is dangerous if it just triggers multiple callbacks 1197 * in a row. With tevent_req_defer_callback() it is possible 1198 * to set an event context that will be used to defer the callback 1199 * via an immediate event (similar to tevent_req_post()). 1200 * 1201 * @code 1202 * struct complete_state { 1203 * struct tevent_context *ev; 1204 * 1205 * struct tevent_req **reqs; 1206 * }; 1207 * 1208 * void complete(struct complete_state *state) 1209 * { 1210 * size_t i, c = talloc_array_length(state->reqs); 1211 * 1212 * for (i=0; i < c; i++) { 1213 * tevent_req_defer_callback(state->reqs[i], state->ev); 1214 * tevent_req_done(state->reqs[i]); 1215 * } 1216 * } 1217 * @endcode 1218 * 1219 * @param[in] req The finished request. 1220 * 1221 * @param[in] ev The tevent_context for the immediate event. 1222 * 1223 * @return The given request will be returned. 1224 */ 1225 void tevent_req_defer_callback(struct tevent_req *req, 1226 struct tevent_context *ev); 1035 1227 1036 1228 /** … … 1219 1411 * @param[in] secs The seconds to set. 1220 1412 * 1221 * @param[in] usecs The mi lliseconds to set.1413 * @param[in] usecs The microseconds to set. 1222 1414 * 1223 1415 * @return A timeval structure with the given values. … … 1254 1446 * @param[in] secs The seconds to add to the timeval. 1255 1447 * 1256 * @param[in] usecs The mi lliseconds to add to the timeval.1448 * @param[in] usecs The microseconds to add to the timeval. 1257 1449 * 1258 1450 * @return The timeval structure with the new time. … … 1266 1458 * @param[in] secs The seconds of the offset from now. 1267 1459 * 1268 * @param[in] usecs The mi lliseconds of the offset from now.1460 * @param[in] usecs The microseconds of the offset from now. 1269 1461 * 1270 1462 * @return A timval with the given offset in the future. … … 1292 1484 1293 1485 struct tevent_queue; 1486 struct tevent_queue_entry; 1294 1487 1295 1488 #ifdef DOXYGEN … … 1303 1496 * @return An allocated tevent queue on success, NULL on error. 1304 1497 * 1305 * @see tevent_ start()1306 * @see tevent_ stop()1498 * @see tevent_queue_start() 1499 * @see tevent_queue_stop() 1307 1500 */ 1308 1501 struct tevent_queue *tevent_queue_create(TALLOC_CTX *mem_ctx, … … 1326 1519 * 1327 1520 * @see tevent_queue_add() 1521 * @see tevent_queue_add_entry() 1522 * @see tevent_queue_add_optimize_empty() 1328 1523 */ 1329 1524 typedef void (*tevent_queue_trigger_fn_t)(struct tevent_req *req, … … 1340 1535 * 1341 1536 * @param[in] trigger The function triggered by the queue when the request 1342 * is called. 1537 * is called. Since tevent 0.9.14 it's possible to 1538 * pass NULL, in order to just add a "blocker" to the 1539 * queue. 1343 1540 * 1344 1541 * @param[in] private_data The private data passed to the trigger function. … … 1354 1551 1355 1552 /** 1553 * @brief Add a tevent request to the queue. 1554 * 1555 * The request can be removed from the queue by calling talloc_free() 1556 * (or a similar function) on the returned queue entry. This 1557 * is the only difference to tevent_queue_add(). 1558 * 1559 * @param[in] queue The queue to add the request. 1560 * 1561 * @param[in] ev The event handle to use for the request. 1562 * 1563 * @param[in] req The tevent request to add to the queue. 1564 * 1565 * @param[in] trigger The function triggered by the queue when the request 1566 * is called. Since tevent 0.9.14 it's possible to 1567 * pass NULL, in order to just add a "blocker" to the 1568 * queue. 1569 * 1570 * @param[in] private_data The private data passed to the trigger function. 1571 * 1572 * @return a pointer to the tevent_queue_entry if the request 1573 * has been successfully added, NULL otherwise. 1574 * 1575 * @see tevent_queue_add() 1576 * @see tevent_queue_add_optimize_empty() 1577 */ 1578 struct tevent_queue_entry *tevent_queue_add_entry( 1579 struct tevent_queue *queue, 1580 struct tevent_context *ev, 1581 struct tevent_req *req, 1582 tevent_queue_trigger_fn_t trigger, 1583 void *private_data); 1584 1585 /** 1586 * @brief Add a tevent request to the queue using a possible optimization. 1587 * 1588 * This tries to optimize for the empty queue case and may calls 1589 * the trigger function directly. This is the only difference compared 1590 * to tevent_queue_add_entry(). 1591 * 1592 * The caller needs to be prepared that the trigger function has 1593 * already called tevent_req_notify_callback(), tevent_req_error(), 1594 * tevent_req_done() or a similar function. 1595 * 1596 * The request can be removed from the queue by calling talloc_free() 1597 * (or a similar function) on the returned queue entry. 1598 * 1599 * @param[in] queue The queue to add the request. 1600 * 1601 * @param[in] ev The event handle to use for the request. 1602 * 1603 * @param[in] req The tevent request to add to the queue. 1604 * 1605 * @param[in] trigger The function triggered by the queue when the request 1606 * is called. Since tevent 0.9.14 it's possible to 1607 * pass NULL, in order to just add a "blocker" to the 1608 * queue. 1609 * 1610 * @param[in] private_data The private data passed to the trigger function. 1611 * 1612 * @return a pointer to the tevent_queue_entry if the request 1613 * has been successfully added, NULL otherwise. 1614 * 1615 * @see tevent_queue_add() 1616 * @see tevent_queue_add_entry() 1617 */ 1618 struct tevent_queue_entry *tevent_queue_add_optimize_empty( 1619 struct tevent_queue *queue, 1620 struct tevent_context *ev, 1621 struct tevent_req *req, 1622 tevent_queue_trigger_fn_t trigger, 1623 void *private_data); 1624 1625 /** 1356 1626 * @brief Start a tevent queue. 1357 1627 * … … 1379 1649 */ 1380 1650 size_t tevent_queue_length(struct tevent_queue *queue); 1651 1652 /** 1653 * @brief Is the tevent queue running. 1654 * 1655 * The queue is started by default. 1656 * 1657 * @param[in] queue The queue. 1658 * 1659 * @return Wether the queue is running or not.. 1660 */ 1661 bool tevent_queue_running(struct tevent_queue *queue); 1662 1663 /** 1664 * @brief Create a tevent subrequest that waits in a tevent_queue 1665 * 1666 * The idea is that always the same syntax for tevent requests. 1667 * 1668 * @param[in] mem_ctx The talloc memory context to use. 1669 * 1670 * @param[in] ev The event handle to setup the request. 1671 * 1672 * @param[in] queue The queue to wait in. 1673 * 1674 * @return The new subrequest, NULL on error. 1675 * 1676 * @see tevent_queue_wait_recv() 1677 */ 1678 struct tevent_req *tevent_queue_wait_send(TALLOC_CTX *mem_ctx, 1679 struct tevent_context *ev, 1680 struct tevent_queue *queue); 1681 1682 /** 1683 * @brief Check if we no longer need to wait in the queue. 1684 * 1685 * This function needs to be called in the callback function set after calling 1686 * tevent_queue_wait_send(). 1687 * 1688 * @param[in] req The tevent request to check. 1689 * 1690 * @return True on success, false otherwise. 1691 * 1692 * @see tevent_queue_wait_send() 1693 */ 1694 bool tevent_queue_wait_recv(struct tevent_req *req); 1381 1695 1382 1696 typedef int (*tevent_nesting_hook)(struct tevent_context *ev, … … 1386 1700 void *stack_ptr, 1387 1701 const char *location); 1702 1703 /** 1704 * @brief Create a tevent_thread_proxy for message passing between threads. 1705 * 1706 * The tevent_context must have been allocated on the NULL 1707 * talloc context, and talloc_disable_null_tracking() must 1708 * have been called. 1709 * 1710 * @param[in] dest_ev_ctx The tevent_context to receive events. 1711 * 1712 * @return An allocated tevent_thread_proxy, NULL on error. 1713 * If tevent was compiled without PTHREAD support 1714 * NULL is always returned and errno set to ENOSYS. 1715 * 1716 * @see tevent_thread_proxy_schedule() 1717 */ 1718 struct tevent_thread_proxy *tevent_thread_proxy_create( 1719 struct tevent_context *dest_ev_ctx); 1720 1721 /** 1722 * @brief Schedule an immediate event on an event context from another thread. 1723 * 1724 * Causes dest_ev_ctx, being run by another thread, to receive an 1725 * immediate event calling the handler with the *pp_private parameter. 1726 * 1727 * *pp_im must be a pointer to an immediate event talloced on a context owned 1728 * by the calling thread, or the NULL context. Ownership will 1729 * be transferred to the tevent_thread_proxy and *pp_im will be returned as NULL. 1730 * 1731 * *pp_private_data must be a talloced area of memory with no destructors. 1732 * Ownership of this memory will be transferred to the tevent library and 1733 * *pp_private_data will be set to NULL on successful completion of 1734 * the call. Set pp_private to NULL if no parameter transfer 1735 * needed (a pure callback). This is an asynchronous request, caller 1736 * does not wait for callback to be completed before returning. 1737 * 1738 * @param[in] tp The tevent_thread_proxy to use. 1739 * 1740 * @param[in] pp_im Pointer to immediate event pointer. 1741 * 1742 * @param[in] handler The function that will be called. 1743 * 1744 * @param[in] pp_private_data The talloced memory to transfer. 1745 * 1746 * @see tevent_thread_proxy_create() 1747 */ 1748 void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp, 1749 struct tevent_immediate **pp_im, 1750 tevent_immediate_handler_t handler, 1751 void *pp_private_data); 1752 1388 1753 #ifdef TEVENT_DEPRECATED 1389 1754 #ifndef _DEPRECATED_ -
vendor/current/lib/tevent/tevent.pc.in
r740 r988 8 8 Version: @PACKAGE_VERSION@ 9 9 Requires: talloc 10 Libs: -L${libdir} -ltevent11 Cflags: @LIB_RPATH@-I${includedir}10 Libs: @LIB_RPATH@ -L${libdir} -ltevent 11 Cflags: -I${includedir} 12 12 URL: http://samba.org/ -
vendor/current/lib/tevent/tevent_debug.c
r414 r988 95 95 } 96 96 97 void tevent_set_trace_callback(struct tevent_context *ev, 98 tevent_trace_callback_t cb, 99 void *private_data) 100 { 101 ev->tracing.callback = cb; 102 ev->tracing.private_data = private_data; 103 } 104 105 void tevent_get_trace_callback(struct tevent_context *ev, 106 tevent_trace_callback_t *cb, 107 void *private_data) 108 { 109 *cb = ev->tracing.callback; 110 *(void**)private_data = ev->tracing.private_data; 111 } 112 113 void tevent_trace_point_callback(struct tevent_context *ev, 114 enum tevent_trace_point tp) 115 { 116 if (ev->tracing.callback != NULL) { 117 ev->tracing.callback(tp, ev->tracing.private_data); 118 } 119 } -
vendor/current/lib/tevent/tevent_epoll.c
r740 r988 5 5 6 6 Copyright (C) Andrew Tridgell 2003-2005 7 Copyright (C) Stefan Metzmacher 2005-2009 7 Copyright (C) Stefan Metzmacher 2005-2013 8 Copyright (C) Jeremy Allison 2013 8 9 9 10 ** NOTE! The following LGPL license applies to the tevent … … 40 41 41 42 pid_t pid; 43 44 bool panic_force_replay; 45 bool *panic_state; 46 bool (*panic_fallback)(struct tevent_context *ev, bool replay); 42 47 }; 43 48 49 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0) 50 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1) 51 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2) 52 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX (1<<3) 53 54 #ifdef TEST_PANIC_FALLBACK 55 56 static int epoll_create_panic_fallback(struct epoll_event_context *epoll_ev, 57 int size) 58 { 59 if (epoll_ev->panic_fallback == NULL) { 60 return epoll_create(size); 61 } 62 63 /* 50% of the time, fail... */ 64 if ((random() % 2) == 0) { 65 errno = EINVAL; 66 return -1; 67 } 68 69 return epoll_create(size); 70 } 71 72 static int epoll_ctl_panic_fallback(struct epoll_event_context *epoll_ev, 73 int epfd, int op, int fd, 74 struct epoll_event *event) 75 { 76 if (epoll_ev->panic_fallback == NULL) { 77 return epoll_ctl(epfd, op, fd, event); 78 } 79 80 /* 50% of the time, fail... */ 81 if ((random() % 2) == 0) { 82 errno = EINVAL; 83 return -1; 84 } 85 86 return epoll_ctl(epfd, op, fd, event); 87 } 88 89 static int epoll_wait_panic_fallback(struct epoll_event_context *epoll_ev, 90 int epfd, 91 struct epoll_event *events, 92 int maxevents, 93 int timeout) 94 { 95 if (epoll_ev->panic_fallback == NULL) { 96 return epoll_wait(epfd, events, maxevents, timeout); 97 } 98 99 /* 50% of the time, fail... */ 100 if ((random() % 2) == 0) { 101 errno = EINVAL; 102 return -1; 103 } 104 105 return epoll_wait(epfd, events, maxevents, timeout); 106 } 107 108 #define epoll_create(_size) \ 109 epoll_create_panic_fallback(epoll_ev, _size) 110 #define epoll_ctl(_epfd, _op, _fd, _event) \ 111 epoll_ctl_panic_fallback(epoll_ev,_epfd, _op, _fd, _event) 112 #define epoll_wait(_epfd, _events, _maxevents, _timeout) \ 113 epoll_wait_panic_fallback(epoll_ev, _epfd, _events, _maxevents, _timeout) 114 #endif 115 116 /* 117 called to set the panic fallback function. 118 */ 119 _PRIVATE_ void tevent_epoll_set_panic_fallback(struct tevent_context *ev, 120 bool (*panic_fallback)(struct tevent_context *ev, 121 bool replay)) 122 { 123 struct epoll_event_context *epoll_ev = 124 talloc_get_type_abort(ev->additional_data, 125 struct epoll_event_context); 126 127 epoll_ev->panic_fallback = panic_fallback; 128 } 129 44 130 /* 45 131 called when a epoll call fails 46 132 */ 47 static void epoll_panic(struct epoll_event_context *epoll_ev, const char *reason) 48 { 49 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL, 50 "%s (%s) - calling abort()\n", reason, strerror(errno)); 51 abort(); 133 static void epoll_panic(struct epoll_event_context *epoll_ev, 134 const char *reason, bool replay) 135 { 136 struct tevent_context *ev = epoll_ev->ev; 137 bool (*panic_fallback)(struct tevent_context *ev, bool replay); 138 139 panic_fallback = epoll_ev->panic_fallback; 140 141 if (epoll_ev->panic_state != NULL) { 142 *epoll_ev->panic_state = true; 143 } 144 145 if (epoll_ev->panic_force_replay) { 146 replay = true; 147 } 148 149 TALLOC_FREE(ev->additional_data); 150 151 if (panic_fallback == NULL) { 152 tevent_debug(ev, TEVENT_DEBUG_FATAL, 153 "%s (%s) replay[%u] - calling abort()\n", 154 reason, strerror(errno), (unsigned)replay); 155 abort(); 156 } 157 158 tevent_debug(ev, TEVENT_DEBUG_ERROR, 159 "%s (%s) replay[%u] - calling panic_fallback\n", 160 reason, strerror(errno), (unsigned)replay); 161 162 if (!panic_fallback(ev, replay)) { 163 /* Fallback failed. */ 164 tevent_debug(ev, TEVENT_DEBUG_FATAL, 165 "%s (%s) replay[%u] - calling abort()\n", 166 reason, strerror(errno), (unsigned)replay); 167 abort(); 168 } 52 169 } 53 170 … … 79 196 { 80 197 epoll_ev->epoll_fd = epoll_create(64); 198 if (epoll_ev->epoll_fd == -1) { 199 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL, 200 "Failed to create epoll handle.\n"); 201 return -1; 202 } 203 204 if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) { 205 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING, 206 "Failed to set close-on-exec, file descriptor may be leaked to children.\n"); 207 } 208 81 209 epoll_ev->pid = getpid(); 82 210 talloc_set_destructor(epoll_ev, epoll_ctx_destructor); 83 if (epoll_ev->epoll_fd == -1) { 84 return -1; 85 } 211 86 212 return 0; 87 213 } 88 214 89 static void epoll_ add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);215 static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde); 90 216 91 217 /* 92 218 reopen the epoll handle when our pid changes 93 see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 219 see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 94 220 demonstration of why this is needed 95 221 */ … … 97 223 { 98 224 struct tevent_fd *fde; 225 bool *caller_panic_state = epoll_ev->panic_state; 226 bool panic_triggered = false; 99 227 100 228 if (epoll_ev->pid == getpid()) { … … 105 233 epoll_ev->epoll_fd = epoll_create(64); 106 234 if (epoll_ev->epoll_fd == -1) { 235 epoll_panic(epoll_ev, "epoll_create() failed", false); 236 return; 237 } 238 239 if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) { 240 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING, 241 "Failed to set close-on-exec, file descriptor may be leaked to children.\n"); 242 } 243 244 epoll_ev->pid = getpid(); 245 epoll_ev->panic_state = &panic_triggered; 246 for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) { 247 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 248 epoll_update_event(epoll_ev, fde); 249 250 if (panic_triggered) { 251 if (caller_panic_state != NULL) { 252 *caller_panic_state = true; 253 } 254 return; 255 } 256 } 257 epoll_ev->panic_state = NULL; 258 } 259 260 /* 261 epoll cannot add the same file descriptor twice, once 262 with read, once with write which is allowed by the 263 tevent backend. Multiplex the existing fde, flag it 264 as such so we can search for the correct fde on 265 event triggering. 266 */ 267 268 static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev, 269 struct tevent_fd *add_fde) 270 { 271 struct epoll_event event; 272 struct tevent_fd *mpx_fde; 273 int ret; 274 275 /* Find the existing fde that caused the EEXIST error. */ 276 for (mpx_fde = epoll_ev->ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) { 277 if (mpx_fde->fd != add_fde->fd) { 278 continue; 279 } 280 281 if (mpx_fde == add_fde) { 282 continue; 283 } 284 285 break; 286 } 287 if (mpx_fde == NULL) { 107 288 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL, 108 "Failed to recreate epoll handle after fork\n"); 109 return; 110 } 111 epoll_ev->pid = getpid(); 112 for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) { 113 epoll_add_event(epoll_ev, fde); 114 } 115 } 116 117 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0) 118 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1) 119 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2) 289 "can't find multiplex fde for fd[%d]", 290 add_fde->fd); 291 return -1; 292 } 293 294 if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) { 295 /* Logic error. Can't have more than 2 multiplexed fde's. */ 296 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL, 297 "multiplex fde for fd[%d] is already multiplexed\n", 298 mpx_fde->fd); 299 return -1; 300 } 301 302 /* 303 * The multiplex fde must have the same fd, and also 304 * already have an epoll event attached. 305 */ 306 if (!(mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) { 307 /* Logic error. Can't have more than 2 multiplexed fde's. */ 308 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL, 309 "multiplex fde for fd[%d] has no event\n", 310 mpx_fde->fd); 311 return -1; 312 } 313 314 /* Modify the mpx_fde to add in the new flags. */ 315 ZERO_STRUCT(event); 316 event.events = epoll_map_flags(mpx_fde->flags); 317 event.events |= epoll_map_flags(add_fde->flags); 318 event.data.ptr = mpx_fde; 319 ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, mpx_fde->fd, &event); 320 if (ret != 0 && errno == EBADF) { 321 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR, 322 "EPOLL_CTL_MOD EBADF for " 323 "add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n", 324 add_fde, mpx_fde, add_fde->fd); 325 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde); 326 mpx_fde->event_ctx = NULL; 327 DLIST_REMOVE(epoll_ev->ev->fd_events, add_fde); 328 add_fde->event_ctx = NULL; 329 return 0; 330 } else if (ret != 0) { 331 return ret; 332 } 333 334 /* 335 * Make each fde->additional_data pointers point at each other 336 * so we can look them up from each other. They are now paired. 337 */ 338 mpx_fde->additional_data = (struct tevent_fd *)add_fde; 339 add_fde->additional_data = (struct tevent_fd *)mpx_fde; 340 341 /* Now flag both fde's as being multiplexed. */ 342 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX; 343 add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX; 344 345 /* we need to keep the GOT_ERROR flag */ 346 if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR) { 347 add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; 348 } 349 350 return 0; 351 } 120 352 121 353 /* … … 125 357 { 126 358 struct epoll_event event; 127 128 if (epoll_ev->epoll_fd == -1) return; 129 359 int ret; 360 struct tevent_fd *mpx_fde = NULL; 361 362 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 130 363 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 131 364 132 /* if we don't want events yet, don't add an epoll_event */ 133 if (fde->flags == 0) return; 365 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) { 366 /* 367 * This is a multiplexed fde, we need to include both 368 * flags in the modified event. 369 */ 370 mpx_fde = talloc_get_type_abort(fde->additional_data, 371 struct tevent_fd); 372 373 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 374 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 375 } 134 376 135 377 ZERO_STRUCT(event); 136 378 event.events = epoll_map_flags(fde->flags); 379 if (mpx_fde != NULL) { 380 event.events |= epoll_map_flags(mpx_fde->flags); 381 } 137 382 event.data.ptr = fde; 138 if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) { 139 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed"); 140 } 383 ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event); 384 if (ret != 0 && errno == EBADF) { 385 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR, 386 "EPOLL_CTL_ADD EBADF for " 387 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n", 388 fde, mpx_fde, fde->fd); 389 DLIST_REMOVE(epoll_ev->ev->fd_events, fde); 390 fde->event_ctx = NULL; 391 if (mpx_fde != NULL) { 392 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde); 393 mpx_fde->event_ctx = NULL; 394 } 395 return; 396 } else if (ret != 0 && errno == EEXIST && mpx_fde == NULL) { 397 ret = epoll_add_multiplex_fd(epoll_ev, fde); 398 if (ret != 0) { 399 epoll_panic(epoll_ev, "epoll_add_multiplex_fd failed", 400 false); 401 return; 402 } 403 } else if (ret != 0) { 404 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false); 405 return; 406 } 407 141 408 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 142 143 409 /* only if we want to read we want to tell the event handler about errors */ 144 410 if (fde->flags & TEVENT_FD_READ) { 145 411 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 146 412 } 413 414 if (mpx_fde == NULL) { 415 return; 416 } 417 418 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 419 /* only if we want to read we want to tell the event handler about errors */ 420 if (mpx_fde->flags & TEVENT_FD_READ) { 421 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 422 } 147 423 } 148 424 … … 153 429 { 154 430 struct epoll_event event; 155 156 if (epoll_ev->epoll_fd == -1) return; 157 431 int ret; 432 struct tevent_fd *mpx_fde = NULL; 433 434 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 158 435 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 159 436 160 /* if there's no epoll_event, we don't need to delete it */ 161 if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return; 437 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) { 438 /* 439 * This is a multiplexed fde, we need to modify both events. 440 */ 441 mpx_fde = talloc_get_type_abort(fde->additional_data, 442 struct tevent_fd); 443 444 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 445 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 446 } 447 448 ZERO_STRUCT(event); 449 ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event); 450 if (ret != 0 && errno == ENOENT) { 451 /* 452 * This can happen after a epoll_check_reopen 453 * within epoll_event_fd_destructor. 454 */ 455 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_TRACE, 456 "EPOLL_CTL_DEL ignoring ENOENT for fd[%d]\n", 457 fde->fd); 458 return; 459 } else if (ret != 0 && errno == EBADF) { 460 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING, 461 "EPOLL_CTL_DEL EBADF for " 462 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n", 463 fde, mpx_fde, fde->fd); 464 DLIST_REMOVE(epoll_ev->ev->fd_events, fde); 465 fde->event_ctx = NULL; 466 if (mpx_fde != NULL) { 467 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde); 468 mpx_fde->event_ctx = NULL; 469 } 470 return; 471 } else if (ret != 0) { 472 epoll_panic(epoll_ev, "EPOLL_CTL_DEL failed", false); 473 return; 474 } 475 } 476 477 /* 478 change the epoll event to the given fd_event 479 */ 480 static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde) 481 { 482 struct tevent_fd *mpx_fde = NULL; 483 struct epoll_event event; 484 int ret; 485 486 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 487 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 488 489 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) { 490 /* 491 * This is a multiplexed fde, we need to include both 492 * flags in the modified event. 493 */ 494 mpx_fde = talloc_get_type_abort(fde->additional_data, 495 struct tevent_fd); 496 497 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 498 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 499 } 162 500 163 501 ZERO_STRUCT(event); 164 502 event.events = epoll_map_flags(fde->flags); 503 if (mpx_fde != NULL) { 504 event.events |= epoll_map_flags(mpx_fde->flags); 505 } 165 506 event.data.ptr = fde; 166 if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) { 167 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL, 168 "epoll_del_event failed! probable early close bug (%s)\n", 169 strerror(errno)); 170 } 171 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 172 } 173 174 /* 175 change the epoll event to the given fd_event 176 */ 177 static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde) 178 { 179 struct epoll_event event; 180 if (epoll_ev->epoll_fd == -1) return; 181 182 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 183 184 ZERO_STRUCT(event); 185 event.events = epoll_map_flags(fde->flags); 186 event.data.ptr = fde; 187 if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) { 188 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed"); 189 } 190 507 ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event); 508 if (ret != 0 && errno == EBADF) { 509 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR, 510 "EPOLL_CTL_MOD EBADF for " 511 "fde[%p] mpx_fde[%p] fd[%d] - disabling\n", 512 fde, mpx_fde, fde->fd); 513 DLIST_REMOVE(epoll_ev->ev->fd_events, fde); 514 fde->event_ctx = NULL; 515 if (mpx_fde != NULL) { 516 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde); 517 mpx_fde->event_ctx = NULL; 518 } 519 return; 520 } else if (ret != 0) { 521 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false); 522 return; 523 } 524 525 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 191 526 /* only if we want to read we want to tell the event handler about errors */ 192 527 if (fde->flags & TEVENT_FD_READ) { 193 528 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 194 529 } 195 } 196 197 static void epoll_change_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde) 530 531 if (mpx_fde == NULL) { 532 return; 533 } 534 535 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 536 /* only if we want to read we want to tell the event handler about errors */ 537 if (mpx_fde->flags & TEVENT_FD_READ) { 538 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 539 } 540 } 541 542 static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde) 198 543 { 199 544 bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR); 200 545 bool want_read = (fde->flags & TEVENT_FD_READ); 201 546 bool want_write= (fde->flags & TEVENT_FD_WRITE); 202 203 if (epoll_ev->epoll_fd == -1) return; 204 205 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 547 struct tevent_fd *mpx_fde = NULL; 548 549 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) { 550 /* 551 * work out what the multiplexed fde wants. 552 */ 553 mpx_fde = talloc_get_type_abort(fde->additional_data, 554 struct tevent_fd); 555 556 if (mpx_fde->flags & TEVENT_FD_READ) { 557 want_read = true; 558 } 559 560 if (mpx_fde->flags & TEVENT_FD_WRITE) { 561 want_write = true; 562 } 563 } 206 564 207 565 /* there's already an event */ … … 229 587 230 588 /* 589 Cope with epoll returning EPOLLHUP|EPOLLERR on an event. 590 Return true if there's nothing else to do, false if 591 this event needs further handling. 592 */ 593 static bool epoll_handle_hup_or_err(struct epoll_event_context *epoll_ev, 594 struct tevent_fd *fde) 595 { 596 if (fde == NULL) { 597 /* Nothing to do if no event. */ 598 return true; 599 } 600 601 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; 602 /* 603 * if we only wait for TEVENT_FD_WRITE, we should not tell the 604 * event handler about it, and remove the epoll_event, 605 * as we only report errors when waiting for read events, 606 * to match the select() behavior 607 */ 608 if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) { 609 /* 610 * Do the same as the poll backend and 611 * remove the writeable flag. 612 */ 613 fde->flags &= ~TEVENT_FD_WRITE; 614 return true; 615 } 616 /* This has TEVENT_FD_READ set, we're not finished. */ 617 return false; 618 } 619 620 /* 231 621 event loop handling using epoll 232 622 */ … … 237 627 struct epoll_event events[MAXEVENTS]; 238 628 int timeout = -1; 239 240 if (epoll_ev->epoll_fd == -1) return -1; 629 int wait_errno; 241 630 242 631 if (tvalp) { 243 /* it's better to trigger timed events a bit later than to early */632 /* it's better to trigger timed events a bit later than too early */ 244 633 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000); 245 634 } … … 250 639 } 251 640 641 tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT); 252 642 ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout); 253 254 if (ret == -1 && errno == EINTR && epoll_ev->ev->signal_events) { 643 wait_errno = errno; 644 tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT); 645 646 if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) { 255 647 if (tevent_common_check_signal(epoll_ev->ev)) { 256 648 return 0; … … 258 650 } 259 651 260 if (ret == -1 && errno != EINTR) {261 epoll_panic(epoll_ev, "epoll_wait() failed" );652 if (ret == -1 && wait_errno != EINTR) { 653 epoll_panic(epoll_ev, "epoll_wait() failed", true); 262 654 return -1; 263 655 } … … 270 662 271 663 for (i=0;i<ret;i++) { 272 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 664 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 273 665 struct tevent_fd); 274 666 uint16_t flags = 0; 667 struct tevent_fd *mpx_fde = NULL; 275 668 276 669 if (fde == NULL) { 277 epoll_panic(epoll_ev, "epoll_wait() gave bad data" );670 epoll_panic(epoll_ev, "epoll_wait() gave bad data", true); 278 671 return -1; 279 672 } 673 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) { 674 /* 675 * Save off the multiplexed event in case we need 676 * to use it to call the handler function. 677 */ 678 mpx_fde = talloc_get_type_abort(fde->additional_data, 679 struct tevent_fd); 680 } 280 681 if (events[i].events & (EPOLLHUP|EPOLLERR)) { 281 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; 282 /* 283 * if we only wait for TEVENT_FD_WRITE, we should not tell the 284 * event handler about it, and remove the epoll_event, 285 * as we only report errors when waiting for read events, 286 * to match the select() behavior 287 */ 288 if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) { 289 epoll_del_event(epoll_ev, fde); 682 bool handled_fde = epoll_handle_hup_or_err(epoll_ev, fde); 683 bool handled_mpx = epoll_handle_hup_or_err(epoll_ev, mpx_fde); 684 685 if (handled_fde && handled_mpx) { 686 epoll_update_event(epoll_ev, fde); 290 687 continue; 291 688 } 689 690 if (!handled_mpx) { 691 /* 692 * If the mpx event was the one that needs 693 * further handling, it's the TEVENT_FD_READ 694 * event so switch over and call that handler. 695 */ 696 fde = mpx_fde; 697 mpx_fde = NULL; 698 } 292 699 flags |= TEVENT_FD_READ; 293 700 } 294 701 if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ; 295 702 if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE; 703 704 if (flags & TEVENT_FD_WRITE) { 705 if (fde->flags & TEVENT_FD_WRITE) { 706 mpx_fde = NULL; 707 } 708 if (mpx_fde && mpx_fde->flags & TEVENT_FD_WRITE) { 709 fde = mpx_fde; 710 mpx_fde = NULL; 711 } 712 } 713 714 if (mpx_fde) { 715 /* Ensure we got the right fde. */ 716 if ((flags & fde->flags) == 0) { 717 fde = mpx_fde; 718 mpx_fde = NULL; 719 } 720 } 721 722 /* 723 * make sure we only pass the flags 724 * the handler is expecting. 725 */ 726 flags &= fde->flags; 296 727 if (flags) { 297 728 fde->handler(epoll_ev->ev, fde, flags, fde->private_data); … … 310 741 int ret; 311 742 struct epoll_event_context *epoll_ev; 743 744 /* 745 * We might be called during tevent_re_initialise() 746 * which means we need to free our old additional_data. 747 */ 748 TALLOC_FREE(ev->additional_data); 312 749 313 750 epoll_ev = talloc_zero(ev, struct epoll_event_context); … … 333 770 struct tevent_context *ev = fde->event_ctx; 334 771 struct epoll_event_context *epoll_ev = NULL; 335 336 if (ev) { 337 epoll_ev = talloc_get_type(ev->additional_data, 338 struct epoll_event_context); 339 340 epoll_check_reopen(epoll_ev); 341 342 epoll_del_event(epoll_ev, fde); 343 } 772 bool panic_triggered = false; 773 struct tevent_fd *mpx_fde = NULL; 774 int flags = fde->flags; 775 776 if (ev == NULL) { 777 return tevent_common_fd_destructor(fde); 778 } 779 780 epoll_ev = talloc_get_type_abort(ev->additional_data, 781 struct epoll_event_context); 782 783 /* 784 * we must remove the event from the list 785 * otherwise a panic fallback handler may 786 * reuse invalid memory 787 */ 788 DLIST_REMOVE(ev->fd_events, fde); 789 790 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) { 791 mpx_fde = talloc_get_type_abort(fde->additional_data, 792 struct tevent_fd); 793 794 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX; 795 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX; 796 797 fde->additional_data = NULL; 798 mpx_fde->additional_data = NULL; 799 800 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 801 } 802 803 epoll_ev->panic_state = &panic_triggered; 804 epoll_check_reopen(epoll_ev); 805 if (panic_triggered) { 806 return tevent_common_fd_destructor(fde); 807 } 808 809 if (mpx_fde != NULL) { 810 epoll_update_event(epoll_ev, mpx_fde); 811 if (panic_triggered) { 812 return tevent_common_fd_destructor(fde); 813 } 814 } 815 816 fde->flags = 0; 817 epoll_update_event(epoll_ev, fde); 818 fde->flags = flags; 819 if (panic_triggered) { 820 return tevent_common_fd_destructor(fde); 821 } 822 epoll_ev->panic_state = NULL; 344 823 345 824 return tevent_common_fd_destructor(fde); … … 357 836 const char *location) 358 837 { 359 struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, 360 struct epoll_event_context); 838 struct epoll_event_context *epoll_ev = 839 talloc_get_type_abort(ev->additional_data, 840 struct epoll_event_context); 361 841 struct tevent_fd *fde; 362 363 epoll_check_reopen(epoll_ev); 842 bool panic_triggered = false; 364 843 365 844 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags, … … 370 849 talloc_set_destructor(fde, epoll_event_fd_destructor); 371 850 372 epoll_add_event(epoll_ev, fde); 851 epoll_ev->panic_state = &panic_triggered; 852 epoll_check_reopen(epoll_ev); 853 if (panic_triggered) { 854 return fde; 855 } 856 epoll_ev->panic_state = NULL; 857 858 epoll_update_event(epoll_ev, fde); 373 859 374 860 return fde; … … 382 868 struct tevent_context *ev; 383 869 struct epoll_event_context *epoll_ev; 870 bool panic_triggered = false; 384 871 385 872 if (fde->flags == flags) return; 386 873 387 874 ev = fde->event_ctx; 388 epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context); 875 epoll_ev = talloc_get_type_abort(ev->additional_data, 876 struct epoll_event_context); 389 877 390 878 fde->flags = flags; 391 879 880 epoll_ev->panic_state = &panic_triggered; 392 881 epoll_check_reopen(epoll_ev); 393 394 epoll_change_event(epoll_ev, fde); 395 } 396 397 /* 398 do a single event loop using the events defined in ev 882 if (panic_triggered) { 883 return; 884 } 885 epoll_ev->panic_state = NULL; 886 887 epoll_update_event(epoll_ev, fde); 888 } 889 890 /* 891 do a single event loop using the events defined in ev 399 892 */ 400 893 static int epoll_event_loop_once(struct tevent_context *ev, const char *location) 401 894 { 402 struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, 403 struct epoll_event_context); 895 struct epoll_event_context *epoll_ev = 896 talloc_get_type_abort(ev->additional_data, 897 struct epoll_event_context); 404 898 struct timeval tval; 899 bool panic_triggered = false; 405 900 406 901 if (ev->signal_events && … … 419 914 } 420 915 916 epoll_ev->panic_state = &panic_triggered; 917 epoll_ev->panic_force_replay = true; 421 918 epoll_check_reopen(epoll_ev); 919 if (panic_triggered) { 920 errno = EINVAL; 921 return -1; 922 } 923 epoll_ev->panic_force_replay = false; 924 epoll_ev->panic_state = NULL; 422 925 423 926 return epoll_event_loop(epoll_ev, &tval); … … 430 933 .get_fd_flags = tevent_common_fd_get_flags, 431 934 .set_fd_flags = epoll_event_set_fd_flags, 432 .add_timer = tevent_common_add_timer ,935 .add_timer = tevent_common_add_timer_v2, 433 936 .schedule_immediate = tevent_common_schedule_immediate, 434 937 .add_signal = tevent_common_add_signal, -
vendor/current/lib/tevent/tevent_immediate.c
r414 r988 89 89 im->additional_data = NULL; 90 90 91 DLIST_ADD_END(ev->immediate_events, im , struct tevent_immediate *);91 DLIST_ADD_END(ev->immediate_events, im); 92 92 talloc_set_destructor(im, tevent_common_immediate_destructor); 93 93 -
vendor/current/lib/tevent/tevent_internal.h
r740 r988 75 75 76 76 /** 77 * @brief A function to cleanup the request 78 * 79 * The implementation might want to set a function 80 * that is called before the tevent_req_done() and tevent_req_error() 81 * trigger the callers callback function. 82 */ 83 struct { 84 tevent_req_cleanup_fn fn; 85 enum tevent_req_state state; 86 } private_cleanup; 87 88 /** 77 89 * @brief Internal state of the request 78 90 * … … 141 153 */ 142 154 struct tevent_immediate *trigger; 155 156 /** 157 * @brief An event context which will be used to 158 * defer the _tevent_req_notify_callback(). 159 */ 160 struct tevent_context *defer_callback_ev; 143 161 144 162 /** … … 253 271 void *hook_private; 254 272 } nesting; 255 }; 256 273 274 struct { 275 tevent_trace_callback_t callback; 276 void *private_data; 277 } tracing; 278 279 /* 280 * an optimization pointer into timer_events 281 * used by used by common code via 282 * tevent_common_add_timer_v2() 283 */ 284 struct tevent_timer *last_zero_timer; 285 }; 286 287 const struct tevent_ops *tevent_find_ops_byname(const char *name); 257 288 258 289 int tevent_common_context_destructor(struct tevent_context *ev); … … 281 312 const char *handler_name, 282 313 const char *location); 314 struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev, 315 TALLOC_CTX *mem_ctx, 316 struct timeval next_event, 317 tevent_timer_handler_t handler, 318 void *private_data, 319 const char *handler_name, 320 const char *location); 283 321 struct timeval tevent_common_loop_timer_delay(struct tevent_context *); 284 322 … … 305 343 bool tevent_select_init(void); 306 344 bool tevent_poll_init(void); 345 void tevent_poll_event_add_fd_internal(struct tevent_context *ev, 346 struct tevent_fd *fde); 347 bool tevent_poll_mt_init(void); 307 348 #ifdef HAVE_EPOLL 308 349 bool tevent_epoll_init(void); 350 void tevent_epoll_set_panic_fallback(struct tevent_context *ev, 351 bool (*panic_fallback)(struct tevent_context *ev, 352 bool replay)); 309 353 #endif 354 #ifdef HAVE_SOLARIS_PORTS 355 bool tevent_port_init(void); 356 #endif 357 358 359 void tevent_trace_point_callback(struct tevent_context *ev, 360 enum tevent_trace_point); -
vendor/current/lib/tevent/tevent_liboop.c
r740 r988 2 2 Unix SMB/CIFS implementation. 3 3 main select loop and event handling 4 wrapper for http:// liboop.org/4 wrapper for http://git.lysator.liu.se/liboop/ 5 5 6 6 Copyright (C) Stefan Metzmacher 2005 -
vendor/current/lib/tevent/tevent_poll.c
r740 r988 31 31 32 32 struct poll_event_context { 33 /* a pointer back to the generic event_context */ 34 struct tevent_context *ev; 35 36 /* 37 * A DLIST for fresh fde's added by poll_event_add_fd but not 38 * picked up yet by poll_event_loop_once 39 */ 40 struct tevent_fd *fresh; 41 /* 42 * A DLIST for disabled fde's. 43 */ 44 struct tevent_fd *disabled; 45 /* 46 * one or more events were deleted or disabled 47 */ 48 bool deleted; 49 33 50 /* 34 51 * These two arrays are maintained together. 35 52 */ 36 53 struct pollfd *fds; 37 struct tevent_fd **fd_events; 38 uint64_t num_fds; 39 40 /* information for exiting from the event loop */ 41 int exit_code; 54 struct tevent_fd **fdes; 55 unsigned num_fds; 56 57 /* 58 * Signal fd to wake the poll() thread 59 */ 60 int signal_fd; 42 61 }; 43 62 63 static int poll_event_context_destructor(struct poll_event_context *poll_ev) 64 { 65 struct tevent_fd *fd, *fn; 66 67 for (fd = poll_ev->fresh; fd; fd = fn) { 68 fn = fd->next; 69 fd->event_ctx = NULL; 70 DLIST_REMOVE(poll_ev->fresh, fd); 71 } 72 73 for (fd = poll_ev->disabled; fd; fd = fn) { 74 fn = fd->next; 75 fd->event_ctx = NULL; 76 DLIST_REMOVE(poll_ev->disabled, fd); 77 } 78 79 if (poll_ev->signal_fd == -1) { 80 /* 81 * Non-threaded, no signal pipe 82 */ 83 return 0; 84 } 85 86 close(poll_ev->signal_fd); 87 poll_ev->signal_fd = -1; 88 89 if (poll_ev->num_fds == 0) { 90 return 0; 91 } 92 if (poll_ev->fds[0].fd != -1) { 93 close(poll_ev->fds[0].fd); 94 poll_ev->fds[0].fd = -1; 95 } 96 return 0; 97 } 98 44 99 /* 45 create a select_event_context structure.100 create a poll_event_context structure. 46 101 */ 47 102 static int poll_event_context_init(struct tevent_context *ev) 48 103 { 49 104 struct poll_event_context *poll_ev; 105 106 /* 107 * we might be called during tevent_re_initialise() 108 * which means we need to free our old additional_data 109 * in order to detach old fd events from the 110 * poll_ev->fresh list 111 */ 112 TALLOC_FREE(ev->additional_data); 50 113 51 114 poll_ev = talloc_zero(ev, struct poll_event_context); … … 53 116 return -1; 54 117 } 118 poll_ev->ev = ev; 119 poll_ev->signal_fd = -1; 55 120 ev->additional_data = poll_ev; 121 talloc_set_destructor(poll_ev, poll_event_context_destructor); 56 122 return 0; 123 } 124 125 static bool set_nonblock(int fd) 126 { 127 int val; 128 129 val = fcntl(fd, F_GETFL, 0); 130 if (val == -1) { 131 return false; 132 } 133 val |= O_NONBLOCK; 134 135 return (fcntl(fd, F_SETFL, val) != -1); 136 } 137 138 static int poll_event_context_init_mt(struct tevent_context *ev) 139 { 140 struct poll_event_context *poll_ev; 141 struct pollfd *pfd; 142 int fds[2]; 143 int ret; 144 145 ret = poll_event_context_init(ev); 146 if (ret == -1) { 147 return ret; 148 } 149 150 poll_ev = talloc_get_type_abort( 151 ev->additional_data, struct poll_event_context); 152 153 poll_ev->fds = talloc_zero(poll_ev, struct pollfd); 154 if (poll_ev->fds == NULL) { 155 return -1; 156 } 157 158 ret = pipe(fds); 159 if (ret == -1) { 160 return -1; 161 } 162 163 if (!set_nonblock(fds[0]) || !set_nonblock(fds[1])) { 164 close(fds[0]); 165 close(fds[1]); 166 return -1; 167 } 168 169 poll_ev->signal_fd = fds[1]; 170 171 pfd = &poll_ev->fds[0]; 172 pfd->fd = fds[0]; 173 pfd->events = (POLLIN|POLLHUP); 174 175 poll_ev->num_fds = 1; 176 177 talloc_set_destructor(poll_ev, poll_event_context_destructor); 178 179 return 0; 180 } 181 182 static void poll_event_wake_pollthread(struct poll_event_context *poll_ev) 183 { 184 char c; 185 ssize_t ret; 186 187 if (poll_ev->signal_fd == -1) { 188 return; 189 } 190 c = 0; 191 do { 192 ret = write(poll_ev->signal_fd, &c, sizeof(c)); 193 } while ((ret == -1) && (errno == EINTR)); 194 } 195 196 static void poll_event_drain_signal_fd(struct poll_event_context *poll_ev) 197 { 198 char buf[16]; 199 ssize_t ret; 200 int fd; 201 202 if (poll_ev->signal_fd == -1) { 203 return; 204 } 205 206 if (poll_ev->num_fds < 1) { 207 return; 208 } 209 fd = poll_ev->fds[0].fd; 210 211 do { 212 ret = read(fd, buf, sizeof(buf)); 213 } while (ret == sizeof(buf)); 57 214 } 58 215 … … 63 220 { 64 221 struct tevent_context *ev = fde->event_ctx; 65 struct poll_event_context *poll_ev = NULL; 66 struct tevent_fd *moved_fde; 222 struct poll_event_context *poll_ev; 67 223 uint64_t del_idx = fde->additional_flags; 68 224 … … 74 230 ev->additional_data, struct poll_event_context); 75 231 76 moved_fde = poll_ev->fd_events[poll_ev->num_fds-1]; 77 poll_ev->fd_events[del_idx] = moved_fde; 78 poll_ev->fds[del_idx] = poll_ev->fds[poll_ev->num_fds-1]; 79 moved_fde->additional_flags = del_idx; 80 81 poll_ev->num_fds -= 1; 232 if (del_idx == UINT64_MAX) { 233 struct tevent_fd **listp = 234 (struct tevent_fd **)fde->additional_data; 235 236 DLIST_REMOVE((*listp), fde); 237 goto done; 238 } 239 240 poll_ev->fdes[del_idx] = NULL; 241 poll_ev->deleted = true; 242 poll_event_wake_pollthread(poll_ev); 82 243 done: 83 244 return tevent_common_fd_destructor(fde); 245 } 246 247 static void poll_event_schedule_immediate(struct tevent_immediate *im, 248 struct tevent_context *ev, 249 tevent_immediate_handler_t handler, 250 void *private_data, 251 const char *handler_name, 252 const char *location) 253 { 254 struct poll_event_context *poll_ev = talloc_get_type_abort( 255 ev->additional_data, struct poll_event_context); 256 257 tevent_common_schedule_immediate(im, ev, handler, private_data, 258 handler_name, location); 259 poll_event_wake_pollthread(poll_ev); 260 } 261 262 /* 263 Private function called by "standard" backend fallback. 264 Note this only allows fallback to "poll" backend, not "poll-mt". 265 */ 266 _PRIVATE_ void tevent_poll_event_add_fd_internal(struct tevent_context *ev, 267 struct tevent_fd *fde) 268 { 269 struct poll_event_context *poll_ev = talloc_get_type_abort( 270 ev->additional_data, struct poll_event_context); 271 struct tevent_fd **listp; 272 273 if (fde->flags != 0) { 274 listp = &poll_ev->fresh; 275 } else { 276 listp = &poll_ev->disabled; 277 } 278 279 fde->additional_flags = UINT64_MAX; 280 fde->additional_data = listp; 281 282 DLIST_ADD((*listp), fde); 283 talloc_set_destructor(fde, poll_event_fd_destructor); 84 284 } 85 285 … … 98 298 struct poll_event_context *poll_ev = talloc_get_type_abort( 99 299 ev->additional_data, struct poll_event_context); 100 struct pollfd *pfd;101 300 struct tevent_fd *fde; 102 301 103 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags, 104 handler, private_data, 105 handler_name, location); 302 if (fd < 0) { 303 return NULL; 304 } 305 306 fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd); 106 307 if (fde == NULL) { 107 308 return NULL; 108 309 } 109 110 /* we allocate 16 slots to avoid a lot of reallocations */ 111 if (talloc_array_length(poll_ev->fds) == poll_ev->num_fds) { 112 struct pollfd *tmp_fds; 113 struct tevent_fd **tmp_fd_events; 114 tmp_fds = talloc_realloc( 115 poll_ev, poll_ev->fds, struct pollfd, 116 poll_ev->num_fds + 16); 117 if (tmp_fds == NULL) { 118 TALLOC_FREE(fde); 119 return NULL; 120 } 121 poll_ev->fds = tmp_fds; 122 123 tmp_fd_events = talloc_realloc( 124 poll_ev, poll_ev->fd_events, struct tevent_fd *, 125 poll_ev->num_fds + 16); 126 if (tmp_fd_events == NULL) { 127 TALLOC_FREE(fde); 128 return NULL; 129 } 130 poll_ev->fd_events = tmp_fd_events; 131 } 132 133 pfd = &poll_ev->fds[poll_ev->num_fds]; 134 135 pfd->fd = fd; 136 137 pfd->events = 0; 138 pfd->revents = 0; 139 140 if (flags & TEVENT_FD_READ) { 141 pfd->events |= (POLLIN|POLLHUP); 142 } 143 if (flags & TEVENT_FD_WRITE) { 144 pfd->events |= (POLLOUT); 145 } 146 147 fde->additional_flags = poll_ev->num_fds; 148 poll_ev->fd_events[poll_ev->num_fds] = fde; 149 150 poll_ev->num_fds += 1; 151 152 talloc_set_destructor(fde, poll_event_fd_destructor); 153 310 fde->event_ctx = ev; 311 fde->fd = fd; 312 fde->flags = flags; 313 fde->handler = handler; 314 fde->close_fn = NULL; 315 fde->private_data = private_data; 316 fde->handler_name = handler_name; 317 fde->location = location; 318 fde->additional_flags = UINT64_MAX; 319 fde->additional_data = NULL; 320 321 tevent_poll_event_add_fd_internal(ev, fde); 322 poll_event_wake_pollthread(poll_ev); 323 324 /* 325 * poll_event_loop_poll will take care of the rest in 326 * poll_event_setup_fresh 327 */ 154 328 return fde; 155 329 } … … 160 334 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags) 161 335 { 162 struct poll_event_context *poll_ev = talloc_get_type_abort(163 fde->event_ctx->additional_data, struct poll_event_context);336 struct tevent_context *ev = fde->event_ctx; 337 struct poll_event_context *poll_ev; 164 338 uint64_t idx = fde->additional_flags; 165 uint16_t pollflags = 0; 339 uint16_t pollflags; 340 341 if (ev == NULL) { 342 return; 343 } 344 poll_ev = talloc_get_type_abort( 345 ev->additional_data, struct poll_event_context); 346 347 fde->flags = flags; 348 349 if (idx == UINT64_MAX) { 350 struct tevent_fd **listp = 351 (struct tevent_fd **)fde->additional_data; 352 353 /* 354 * We move it between the fresh and disabled lists. 355 */ 356 DLIST_REMOVE((*listp), fde); 357 tevent_poll_event_add_fd_internal(ev, fde); 358 poll_event_wake_pollthread(poll_ev); 359 return; 360 } 361 362 if (fde->flags == 0) { 363 /* 364 * We need to remove it from the array 365 * and move it to the disabled list. 366 */ 367 poll_ev->fdes[idx] = NULL; 368 poll_ev->deleted = true; 369 DLIST_REMOVE(ev->fd_events, fde); 370 tevent_poll_event_add_fd_internal(ev, fde); 371 poll_event_wake_pollthread(poll_ev); 372 return; 373 } 374 375 pollflags = 0; 166 376 167 377 if (flags & TEVENT_FD_READ) { … … 171 381 pollflags |= (POLLOUT); 172 382 } 173 174 383 poll_ev->fds[idx].events = pollflags; 175 384 176 fde->flags = flags; 385 poll_event_wake_pollthread(poll_ev); 386 } 387 388 static bool poll_event_setup_fresh(struct tevent_context *ev, 389 struct poll_event_context *poll_ev) 390 { 391 struct tevent_fd *fde, *next; 392 unsigned num_fresh, num_fds; 393 394 if (poll_ev->deleted) { 395 unsigned first_fd = (poll_ev->signal_fd != -1) ? 1 : 0; 396 unsigned i; 397 398 for (i=first_fd; i < poll_ev->num_fds;) { 399 fde = poll_ev->fdes[i]; 400 if (fde != NULL) { 401 i++; 402 continue; 403 } 404 405 /* 406 * This fde was talloc_free()'ed. Delete it 407 * from the arrays 408 */ 409 poll_ev->num_fds -= 1; 410 if (poll_ev->num_fds == i) { 411 break; 412 } 413 poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds]; 414 poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds]; 415 if (poll_ev->fdes[i] != NULL) { 416 poll_ev->fdes[i]->additional_flags = i; 417 } 418 } 419 poll_ev->deleted = false; 420 } 421 422 if (poll_ev->fresh == NULL) { 423 return true; 424 } 425 426 num_fresh = 0; 427 for (fde = poll_ev->fresh; fde; fde = fde->next) { 428 num_fresh += 1; 429 } 430 num_fds = poll_ev->num_fds + num_fresh; 431 432 /* 433 * We check the length of fdes here. It is the last one 434 * enlarged, so if the realloc for poll_fd->fdes fails, 435 * poll_fd->fds will have at least the size of poll_fd->fdes 436 */ 437 438 if (num_fds >= talloc_array_length(poll_ev->fdes)) { 439 struct pollfd *tmp_fds; 440 struct tevent_fd **tmp_fdes; 441 unsigned array_length; 442 443 array_length = (num_fds + 15) & ~15; /* round up to 16 */ 444 445 tmp_fds = talloc_realloc( 446 poll_ev, poll_ev->fds, struct pollfd, array_length); 447 if (tmp_fds == NULL) { 448 return false; 449 } 450 poll_ev->fds = tmp_fds; 451 452 tmp_fdes = talloc_realloc( 453 poll_ev, poll_ev->fdes, struct tevent_fd *, 454 array_length); 455 if (tmp_fdes == NULL) { 456 return false; 457 } 458 poll_ev->fdes = tmp_fdes; 459 } 460 461 for (fde = poll_ev->fresh; fde; fde = next) { 462 struct pollfd *pfd; 463 464 pfd = &poll_ev->fds[poll_ev->num_fds]; 465 466 pfd->fd = fde->fd; 467 pfd->events = 0; 468 pfd->revents = 0; 469 470 if (fde->flags & TEVENT_FD_READ) { 471 pfd->events |= (POLLIN|POLLHUP); 472 } 473 if (fde->flags & TEVENT_FD_WRITE) { 474 pfd->events |= (POLLOUT); 475 } 476 477 fde->additional_flags = poll_ev->num_fds; 478 poll_ev->fdes[poll_ev->num_fds] = fde; 479 480 next = fde->next; 481 DLIST_REMOVE(poll_ev->fresh, fde); 482 DLIST_ADD(ev->fd_events, fde); 483 484 poll_ev->num_fds += 1; 485 } 486 return true; 177 487 } 178 488 179 489 /* 180 event loop handling using select()490 event loop handling using poll() 181 491 */ 182 492 static int poll_event_loop_poll(struct tevent_context *ev, … … 185 495 struct poll_event_context *poll_ev = talloc_get_type_abort( 186 496 ev->additional_data, struct poll_event_context); 187 struct tevent_fd *fde;188 497 int pollrtn; 189 498 int timeout = -1; 499 int poll_errno; 500 struct tevent_fd *fde = NULL; 501 struct tevent_fd *next = NULL; 502 unsigned i; 190 503 191 504 if (ev->signal_events && tevent_common_check_signal(ev)) { … … 198 511 } 199 512 513 poll_event_drain_signal_fd(poll_ev); 514 515 if (!poll_event_setup_fresh(ev, poll_ev)) { 516 return -1; 517 } 518 519 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT); 200 520 pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout); 201 202 if (pollrtn == -1 && errno == EINTR && ev->signal_events) { 521 poll_errno = errno; 522 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT); 523 524 if (pollrtn == -1 && poll_errno == EINTR && ev->signal_events) { 203 525 tevent_common_check_signal(ev); 204 526 return 0; 205 }206 207 if (pollrtn == -1 && errno == EBADF) {208 /* the socket is dead! this should never209 happen as the socket should have first been210 made readable and that should have removed211 the event, so this must be a bug. This is a212 fatal error. */213 tevent_debug(ev, TEVENT_DEBUG_FATAL,214 "ERROR: EBADF on poll_event_loop_once\n");215 poll_ev->exit_code = EBADF;216 return -1;217 527 } 218 528 … … 223 533 } 224 534 225 if (pollrtn > 0) { 226 /* at least one file descriptor is ready - check 227 which ones and call the handler, being careful to allow 228 the handler to remove itself when called */ 229 for (fde = ev->fd_events; fde; fde = fde->next) { 230 struct pollfd *pfd; 231 uint64_t pfd_idx = fde->additional_flags; 232 uint16_t flags = 0; 233 234 pfd = &poll_ev->fds[pfd_idx]; 235 236 if (pfd->revents & (POLLHUP|POLLERR)) { 237 /* If we only wait for TEVENT_FD_WRITE, we 238 should not tell the event handler about it, 239 and remove the writable flag, as we only 240 report errors when waiting for read events 241 to match the select behavior. */ 242 if (!(fde->flags & TEVENT_FD_READ)) { 243 TEVENT_FD_NOT_WRITEABLE(fde); 244 continue; 245 } 246 flags |= TEVENT_FD_READ; 535 if (pollrtn <= 0) { 536 /* 537 * No fd's ready 538 */ 539 return 0; 540 } 541 542 /* at least one file descriptor is ready - check 543 which ones and call the handler, being careful to allow 544 the handler to remove itself when called */ 545 546 for (fde = ev->fd_events; fde; fde = next) { 547 uint64_t idx = fde->additional_flags; 548 struct pollfd *pfd; 549 uint16_t flags = 0; 550 551 next = fde->next; 552 553 if (idx == UINT64_MAX) { 554 continue; 555 } 556 557 pfd = &poll_ev->fds[idx]; 558 559 if (pfd->revents & POLLNVAL) { 560 /* 561 * the socket is dead! this should never 562 * happen as the socket should have first been 563 * made readable and that should have removed 564 * the event, so this must be a bug. 565 * 566 * We ignore it here to match the epoll 567 * behavior. 568 */ 569 tevent_debug(ev, TEVENT_DEBUG_ERROR, 570 "POLLNVAL on fde[%p] fd[%d] - disabling\n", 571 fde, pfd->fd); 572 poll_ev->fdes[idx] = NULL; 573 poll_ev->deleted = true; 574 DLIST_REMOVE(ev->fd_events, fde); 575 fde->event_ctx = NULL; 576 continue; 577 } 578 579 if (pfd->revents & (POLLHUP|POLLERR)) { 580 /* If we only wait for TEVENT_FD_WRITE, we 581 should not tell the event handler about it, 582 and remove the writable flag, as we only 583 report errors when waiting for read events 584 to match the select behavior. */ 585 if (!(fde->flags & TEVENT_FD_READ)) { 586 TEVENT_FD_NOT_WRITEABLE(fde); 587 continue; 247 588 } 248 if (pfd->revents & POLLIN) { 249 flags |= TEVENT_FD_READ; 250 } 251 if (pfd->revents & POLLOUT) { 252 flags |= TEVENT_FD_WRITE; 253 } 254 if (flags != 0) { 255 fde->handler(ev, fde, flags, 256 fde->private_data); 257 break; 589 flags |= TEVENT_FD_READ; 590 } 591 if (pfd->revents & POLLIN) { 592 flags |= TEVENT_FD_READ; 593 } 594 if (pfd->revents & POLLOUT) { 595 flags |= TEVENT_FD_WRITE; 596 } 597 /* 598 * Note that fde->flags could be changed when using 599 * the poll_mt backend together with threads, 600 * that why we need to check pfd->revents and fde->flags 601 */ 602 flags &= fde->flags; 603 if (flags != 0) { 604 DLIST_DEMOTE(ev->fd_events, fde); 605 fde->handler(ev, fde, flags, fde->private_data); 606 return 0; 607 } 608 } 609 610 for (i = 0; i < poll_ev->num_fds; i++) { 611 if (poll_ev->fds[i].revents & POLLNVAL) { 612 /* 613 * the socket is dead! this should never 614 * happen as the socket should have first been 615 * made readable and that should have removed 616 * the event, so this must be a bug or 617 * a race in the poll_mt usage. 618 */ 619 fde = poll_ev->fdes[i]; 620 tevent_debug(ev, TEVENT_DEBUG_WARNING, 621 "POLLNVAL on dangling fd[%d] fde[%p] - disabling\n", 622 poll_ev->fds[i].fd, fde); 623 poll_ev->fdes[i] = NULL; 624 poll_ev->deleted = true; 625 if (fde != NULL) { 626 DLIST_REMOVE(ev->fd_events, fde); 627 fde->event_ctx = NULL; 258 628 } 259 629 } … … 287 657 288 658 return poll_event_loop_poll(ev, &tval); 659 } 660 661 static int poll_event_loop_wait(struct tevent_context *ev, 662 const char *location) 663 { 664 struct poll_event_context *poll_ev = talloc_get_type_abort( 665 ev->additional_data, struct poll_event_context); 666 667 /* 668 * loop as long as we have events pending 669 */ 670 while (ev->fd_events || 671 ev->timer_events || 672 ev->immediate_events || 673 ev->signal_events || 674 poll_ev->fresh || 675 poll_ev->disabled) { 676 int ret; 677 ret = _tevent_loop_once(ev, location); 678 if (ret != 0) { 679 tevent_debug(ev, TEVENT_DEBUG_FATAL, 680 "_tevent_loop_once() failed: %d - %s\n", 681 ret, strerror(errno)); 682 return ret; 683 } 684 } 685 686 tevent_debug(ev, TEVENT_DEBUG_WARNING, 687 "poll_event_loop_wait() out of events\n"); 688 return 0; 289 689 } 290 690 … … 295 695 .get_fd_flags = tevent_common_fd_get_flags, 296 696 .set_fd_flags = poll_event_set_fd_flags, 297 .add_timer = tevent_common_add_timer ,697 .add_timer = tevent_common_add_timer_v2, 298 698 .schedule_immediate = tevent_common_schedule_immediate, 299 699 .add_signal = tevent_common_add_signal, 300 700 .loop_once = poll_event_loop_once, 301 .loop_wait = tevent_common_loop_wait,701 .loop_wait = poll_event_loop_wait, 302 702 }; 303 703 … … 306 706 return tevent_register_backend("poll", &poll_event_ops); 307 707 } 708 709 static const struct tevent_ops poll_event_mt_ops = { 710 .context_init = poll_event_context_init_mt, 711 .add_fd = poll_event_add_fd, 712 .set_fd_close_fn = tevent_common_fd_set_close_fn, 713 .get_fd_flags = tevent_common_fd_get_flags, 714 .set_fd_flags = poll_event_set_fd_flags, 715 .add_timer = tevent_common_add_timer_v2, 716 .schedule_immediate = poll_event_schedule_immediate, 717 .add_signal = tevent_common_add_signal, 718 .loop_once = poll_event_loop_once, 719 .loop_wait = poll_event_loop_wait, 720 }; 721 722 _PRIVATE_ bool tevent_poll_mt_init(void) 723 { 724 return tevent_register_backend("poll_mt", &poll_event_mt_ops); 725 } -
vendor/current/lib/tevent/tevent_queue.c
r414 r988 134 134 void *private_data) 135 135 { 136 struct tevent_queue *q = talloc_get_type(private_data, 137 struct tevent_queue); 136 struct tevent_queue *q = 137 talloc_get_type_abort(private_data, 138 struct tevent_queue); 138 139 139 140 if (!q->running) { 141 return; 142 } 143 144 if (!q->list) { 140 145 return; 141 146 } … … 143 148 q->list->triggered = true; 144 149 q->list->trigger(q->list->req, q->list->private_data); 150 } 151 152 static struct tevent_queue_entry *tevent_queue_add_internal( 153 struct tevent_queue *queue, 154 struct tevent_context *ev, 155 struct tevent_req *req, 156 tevent_queue_trigger_fn_t trigger, 157 void *private_data, 158 bool allow_direct) 159 { 160 struct tevent_queue_entry *e; 161 162 e = talloc_zero(req, struct tevent_queue_entry); 163 if (e == NULL) { 164 return NULL; 165 } 166 167 e->queue = queue; 168 e->req = req; 169 e->ev = ev; 170 e->trigger = trigger; 171 e->private_data = private_data; 172 173 /* 174 * if there is no trigger, it is just a blocker 175 */ 176 if (trigger == NULL) { 177 e->triggered = true; 178 } 179 180 if (queue->length > 0) { 181 /* 182 * if there are already entries in the 183 * queue do not optimize. 184 */ 185 allow_direct = false; 186 } 187 188 if (req->async.fn != NULL) { 189 /* 190 * If the callers wants to optimize for the 191 * empty queue case, call the trigger only 192 * if there is no callback defined for the 193 * request yet. 194 */ 195 allow_direct = false; 196 } 197 198 DLIST_ADD_END(queue->list, e); 199 queue->length++; 200 talloc_set_destructor(e, tevent_queue_entry_destructor); 201 202 if (!queue->running) { 203 return e; 204 } 205 206 if (queue->list->triggered) { 207 return e; 208 } 209 210 /* 211 * If allowed we directly call the trigger 212 * avoiding possible delays caused by 213 * an immediate event. 214 */ 215 if (allow_direct) { 216 queue->list->triggered = true; 217 queue->list->trigger(queue->list->req, 218 queue->list->private_data); 219 return e; 220 } 221 222 tevent_schedule_immediate(queue->immediate, 223 queue->list->ev, 224 tevent_queue_immediate_trigger, 225 queue); 226 227 return e; 145 228 } 146 229 … … 153 236 struct tevent_queue_entry *e; 154 237 155 e = talloc_zero(req, struct tevent_queue_entry); 238 e = tevent_queue_add_internal(queue, ev, req, 239 trigger, private_data, false); 156 240 if (e == NULL) { 157 241 return false; 158 242 } 159 243 160 e->queue = queue; 161 e->req = req; 162 e->ev = ev; 163 e->trigger = trigger; 164 e->private_data = private_data; 165 166 DLIST_ADD_END(queue->list, e, struct tevent_queue_entry *); 167 queue->length++; 168 talloc_set_destructor(e, tevent_queue_entry_destructor); 169 170 if (!queue->running) { 171 return true; 244 return true; 245 } 246 247 struct tevent_queue_entry *tevent_queue_add_entry( 248 struct tevent_queue *queue, 249 struct tevent_context *ev, 250 struct tevent_req *req, 251 tevent_queue_trigger_fn_t trigger, 252 void *private_data) 253 { 254 return tevent_queue_add_internal(queue, ev, req, 255 trigger, private_data, false); 256 } 257 258 struct tevent_queue_entry *tevent_queue_add_optimize_empty( 259 struct tevent_queue *queue, 260 struct tevent_context *ev, 261 struct tevent_req *req, 262 tevent_queue_trigger_fn_t trigger, 263 void *private_data) 264 { 265 return tevent_queue_add_internal(queue, ev, req, 266 trigger, private_data, true); 267 } 268 269 void tevent_queue_start(struct tevent_queue *queue) 270 { 271 if (queue->running) { 272 /* already started */ 273 return; 274 } 275 276 queue->running = true; 277 278 if (!queue->list) { 279 return; 172 280 } 173 281 174 282 if (queue->list->triggered) { 175 return true;283 return; 176 284 } 177 285 … … 180 288 tevent_queue_immediate_trigger, 181 289 queue); 182 290 } 291 292 void tevent_queue_stop(struct tevent_queue *queue) 293 { 294 queue->running = false; 295 } 296 297 size_t tevent_queue_length(struct tevent_queue *queue) 298 { 299 return queue->length; 300 } 301 302 bool tevent_queue_running(struct tevent_queue *queue) 303 { 304 return queue->running; 305 } 306 307 struct tevent_queue_wait_state { 308 uint8_t dummy; 309 }; 310 311 static void tevent_queue_wait_trigger(struct tevent_req *req, 312 void *private_data); 313 314 struct tevent_req *tevent_queue_wait_send(TALLOC_CTX *mem_ctx, 315 struct tevent_context *ev, 316 struct tevent_queue *queue) 317 { 318 struct tevent_req *req; 319 struct tevent_queue_wait_state *state; 320 bool ok; 321 322 req = tevent_req_create(mem_ctx, &state, 323 struct tevent_queue_wait_state); 324 if (req == NULL) { 325 return NULL; 326 } 327 328 ok = tevent_queue_add(queue, ev, req, 329 tevent_queue_wait_trigger, 330 NULL); 331 if (!ok) { 332 tevent_req_oom(req); 333 return tevent_req_post(req, ev); 334 } 335 336 return req; 337 } 338 339 static void tevent_queue_wait_trigger(struct tevent_req *req, 340 void *private_data) 341 { 342 tevent_req_done(req); 343 } 344 345 bool tevent_queue_wait_recv(struct tevent_req *req) 346 { 347 enum tevent_req_state state; 348 uint64_t err; 349 350 if (tevent_req_is_error(req, &state, &err)) { 351 tevent_req_received(req); 352 return false; 353 } 354 355 tevent_req_received(req); 183 356 return true; 184 357 } 185 186 void tevent_queue_start(struct tevent_queue *queue)187 {188 if (queue->running) {189 /* already started */190 return;191 }192 193 queue->running = true;194 195 if (!queue->list) {196 return;197 }198 199 if (queue->list->triggered) {200 return;201 }202 203 tevent_schedule_immediate(queue->immediate,204 queue->list->ev,205 tevent_queue_immediate_trigger,206 queue);207 }208 209 void tevent_queue_stop(struct tevent_queue *queue)210 {211 queue->running = false;212 }213 214 size_t tevent_queue_length(struct tevent_queue *queue)215 {216 return queue->length;217 } -
vendor/current/lib/tevent/tevent_req.c
r740 r988 52 52 } 53 53 54 static int tevent_req_destructor(struct tevent_req *req); 55 54 56 struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx, 55 57 void *pdata, … … 62 64 void *data; 63 65 64 req = talloc_zero(mem_ctx, struct tevent_req); 66 req = talloc_pooled_object( 67 mem_ctx, struct tevent_req, 2, 68 sizeof(struct tevent_immediate) + data_size); 65 69 if (req == NULL) { 66 70 return NULL; 67 71 } 72 ZERO_STRUCTP(req); 68 73 req->internal.private_type = type; 69 74 req->internal.create_location = location; 70 req->internal.finish_location = NULL;71 75 req->internal.state = TEVENT_REQ_IN_PROGRESS; 72 76 req->internal.trigger = tevent_create_immediate(req); … … 85 89 req->data = data; 86 90 91 talloc_set_destructor(req, tevent_req_destructor); 92 87 93 *ppdata = data; 88 94 return req; 89 95 } 90 96 97 static int tevent_req_destructor(struct tevent_req *req) 98 { 99 tevent_req_received(req); 100 return 0; 101 } 102 91 103 void _tevent_req_notify_callback(struct tevent_req *req, const char *location) 92 104 { 93 105 req->internal.finish_location = location; 106 if (req->internal.defer_callback_ev) { 107 (void)tevent_req_post(req, req->internal.defer_callback_ev); 108 req->internal.defer_callback_ev = NULL; 109 return; 110 } 94 111 if (req->async.fn != NULL) { 95 112 req->async.fn(req); 96 113 } 114 } 115 116 static void tevent_req_cleanup(struct tevent_req *req) 117 { 118 if (req->private_cleanup.fn == NULL) { 119 return; 120 } 121 122 if (req->private_cleanup.state >= req->internal.state) { 123 /* 124 * Don't call the cleanup_function multiple times for the same 125 * state recursively 126 */ 127 return; 128 } 129 130 req->private_cleanup.state = req->internal.state; 131 req->private_cleanup.fn(req, req->internal.state); 97 132 } 98 133 … … 101 136 const char *location) 102 137 { 138 /* 139 * make sure we do not timeout after 140 * the request was already finished 141 */ 142 TALLOC_FREE(req->internal.timer); 143 103 144 req->internal.state = state; 145 req->internal.finish_location = location; 146 147 tevent_req_cleanup(req); 148 104 149 _tevent_req_notify_callback(req, location); 105 150 } … … 124 169 } 125 170 171 void _tevent_req_oom(struct tevent_req *req, const char *location) 172 { 173 tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location); 174 } 175 126 176 bool _tevent_req_nomem(const void *p, 127 177 struct tevent_req *req, … … 131 181 return false; 132 182 } 133 tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);183 _tevent_req_oom(req, location); 134 184 return true; 135 185 } … … 150 200 void *private_data) 151 201 { 152 struct tevent_req *req = talloc_get_type(private_data, 153 struct tevent_req); 202 struct tevent_req *req = 203 talloc_get_type_abort(private_data, 204 struct tevent_req); 154 205 155 206 tevent_req_finish(req, req->internal.state, … … 165 216 } 166 217 218 void tevent_req_defer_callback(struct tevent_req *req, 219 struct tevent_context *ev) 220 { 221 req->internal.defer_callback_ev = ev; 222 } 223 167 224 bool tevent_req_is_in_progress(struct tevent_req *req) 168 225 { … … 176 233 void tevent_req_received(struct tevent_req *req) 177 234 { 178 TALLOC_FREE(req->data); 235 talloc_set_destructor(req, NULL); 236 179 237 req->private_print = NULL; 238 req->private_cancel = NULL; 180 239 181 240 TALLOC_FREE(req->internal.trigger); … … 183 242 184 243 req->internal.state = TEVENT_REQ_RECEIVED; 244 245 tevent_req_cleanup(req); 246 247 TALLOC_FREE(req->data); 185 248 } 186 249 … … 218 281 void *private_data) 219 282 { 220 struct tevent_req *req = talloc_get_type(private_data, 221 struct tevent_req); 283 struct tevent_req *req = 284 talloc_get_type_abort(private_data, 285 struct tevent_req); 222 286 223 287 TALLOC_FREE(req->internal.timer); … … 276 340 return req->private_cancel(req); 277 341 } 342 343 void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn) 344 { 345 req->private_cleanup.state = req->internal.state; 346 req->private_cleanup.fn = fn; 347 } -
vendor/current/lib/tevent/tevent_select.c
r740 r988 36 36 /* the maximum file descriptor number in fd_events */ 37 37 int maxfd; 38 39 /* information for exiting from the event loop */40 int exit_code;41 38 }; 42 39 … … 47 44 { 48 45 struct select_event_context *select_ev; 46 47 /* 48 * We might be called during tevent_re_initialise() 49 * which means we need to free our old additional_data. 50 */ 51 TALLOC_FREE(ev->additional_data); 49 52 50 53 select_ev = talloc_zero(ev, struct select_event_context); … … 86 89 87 90 if (ev) { 88 select_ev = talloc_get_type (ev->additional_data,89 91 select_ev = talloc_get_type_abort(ev->additional_data, 92 struct select_event_context); 90 93 91 94 if (select_ev->maxfd == fde->fd) { … … 108 111 const char *location) 109 112 { 110 struct select_event_context *select_ev = talloc_get_type(ev->additional_data, 111 struct select_event_context); 113 struct select_event_context *select_ev = 114 talloc_get_type_abort(ev->additional_data, 115 struct select_event_context); 112 116 struct tevent_fd *fde; 113 117 … … 139 143 struct tevent_fd *fde; 140 144 int selrtn; 145 int select_errno; 141 146 142 147 /* we maybe need to recalculate the maxfd */ … … 151 156 for (fde = select_ev->ev->fd_events; fde; fde = fde->next) { 152 157 if (fde->fd < 0 || fde->fd >= FD_SETSIZE) { 158 tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL, 159 "ERROR: EBADF fd[%d] >= %d " 160 "select_event_loop_once\n", 161 fde->fd, FD_SETSIZE); 153 162 errno = EBADF; 154 163 return -1; … … 168 177 } 169 178 179 tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_BEFORE_WAIT); 170 180 selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); 171 172 if (selrtn == -1 && errno == EINTR && 181 select_errno = errno; 182 tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_AFTER_WAIT); 183 184 if (selrtn == -1 && select_errno == EINTR && 173 185 select_ev->ev->signal_events) { 174 186 tevent_common_check_signal(select_ev->ev); … … 176 188 } 177 189 178 if (selrtn == -1 && errno == EBADF) {190 if (selrtn == -1 && select_errno == EBADF) { 179 191 /* the socket is dead! this should never 180 192 happen as the socket should have first been … … 184 196 tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL, 185 197 "ERROR: EBADF on select_event_loop_once\n"); 186 select_ev->exit_code = EBADF;198 errno = select_errno; 187 199 return -1; 188 200 } … … 201 213 uint16_t flags = 0; 202 214 203 if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ; 204 if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE; 215 if (FD_ISSET(fde->fd, &r_fds) && (fde->flags & TEVENT_FD_READ)) { 216 flags |= TEVENT_FD_READ; 217 } 218 if (FD_ISSET(fde->fd, &w_fds) && (fde->flags & TEVENT_FD_WRITE)) { 219 flags |= TEVENT_FD_WRITE; 220 } 205 221 if (flags) { 222 DLIST_DEMOTE(select_ev->ev->fd_events, fde); 206 223 fde->handler(select_ev->ev, fde, flags, fde->private_data); 207 224 break; … … 218 235 static int select_event_loop_once(struct tevent_context *ev, const char *location) 219 236 { 220 struct select_event_context *select_ev = talloc_get_type(ev->additional_data, 221 struct select_event_context); 237 struct select_event_context *select_ev = 238 talloc_get_type_abort(ev->additional_data, 239 struct select_event_context); 222 240 struct timeval tval; 223 241 … … 246 264 .get_fd_flags = tevent_common_fd_get_flags, 247 265 .set_fd_flags = tevent_common_fd_set_flags, 248 .add_timer = tevent_common_add_timer ,266 .add_timer = tevent_common_add_timer_v2, 249 267 .schedule_immediate = tevent_common_schedule_immediate, 250 268 .add_signal = tevent_common_add_signal, -
vendor/current/lib/tevent/tevent_signal.c
r860 r988 1 /* 1 /* 2 2 Unix SMB/CIFS implementation. 3 3 … … 31 31 #include "tevent_util.h" 32 32 33 #define TEVENT_NUM_SIGNALS 6434 35 33 /* maximum number of SA_SIGINFO signals to hold in the queue. 36 34 NB. This *MUST* be a power of 2, in order for the ring buffer … … 38 36 for this. */ 39 37 40 #define TEVENT_SA_INFO_QUEUE_COUNT 64 38 #define TEVENT_SA_INFO_QUEUE_COUNT 256 39 40 size_t tevent_num_signals(void) 41 { 42 return TEVENT_NUM_SIGNALS; 43 } 44 45 size_t tevent_sa_info_queue_count(void) 46 { 47 return TEVENT_SA_INFO_QUEUE_COUNT; 48 } 41 49 42 50 struct tevent_sigcounter { … … 45 53 }; 46 54 55 #if defined(HAVE___SYNC_FETCH_AND_ADD) 56 #define TEVENT_SIG_INCREMENT(s) __sync_fetch_and_add(&((s).count), 1) 57 #elif defined(HAVE_ATOMIC_ADD_32) 58 #define TEVENT_SIG_INCREMENT(s) atomic_add_32(&((s).count), 1) 59 #else 47 60 #define TEVENT_SIG_INCREMENT(s) (s).count++ 61 #endif 48 62 #define TEVENT_SIG_SEEN(s, n) (s).seen += (n) 49 63 #define TEVENT_SIG_PENDING(s) ((s).seen != (s).count) … … 83 97 { 84 98 char c = 0; 85 ssize_t res;86 99 struct tevent_common_signal_list *sl; 87 100 struct tevent_context *ev = NULL; … … 96 109 ev = sl->se->event_ctx; 97 110 /* doesn't matter if this pipe overflows */ 98 res =write(ev->pipe_fds[1], &c, 1);111 (void) write(ev->pipe_fds[1], &c, 1); 99 112 } 100 113 } … … 174 187 static int tevent_signal_destructor(struct tevent_signal *se) 175 188 { 176 struct tevent_common_signal_list *sl ;177 sl = talloc_get_type(se->additional_data,178 189 struct tevent_common_signal_list *sl = 190 talloc_get_type_abort(se->additional_data, 191 struct tevent_common_signal_list); 179 192 180 193 if (se->event_ctx) { 181 DLIST_REMOVE(se->event_ctx->signal_events, se); 194 struct tevent_context *ev = se->event_ctx; 195 196 DLIST_REMOVE(ev->signal_events, se); 197 198 if (ev->signal_events == NULL && ev->pipe_fde != NULL) { 199 /* 200 * This was the last signal. Destroy the pipe. 201 */ 202 TALLOC_FREE(ev->pipe_fde); 203 204 close(ev->pipe_fds[0]); 205 close(ev->pipe_fds[1]); 206 } 182 207 } 183 208 … … 188 213 if (sig_state->oldact[se->signum]) { 189 214 sigaction(se->signum, sig_state->oldact[se->signum], NULL); 215 talloc_free(sig_state->oldact[se->signum]); 190 216 sig_state->oldact[se->signum] = NULL; 191 217 } … … 210 236 { 211 237 char c[16]; 212 ssize_t res;213 238 /* its non-blocking, doesn't matter if we read too much */ 214 res =read(fde->fd, c, sizeof(c));239 (void) read(fde->fd, c, sizeof(c)); 215 240 } 216 241 … … 316 341 if (sig_state->oldact[signum] == NULL) { 317 342 talloc_free(se); 318 return NULL; 343 return NULL; 319 344 } 320 345 if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) { 346 talloc_free(sig_state->oldact[signum]); 347 sig_state->oldact[signum] = NULL; 321 348 talloc_free(se); 322 349 return NULL; … … 339 366 } 340 367 368 struct tevent_se_exists { 369 struct tevent_se_exists **myself; 370 }; 371 372 static int tevent_se_exists_destructor(struct tevent_se_exists *s) 373 { 374 *s->myself = NULL; 375 return 0; 376 } 341 377 342 378 /* … … 351 387 return 0; 352 388 } 353 389 354 390 for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) { 355 391 struct tevent_common_signal_list *sl, *next; … … 367 403 for (sl=sig_state->sig_handlers[i];sl;sl=next) { 368 404 struct tevent_signal *se = sl->se; 405 struct tevent_se_exists *exists; 406 369 407 next = sl->next; 408 409 /* 410 * We have to be careful to not touch "se" 411 * after it was deleted in its handler. Thus 412 * we allocate a child whose destructor will 413 * tell by nulling out itself that its parent 414 * is gone. 415 */ 416 exists = talloc(se, struct tevent_se_exists); 417 if (exists == NULL) { 418 continue; 419 } 420 exists->myself = &exists; 421 talloc_set_destructor( 422 exists, tevent_se_exists_destructor); 423 370 424 #ifdef SA_SIGINFO 371 425 if (se->sa_flags & SA_SIGINFO) { … … 382 436 % TEVENT_SA_INFO_QUEUE_COUNT; 383 437 se->handler(ev, se, i, 1, 384 (void*)&sig_state->sig_info[i][ofs], 438 (void*)&sig_state->sig_info[i][ofs], 385 439 se->private_data); 440 if (!exists) { 441 break; 442 } 386 443 } 387 444 #ifdef SA_RESETHAND 388 if ( se->sa_flags & SA_RESETHAND) {445 if (exists && (se->sa_flags & SA_RESETHAND)) { 389 446 talloc_free(se); 390 447 } 391 448 #endif 449 talloc_free(exists); 392 450 continue; 393 451 } … … 395 453 se->handler(ev, se, i, count, NULL, se->private_data); 396 454 #ifdef SA_RESETHAND 397 if ( se->sa_flags & SA_RESETHAND) {455 if (exists && (se->sa_flags & SA_RESETHAND)) { 398 456 talloc_free(se); 399 457 } 400 458 #endif 401 } 402 403 #ifdef SA_SIGINFO 404 if (clear_processed_siginfo) { 459 talloc_free(exists); 460 } 461 462 #ifdef SA_SIGINFO 463 if (clear_processed_siginfo && sig_state->sig_info[i] != NULL) { 405 464 uint32_t j; 406 465 for (j=0;j<count;j++) { … … 441 500 void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se) 442 501 { 443 struct tevent_common_signal_list *sl ;444 sl = talloc_get_type(se->additional_data,445 502 struct tevent_common_signal_list *sl = 503 talloc_get_type_abort(se->additional_data, 504 struct tevent_common_signal_list); 446 505 447 506 tevent_common_signal_list_destructor(sl); … … 450 509 if (sig_state->oldact[se->signum]) { 451 510 sigaction(se->signum, sig_state->oldact[se->signum], NULL); 511 talloc_free(sig_state->oldact[se->signum]); 452 512 sig_state->oldact[se->signum] = NULL; 453 513 } -
vendor/current/lib/tevent/tevent_standard.c
r740 r988 2 2 Unix SMB/CIFS implementation. 3 3 main select loop and event handling 4 Copyright (C) Andrew Tridgell 2003-20055 Copyright (C) Stefan Metzmacher 2005-20094 Copyright (C) Stefan Metzmacher 2013 5 Copyright (C) Jeremy Allison 2013 6 6 7 7 ** NOTE! The following LGPL license applies to the tevent … … 27 27 28 28 - we try to use epoll if configure detected support for it 29 otherwise we use select()29 otherwise we use poll() 30 30 - if epoll is broken on the system or the kernel doesn't support it 31 at runtime we fallback to select()31 at runtime we fallback to poll() 32 32 */ 33 33 34 34 #include "replace.h" 35 #include "system/filesys.h"36 #include "system/select.h"37 35 #include "tevent.h" 38 36 #include "tevent_util.h" 39 37 #include "tevent_internal.h" 40 38 41 struct std_event_context { 42 /* a pointer back to the generic event_context */ 43 struct tevent_context *ev; 44 45 /* the maximum file descriptor number in fd_events */ 46 int maxfd; 47 48 /* information for exiting from the event loop */ 49 int exit_code; 50 51 /* when using epoll this is the handle from epoll_create */ 52 int epoll_fd; 53 54 /* our pid at the time the epoll_fd was created */ 55 pid_t pid; 39 struct std_event_glue { 40 const struct tevent_ops *epoll_ops; 41 const struct tevent_ops *poll_ops; 42 struct tevent_ops *glue_ops; 43 bool fallback_replay; 56 44 }; 57 45 58 /* use epoll if it is available */ 59 #if HAVE_EPOLL 46 static int std_event_context_init(struct tevent_context *ev); 47 48 static const struct tevent_ops std_event_ops = { 49 .context_init = std_event_context_init, 50 }; 51 60 52 /* 61 called when a epoll call fails, and we should fallback 62 to using select 63 */ 64 static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason) 65 { 66 tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL, 67 "%s (%s) - falling back to select()\n", 68 reason, strerror(errno)); 69 close(std_ev->epoll_fd); 70 std_ev->epoll_fd = -1; 71 talloc_set_destructor(std_ev, NULL); 72 } 73 53 If this function gets called. epoll failed at runtime. 54 Move us to using poll instead. If we return false here, 55 caller should abort(). 56 */ 57 #ifdef HAVE_EPOLL 58 static bool std_fallback_to_poll(struct tevent_context *ev, bool replay) 59 { 60 void *glue_ptr = talloc_parent(ev->ops); 61 struct std_event_glue *glue = 62 talloc_get_type_abort(glue_ptr, 63 struct std_event_glue); 64 int ret; 65 struct tevent_fd *fde; 66 struct tevent_fd *fde_next; 67 68 glue->fallback_replay = replay; 69 70 /* First switch all the ops to poll. */ 71 glue->epoll_ops = NULL; 72 73 /* 74 * Set custom_ops the same as poll. 75 */ 76 *glue->glue_ops = *glue->poll_ops; 77 glue->glue_ops->context_init = std_event_context_init; 78 79 /* Next initialize the poll backend. */ 80 ret = glue->poll_ops->context_init(ev); 81 if (ret != 0) { 82 return false; 83 } 84 85 /* 86 * Now we have to change all the existing file descriptor 87 * events from the epoll backend to the poll backend. 88 */ 89 for (fde = ev->fd_events; fde; fde = fde_next) { 90 /* 91 * We must remove this fde off the ev->fd_events list. 92 */ 93 fde_next = fde->next; 94 95 /* Remove from the ev->fd_events list. */ 96 DLIST_REMOVE(ev->fd_events, fde); 97 98 /* Re-add this event as a poll backend event. */ 99 tevent_poll_event_add_fd_internal(ev, fde); 100 } 101 102 return true; 103 } 104 #endif 105 106 static int std_event_loop_once(struct tevent_context *ev, const char *location) 107 { 108 void *glue_ptr = talloc_parent(ev->ops); 109 struct std_event_glue *glue = 110 talloc_get_type_abort(glue_ptr, 111 struct std_event_glue); 112 int ret; 113 114 ret = glue->epoll_ops->loop_once(ev, location); 115 if (glue->epoll_ops != NULL) { 116 /* No fallback */ 117 return ret; 118 } 119 120 if (!glue->fallback_replay) { 121 /* 122 * The problem happened while modifying an event. 123 * An event handler was triggered in this case 124 * and there is no need to call loop_once() again. 125 */ 126 return ret; 127 } 128 129 return glue->poll_ops->loop_once(ev, location); 130 } 131 132 static int std_event_loop_wait(struct tevent_context *ev, const char *location) 133 { 134 void *glue_ptr = talloc_parent(ev->ops); 135 struct std_event_glue *glue = 136 talloc_get_type_abort(glue_ptr, 137 struct std_event_glue); 138 int ret; 139 140 ret = glue->epoll_ops->loop_wait(ev, location); 141 if (glue->epoll_ops != NULL) { 142 /* No fallback */ 143 return ret; 144 } 145 146 return glue->poll_ops->loop_wait(ev, location); 147 } 74 148 /* 75 map from TEVENT_FD_* to EPOLLIN/EPOLLOUT 76 */ 77 static uint32_t epoll_map_flags(uint16_t flags) 78 { 79 uint32_t ret = 0; 80 if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP); 81 if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP); 82 return ret; 83 } 84 85 /* 86 free the epoll fd 87 */ 88 static int epoll_ctx_destructor(struct std_event_context *std_ev) 89 { 90 if (std_ev->epoll_fd != -1) { 91 close(std_ev->epoll_fd); 92 } 93 std_ev->epoll_fd = -1; 94 return 0; 95 } 96 97 /* 98 init the epoll fd 99 */ 100 static void epoll_init_ctx(struct std_event_context *std_ev) 101 { 102 std_ev->epoll_fd = epoll_create(64); 103 std_ev->pid = getpid(); 104 talloc_set_destructor(std_ev, epoll_ctx_destructor); 105 } 106 107 static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde); 108 109 /* 110 reopen the epoll handle when our pid changes 111 see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 112 demonstration of why this is needed 113 */ 114 static void epoll_check_reopen(struct std_event_context *std_ev) 115 { 116 struct tevent_fd *fde; 117 118 if (std_ev->pid == getpid()) { 119 return; 120 } 121 122 close(std_ev->epoll_fd); 123 std_ev->epoll_fd = epoll_create(64); 124 if (std_ev->epoll_fd == -1) { 125 tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL, 126 "Failed to recreate epoll handle after fork\n"); 127 return; 128 } 129 std_ev->pid = getpid(); 130 for (fde=std_ev->ev->fd_events;fde;fde=fde->next) { 131 epoll_add_event(std_ev, fde); 132 } 133 } 134 135 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0) 136 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1) 137 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2) 138 139 /* 140 add the epoll event to the given fd_event 141 */ 142 static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde) 143 { 144 struct epoll_event event; 145 if (std_ev->epoll_fd == -1) return; 146 147 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 148 149 /* if we don't want events yet, don't add an epoll_event */ 150 if (fde->flags == 0) return; 151 152 ZERO_STRUCT(event); 153 event.events = epoll_map_flags(fde->flags); 154 event.data.ptr = fde; 155 if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) { 156 epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed"); 157 } 158 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 159 160 /* only if we want to read we want to tell the event handler about errors */ 161 if (fde->flags & TEVENT_FD_READ) { 162 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 163 } 164 } 165 166 /* 167 delete the epoll event for given fd_event 168 */ 169 static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde) 170 { 171 struct epoll_event event; 172 if (std_ev->epoll_fd == -1) return; 173 174 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 175 176 /* if there's no epoll_event, we don't need to delete it */ 177 if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return; 178 179 ZERO_STRUCT(event); 180 event.events = epoll_map_flags(fde->flags); 181 event.data.ptr = fde; 182 epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event); 183 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; 184 } 185 186 /* 187 change the epoll event to the given fd_event 188 */ 189 static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde) 190 { 191 struct epoll_event event; 192 if (std_ev->epoll_fd == -1) return; 193 194 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 195 196 ZERO_STRUCT(event); 197 event.events = epoll_map_flags(fde->flags); 198 event.data.ptr = fde; 199 if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) { 200 epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed"); 201 } 202 203 /* only if we want to read we want to tell the event handler about errors */ 204 if (fde->flags & TEVENT_FD_READ) { 205 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 206 } 207 } 208 209 static void epoll_change_event(struct std_event_context *std_ev, struct tevent_fd *fde) 210 { 211 bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR); 212 bool want_read = (fde->flags & TEVENT_FD_READ); 213 bool want_write= (fde->flags & TEVENT_FD_WRITE); 214 215 if (std_ev->epoll_fd == -1) return; 216 217 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; 218 219 /* there's already an event */ 220 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) { 221 if (want_read || (want_write && !got_error)) { 222 epoll_mod_event(std_ev, fde); 223 return; 224 } 225 /* 226 * if we want to match the select behavior, we need to remove the epoll_event 227 * when the caller isn't interested in events. 228 * 229 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them 230 */ 231 epoll_del_event(std_ev, fde); 232 return; 233 } 234 235 /* there's no epoll_event attached to the fde */ 236 if (want_read || (want_write && !got_error)) { 237 epoll_add_event(std_ev, fde); 238 return; 239 } 240 } 241 242 /* 243 event loop handling using epoll 244 */ 245 static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp) 246 { 247 int ret, i; 248 #define MAXEVENTS 1 249 struct epoll_event events[MAXEVENTS]; 250 int timeout = -1; 251 252 if (std_ev->epoll_fd == -1) return -1; 253 254 if (tvalp) { 255 /* it's better to trigger timed events a bit later than to early */ 256 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000); 257 } 258 259 if (std_ev->ev->signal_events && 260 tevent_common_check_signal(std_ev->ev)) { 261 return 0; 262 } 263 264 ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout); 265 266 if (ret == -1 && errno == EINTR && std_ev->ev->signal_events) { 267 if (tevent_common_check_signal(std_ev->ev)) { 268 return 0; 269 } 270 } 271 272 if (ret == -1 && errno != EINTR) { 273 epoll_fallback_to_select(std_ev, "epoll_wait() failed"); 274 return -1; 275 } 276 277 if (ret == 0 && tvalp) { 278 /* we don't care about a possible delay here */ 279 tevent_common_loop_timer_delay(std_ev->ev); 280 return 0; 281 } 282 283 for (i=0;i<ret;i++) { 284 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 285 struct tevent_fd); 286 uint16_t flags = 0; 287 288 if (fde == NULL) { 289 epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data"); 149 Initialize the epoll backend and allow it to call a 150 switch function if epoll fails at runtime. 151 */ 152 static int std_event_context_init(struct tevent_context *ev) 153 { 154 struct std_event_glue *glue; 155 int ret; 156 157 /* 158 * If this is the first initialization 159 * we need to set up the allocated ops 160 * pointers. 161 */ 162 163 if (ev->ops == &std_event_ops) { 164 glue = talloc_zero(ev, struct std_event_glue); 165 if (glue == NULL) { 290 166 return -1; 291 167 } 292 if (events[i].events & (EPOLLHUP|EPOLLERR)) { 293 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; 294 /* 295 * if we only wait for TEVENT_FD_WRITE, we should not tell the 296 * event handler about it, and remove the epoll_event, 297 * as we only report errors when waiting for read events, 298 * to match the select() behavior 299 */ 300 if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) { 301 epoll_del_event(std_ev, fde); 302 continue; 303 } 304 flags |= TEVENT_FD_READ; 305 } 306 if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ; 307 if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE; 308 if (flags) { 309 fde->handler(std_ev->ev, fde, flags, fde->private_data); 310 break; 311 } 312 } 313 314 return 0; 315 } 316 #else 317 #define epoll_init_ctx(std_ev) 318 #define epoll_add_event(std_ev,fde) 319 #define epoll_del_event(std_ev,fde) 320 #define epoll_change_event(std_ev,fde) 321 #define epoll_event_loop(std_ev,tvalp) (-1) 322 #define epoll_check_reopen(std_ev) 168 169 glue->epoll_ops = tevent_find_ops_byname("epoll"); 170 171 glue->poll_ops = tevent_find_ops_byname("poll"); 172 if (glue->poll_ops == NULL) { 173 return -1; 174 } 175 176 /* 177 * Allocate space for our custom ops. 178 * Allocate as a child of our epoll_ops pointer 179 * so we can easily get to it using talloc_parent. 180 */ 181 glue->glue_ops = talloc_zero(glue, struct tevent_ops); 182 if (glue->glue_ops == NULL) { 183 talloc_free(glue); 184 return -1; 185 } 186 187 ev->ops = glue->glue_ops; 188 } else { 189 void *glue_ptr = talloc_parent(ev->ops); 190 glue = talloc_get_type_abort(glue_ptr, struct std_event_glue); 191 } 192 193 if (glue->epoll_ops != NULL) { 194 /* 195 * Set custom_ops the same as epoll, 196 * except re-init using std_event_context_init() 197 * and use std_event_loop_once() to add the 198 * ability to fallback to a poll backend on 199 * epoll runtime error. 200 */ 201 *glue->glue_ops = *glue->epoll_ops; 202 glue->glue_ops->context_init = std_event_context_init; 203 glue->glue_ops->loop_once = std_event_loop_once; 204 glue->glue_ops->loop_wait = std_event_loop_wait; 205 206 ret = glue->epoll_ops->context_init(ev); 207 if (ret == -1) { 208 goto fallback; 209 } 210 #ifdef HAVE_EPOLL 211 tevent_epoll_set_panic_fallback(ev, std_fallback_to_poll); 323 212 #endif 324 213 325 /* 326 create a std_event_context structure. 327 */ 328 static int std_event_context_init(struct tevent_context *ev) 329 { 330 struct std_event_context *std_ev; 331 332 std_ev = talloc_zero(ev, struct std_event_context); 333 if (!std_ev) return -1; 334 std_ev->ev = ev; 335 std_ev->epoll_fd = -1; 336 337 epoll_init_ctx(std_ev); 338 339 ev->additional_data = std_ev; 340 return 0; 341 } 342 343 /* 344 recalculate the maxfd 345 */ 346 static void calc_maxfd(struct std_event_context *std_ev) 347 { 348 struct tevent_fd *fde; 349 350 std_ev->maxfd = 0; 351 for (fde = std_ev->ev->fd_events; fde; fde = fde->next) { 352 if (fde->fd > std_ev->maxfd) { 353 std_ev->maxfd = fde->fd; 354 } 355 } 356 } 357 358 359 /* to mark the ev->maxfd invalid 360 * this means we need to recalculate it 361 */ 362 #define EVENT_INVALID_MAXFD (-1) 363 364 /* 365 destroy an fd_event 366 */ 367 static int std_event_fd_destructor(struct tevent_fd *fde) 368 { 369 struct tevent_context *ev = fde->event_ctx; 370 struct std_event_context *std_ev = NULL; 371 372 if (ev) { 373 std_ev = talloc_get_type(ev->additional_data, 374 struct std_event_context); 375 376 epoll_check_reopen(std_ev); 377 378 if (std_ev->maxfd == fde->fd) { 379 std_ev->maxfd = EVENT_INVALID_MAXFD; 380 } 381 382 epoll_del_event(std_ev, fde); 383 } 384 385 return tevent_common_fd_destructor(fde); 386 } 387 388 /* 389 add a fd based event 390 return NULL on failure (memory allocation error) 391 */ 392 static struct tevent_fd *std_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx, 393 int fd, uint16_t flags, 394 tevent_fd_handler_t handler, 395 void *private_data, 396 const char *handler_name, 397 const char *location) 398 { 399 struct std_event_context *std_ev = talloc_get_type(ev->additional_data, 400 struct std_event_context); 401 struct tevent_fd *fde; 402 403 epoll_check_reopen(std_ev); 404 405 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags, 406 handler, private_data, 407 handler_name, location); 408 if (!fde) return NULL; 409 410 if ((std_ev->maxfd != EVENT_INVALID_MAXFD) 411 && (fde->fd > std_ev->maxfd)) { 412 std_ev->maxfd = fde->fd; 413 } 414 talloc_set_destructor(fde, std_event_fd_destructor); 415 416 epoll_add_event(std_ev, fde); 417 418 return fde; 419 } 420 421 /* 422 set the fd event flags 423 */ 424 static void std_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags) 425 { 426 struct tevent_context *ev; 427 struct std_event_context *std_ev; 428 429 if (fde->flags == flags) return; 430 431 ev = fde->event_ctx; 432 std_ev = talloc_get_type(ev->additional_data, struct std_event_context); 433 434 fde->flags = flags; 435 436 epoll_check_reopen(std_ev); 437 438 epoll_change_event(std_ev, fde); 439 } 440 441 /* 442 event loop handling using select() 443 */ 444 static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp) 445 { 446 fd_set r_fds, w_fds; 447 struct tevent_fd *fde; 448 int selrtn; 449 450 /* we maybe need to recalculate the maxfd */ 451 if (std_ev->maxfd == EVENT_INVALID_MAXFD) { 452 calc_maxfd(std_ev); 453 } 454 455 FD_ZERO(&r_fds); 456 FD_ZERO(&w_fds); 457 458 /* setup any fd events */ 459 for (fde = std_ev->ev->fd_events; fde; fde = fde->next) { 460 if (fde->fd < 0 || fde->fd >= FD_SETSIZE) { 461 std_ev->exit_code = EBADF; 462 return -1; 463 } 464 if (fde->flags & TEVENT_FD_READ) { 465 FD_SET(fde->fd, &r_fds); 466 } 467 if (fde->flags & TEVENT_FD_WRITE) { 468 FD_SET(fde->fd, &w_fds); 469 } 470 } 471 472 if (std_ev->ev->signal_events && 473 tevent_common_check_signal(std_ev->ev)) { 474 return 0; 475 } 476 477 selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); 478 479 if (selrtn == -1 && errno == EINTR && 480 std_ev->ev->signal_events) { 481 tevent_common_check_signal(std_ev->ev); 482 return 0; 483 } 484 485 if (selrtn == -1 && errno == EBADF) { 486 /* the socket is dead! this should never 487 happen as the socket should have first been 488 made readable and that should have removed 489 the event, so this must be a bug. This is a 490 fatal error. */ 491 tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL, 492 "ERROR: EBADF on std_event_loop_once\n"); 493 std_ev->exit_code = EBADF; 494 return -1; 495 } 496 497 if (selrtn == 0 && tvalp) { 498 /* we don't care about a possible delay here */ 499 tevent_common_loop_timer_delay(std_ev->ev); 500 return 0; 501 } 502 503 if (selrtn > 0) { 504 /* at least one file descriptor is ready - check 505 which ones and call the handler, being careful to allow 506 the handler to remove itself when called */ 507 for (fde = std_ev->ev->fd_events; fde; fde = fde->next) { 508 uint16_t flags = 0; 509 510 if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ; 511 if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE; 512 if (flags & fde->flags) { 513 fde->handler(std_ev->ev, fde, flags, fde->private_data); 514 break; 515 } 516 } 517 } 518 519 return 0; 520 } 521 522 /* 523 do a single event loop using the events defined in ev 524 */ 525 static int std_event_loop_once(struct tevent_context *ev, const char *location) 526 { 527 struct std_event_context *std_ev = talloc_get_type(ev->additional_data, 528 struct std_event_context); 529 struct timeval tval; 530 531 if (ev->signal_events && 532 tevent_common_check_signal(ev)) { 533 return 0; 534 } 535 536 if (ev->immediate_events && 537 tevent_common_loop_immediate(ev)) { 538 return 0; 539 } 540 541 tval = tevent_common_loop_timer_delay(ev); 542 if (tevent_timeval_is_zero(&tval)) { 543 return 0; 544 } 545 546 epoll_check_reopen(std_ev); 547 548 if (epoll_event_loop(std_ev, &tval) == 0) { 549 return 0; 550 } 551 552 return std_event_loop_select(std_ev, &tval); 553 } 554 555 static const struct tevent_ops std_event_ops = { 556 .context_init = std_event_context_init, 557 .add_fd = std_event_add_fd, 558 .set_fd_close_fn = tevent_common_fd_set_close_fn, 559 .get_fd_flags = tevent_common_fd_get_flags, 560 .set_fd_flags = std_event_set_fd_flags, 561 .add_timer = tevent_common_add_timer, 562 .schedule_immediate = tevent_common_schedule_immediate, 563 .add_signal = tevent_common_add_signal, 564 .loop_once = std_event_loop_once, 565 .loop_wait = tevent_common_loop_wait, 566 }; 567 214 return ret; 215 } 216 217 fallback: 218 glue->epoll_ops = NULL; 219 220 /* 221 * Set custom_ops the same as poll. 222 */ 223 *glue->glue_ops = *glue->poll_ops; 224 glue->glue_ops->context_init = std_event_context_init; 225 226 return glue->poll_ops->context_init(ev); 227 } 568 228 569 229 _PRIVATE_ bool tevent_standard_init(void) … … 571 231 return tevent_register_backend("standard", &std_event_ops); 572 232 } 573 -
vendor/current/lib/tevent/tevent_timed.c
r740 r988 134 134 static int tevent_common_timed_destructor(struct tevent_timer *te) 135 135 { 136 if (te->event_ctx == NULL) { 137 return 0; 138 } 139 136 140 tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE, 137 141 "Destroying timer event %p \"%s\"\n", 138 142 te, te->handler_name); 139 143 140 if (te->event_ctx) { 141 DLIST_REMOVE(te->event_ctx->timer_events, te); 142 } 144 if (te->event_ctx->last_zero_timer == te) { 145 te->event_ctx->last_zero_timer = DLIST_PREV(te); 146 } 147 DLIST_REMOVE(te->event_ctx->timer_events, te); 143 148 144 149 return 0; … … 154 159 return NULL on failure (memory allocation error) 155 160 */ 156 struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev, TALLOC_CTX *mem_ctx, 157 struct timeval next_event, 158 tevent_timer_handler_t handler, 159 void *private_data, 160 const char *handler_name, 161 const char *location) 162 { 163 struct tevent_timer *te, *last_te, *cur_te; 161 static struct tevent_timer *tevent_common_add_timer_internal( 162 struct tevent_context *ev, 163 TALLOC_CTX *mem_ctx, 164 struct timeval next_event, 165 tevent_timer_handler_t handler, 166 void *private_data, 167 const char *handler_name, 168 const char *location, 169 bool optimize_zero) 170 { 171 struct tevent_timer *te, *prev_te, *cur_te; 164 172 165 173 te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer); … … 174 182 te->additional_data = NULL; 175 183 184 if (ev->timer_events == NULL) { 185 ev->last_zero_timer = NULL; 186 } 187 176 188 /* keep the list ordered */ 177 last_te = NULL; 178 for (cur_te = ev->timer_events; cur_te; cur_te = cur_te->next) { 179 /* if the new event comes before the current one break */ 180 if (tevent_timeval_compare(&te->next_event, &cur_te->next_event) < 0) { 189 prev_te = NULL; 190 if (optimize_zero && tevent_timeval_is_zero(&te->next_event)) { 191 /* 192 * Some callers use zero tevent_timer 193 * instead of tevent_immediate events. 194 * 195 * As these can happen very often, 196 * we remember the last zero timer 197 * in the list. 198 */ 199 prev_te = ev->last_zero_timer; 200 ev->last_zero_timer = te; 201 } else { 202 /* 203 * we traverse the list from the tail 204 * because it's much more likely that 205 * timers are added at the end of the list 206 */ 207 for (cur_te = DLIST_TAIL(ev->timer_events); 208 cur_te != NULL; 209 cur_te = DLIST_PREV(cur_te)) 210 { 211 int ret; 212 213 /* 214 * if the new event comes before the current 215 * we continue searching 216 */ 217 ret = tevent_timeval_compare(&te->next_event, 218 &cur_te->next_event); 219 if (ret < 0) { 220 continue; 221 } 222 181 223 break; 182 224 } 183 225 184 last_te = cur_te;185 } 186 187 DLIST_ADD_AFTER(ev->timer_events, te, last_te);226 prev_te = cur_te; 227 } 228 229 DLIST_ADD_AFTER(ev->timer_events, te, prev_te); 188 230 189 231 talloc_set_destructor(te, tevent_common_timed_destructor); … … 193 235 handler_name, te); 194 236 return te; 237 } 238 239 struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev, 240 TALLOC_CTX *mem_ctx, 241 struct timeval next_event, 242 tevent_timer_handler_t handler, 243 void *private_data, 244 const char *handler_name, 245 const char *location) 246 { 247 /* 248 * do not use optimization, there are broken Samba 249 * versions which use tevent_common_add_timer() 250 * without using tevent_common_loop_timer_delay(), 251 * it just uses DLIST_REMOVE(ev->timer_events, te) 252 * and would leave ev->last_zero_timer behind. 253 */ 254 return tevent_common_add_timer_internal(ev, mem_ctx, next_event, 255 handler, private_data, 256 handler_name, location, 257 false); 258 } 259 260 struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev, 261 TALLOC_CTX *mem_ctx, 262 struct timeval next_event, 263 tevent_timer_handler_t handler, 264 void *private_data, 265 const char *handler_name, 266 const char *location) 267 { 268 /* 269 * Here we turn on last_zero_timer optimization 270 */ 271 return tevent_common_add_timer_internal(ev, mem_ctx, next_event, 272 handler, private_data, 273 handler_name, location, 274 true); 195 275 } 196 276 … … 243 323 * handler because in a semi-async inner event loop called from the 244 324 * handler we don't want to come across this event again -- vl */ 325 if (ev->last_zero_timer == te) { 326 ev->last_zero_timer = DLIST_PREV(te); 327 } 245 328 DLIST_REMOVE(ev->timer_events, te); 329 330 tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE, 331 "Running timer event %p \"%s\"\n", 332 te, te->handler_name); 246 333 247 334 /* -
vendor/current/lib/tevent/tevent_util.c
r414 r988 89 89 #undef FLAG_TO_SET 90 90 } 91 92 bool ev_set_close_on_exec(int fd) 93 { 94 #ifdef FD_CLOEXEC 95 int val; 96 97 val = fcntl(fd, F_GETFD, 0); 98 if (val >= 0) { 99 val |= FD_CLOEXEC; 100 val = fcntl(fd, F_SETFD, val); 101 if (val != -1) { 102 return true; 103 } 104 } 105 #endif 106 return false; 107 } -
vendor/current/lib/tevent/tevent_util.h
r740 r988 54 54 list_head->prev, which means we can add to the end of the list in 55 55 O(1) time 56 57 58 Note that the 'type' arguments below are no longer needed, but59 are kept for now to prevent an incompatible argument change60 56 */ 61 57 … … 132 128 /* 133 129 add to the end of a list. 134 Note that 'type' is ignored135 130 */ 136 #define DLIST_ADD_END(list, p , type)\131 #define DLIST_ADD_END(list, p) \ 137 132 do { \ 138 133 if (!(list)) { \ … … 143 138 } while (0) 144 139 145 /* promote an element to the fro mof a list */140 /* promote an element to the front of a list */ 146 141 #define DLIST_PROMOTE(list, p) \ 147 142 do { \ … … 152 147 /* 153 148 demote an element to the end of a list. 154 Note that 'type' is ignored155 149 */ 156 #define DLIST_DEMOTE(list, p , type)\150 #define DLIST_DEMOTE(list, p) \ 157 151 do { \ 158 152 DLIST_REMOVE(list, p); \ 159 DLIST_ADD_END(list, p , NULL);\153 DLIST_ADD_END(list, p); \ 160 154 } while (0) 161 155 … … 163 157 concatenate two lists - putting all elements of the 2nd list at the 164 158 end of the first list. 165 Note that 'type' is ignored166 159 */ 167 #define DLIST_CONCATENATE(list1, list2 , type)\160 #define DLIST_CONCATENATE(list1, list2) \ 168 161 do { \ 169 162 if (!(list1)) { \ … … 184 177 int ev_set_blocking(int fd, bool set); 185 178 size_t ev_str_list_length(const char **list); 179 bool ev_set_close_on_exec(int fd); 186 180 187 181 /* Defined here so we can build against older talloc versions that don't -
vendor/current/lib/tevent/tevent_wakeup.c
r414 r988 47 47 48 48 if (!tevent_req_set_endtime(req, ev, wakeup_time)) { 49 goto post;49 return tevent_req_post(req, ev); 50 50 } 51 52 51 return req; 53 post:54 return tevent_req_post(req, ev);55 52 } 56 53 -
vendor/current/lib/tevent/wscript
r740 r988 2 2 3 3 APPNAME = 'tevent' 4 VERSION = '0.9. 11'4 VERSION = '0.9.28' 5 5 6 6 blddir = 'bin' … … 11 11 srcdir = '.' 12 12 while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5: 13 srcdir = '../' + srcdir13 srcdir = srcdir + '/..' 14 14 sys.path.insert(0, srcdir + '/buildtools/wafsamba') 15 15 16 import wafsamba, samba_dist, Options, Logs16 import wafsamba, samba_dist, samba_utils, Options, Logs 17 17 18 samba_dist.DIST_DIRS('lib/tevent:. lib/replace:lib/replace lib/talloc:lib/talloc buildtools:buildtools ')18 samba_dist.DIST_DIRS('lib/tevent:. lib/replace:lib/replace lib/talloc:lib/talloc buildtools:buildtools third_party/waf:third_party/waf') 19 19 20 20 def set_options(opt): … … 36 36 37 37 if not conf.env.standalone_tevent: 38 if conf.CHECK_BUNDLED_SYSTEM ('tevent', minversion=VERSION,38 if conf.CHECK_BUNDLED_SYSTEM_PKG('tevent', minversion=VERSION, 39 39 onlyif='talloc', implied_deps='replace talloc'): 40 40 conf.define('USING_SYSTEM_TEVENT', 1) 41 if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytevent', 'tevent', minversion=VERSION): 42 conf.define('USING_SYSTEM_PYTEVENT', 1) 41 43 42 44 if conf.CHECK_FUNCS('epoll_create', headers='sys/epoll.h'): 43 45 conf.DEFINE('HAVE_EPOLL', 1) 46 47 tevent_num_signals = 64 48 v = conf.CHECK_VALUEOF('NSIG', headers='signal.h') 49 if v is not None: 50 tevent_num_signals = max(tevent_num_signals, v) 51 v = conf.CHECK_VALUEOF('_NSIG', headers='signal.h') 52 if v is not None: 53 tevent_num_signals = max(tevent_num_signals, v) 54 v = conf.CHECK_VALUEOF('SIGRTMAX', headers='signal.h') 55 if v is not None: 56 tevent_num_signals = max(tevent_num_signals, v) 57 v = conf.CHECK_VALUEOF('SIGRTMIN', headers='signal.h') 58 if v is not None: 59 tevent_num_signals = max(tevent_num_signals, v*2) 60 61 if not conf.CONFIG_SET('USING_SYSTEM_TEVENT'): 62 conf.DEFINE('TEVENT_NUM_SIGNALS', tevent_num_signals) 44 63 45 64 conf.env.disable_python = getattr(Options.options, 'disable_python', False) … … 47 66 if not conf.env.disable_python: 48 67 # also disable if we don't have the python libs installed 68 conf.find_program('python', var='PYTHON') 49 69 conf.check_tool('python') 50 70 conf.check_python_version((2,4,2)) … … 56 76 conf.SAMBA_CONFIG_H() 57 77 78 conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS() 79 58 80 def build(bld): 59 81 bld.RECURSE('lib/replace') … … 62 84 SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c 63 85 tevent_queue.c tevent_req.c tevent_select.c 64 tevent_poll.c86 tevent_poll.c tevent_threads.c 65 87 tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c''' 66 88 … … 68 90 SRC += ' tevent_epoll.c' 69 91 92 if bld.CONFIG_SET('HAVE_SOLARIS_PORTS'): 93 SRC += ' tevent_port.c' 94 70 95 if bld.env.standalone_tevent: 71 96 bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig' 72 bld.PKG_CONFIG_FILES('tevent.pc', vnum=VERSION)73 97 private_library = False 74 98 else: … … 84 108 abi_match='tevent_* _tevent_*', 85 109 vnum=VERSION, 86 public_headers= 'tevent.h',110 public_headers=('' if private_library else 'tevent.h'), 87 111 public_headers_install=not private_library, 112 pc_files='tevent.pc', 88 113 private_library=private_library) 89 114 90 bld.SAMBA_PYTHON('pytevent', 91 'pytevent.c', 92 deps='tevent', 93 enabled=True, 94 realname='_tevent.so') 115 if not bld.CONFIG_SET('USING_SYSTEM_PYTEVENT') and not bld.env.disable_python: 116 for env in bld.gen_python_environments(['PKGCONFIGDIR']): 117 bld.SAMBA_PYTHON('_tevent', 118 'pytevent.c', 119 deps='tevent', 120 realname='_tevent.so', 121 cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION) 122 123 124 bld.INSTALL_WILDCARD('${PYTHONARCHDIR}', 'tevent.py', flat=False) 125 126 # install out various python scripts for use by make test 127 bld.SAMBA_SCRIPT('tevent_python', 128 pattern='tevent.py', 129 installdir='python') 95 130 96 131 … … 98 133 '''test tevent''' 99 134 print("The tevent testsuite is part of smbtorture in samba4") 135 136 samba_utils.ADD_LD_LIBRARY_PATH('bin/shared') 137 samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private') 138 139 pyret = samba_utils.RUN_PYTHON_TESTS(['bindings.py']) 140 sys.exit(pyret) 100 141 101 142
Note:
See TracChangeset
for help on using the changeset viewer.