Ignore:
Timestamp:
Nov 24, 2016, 1:14:11 PM (9 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to version 4.4.3

Location:
vendor/current/lib/tevent
Files:
31 added
2 deleted
24 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/lib/tevent/bindings.py

    r740 r988  
    2323
    2424import signal
     25from unittest import TestCase, TestProgram
     26import gc
     27
    2528import _tevent
    26 from unittest import TestCase
    2729
    2830class BackendListTests(TestCase):
     
    6163        sig = self.ctx.add_signal(signal.SIGINT, 0, lambda callback: None)
    6264        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
     111if __name__ == '__main__':
     112    TestProgram()
  • vendor/current/lib/tevent/doc/mainpage.dox

    r740 r988  
    1111 * tevent_req (tevent request) functions.
    1212 *
    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
    1419 *
    1520 * You can download the latest releases of tevent from the
     
    1722 * on the samba public source archive.
    1823 *
    19  * @section tevent_bugs Discussion and bug reports
     24 * @section main_tevent_bugs Discussion and bug reports
    2025 *
    2126 * tevent does not currently have its own mailing list or bug tracking system.
     
    2631 * bug tracking system.
    2732 *
    28  * @section tevent_devel Development
     33 * @section main_tevent_devel Development
    2934 * You can download the latest code either via git or rsync.
    3035 *
  • vendor/current/lib/tevent/doxy.config

    r740 r988  
    1 # Doxyfile 1.6.1
     1# Doxyfile 1.8.4
    22
    33# 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.
    55#
    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.
    79# The format is:
    810#       TAG = value [value, ...]
    911# For lists items can also be appended using:
    1012#       TAG += value [value, ...]
    11 # Values that contain spaces should be placed between quotes (" ")
     13# Values that contain spaces should be placed between quotes (" ").
    1214
    1315#---------------------------------------------------------------------------
     
    2325DOXYFILE_ENCODING      = UTF-8
    2426
    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.
    2730
    2831PROJECT_NAME           = tevent
     
    3336
    3437PROJECT_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
     43PROJECT_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
     50PROJECT_LOGO           =
    3551
    3652# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
     
    5773# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
    5874# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
    59 # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
    60 # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
    61 # Slovene, 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.
    6278
    6379OUTPUT_LANGUAGE        = English
     
    123139# the path. The tag can be used to show relative paths in the file list.
    124140# 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.
    126144
    127145STRIP_FROM_PATH        =
     
    137155
    138156# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
    139 # (but less readable) file names. This can be useful is your file systems
     157# (but less readable) file names. This can be useful if your file system
    140158# doesn't support long names like on DOS, Mac, or CD-ROM.
    141159
     
    192210ALIASES                =
    193211
     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
     217TCL_SUBST              =
     218
    194219# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
    195220# sources only. Doxygen will then generate output that is more tailored for C.
     
    218243OPTIMIZE_OUTPUT_VHDL   = NO
    219244
    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.
    228255
    229256EXTENSION_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
     265MARKDOWN_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
     272AUTOLINK_SUPPORT       = YES
    230273
    231274# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
     
    233276# set this tag to YES in order to let doxygen match functions declarations and
    234277# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
    235 # func(std::string) {}). This also make the inheritance and collaboration
     278# func(std::string) {}). This also makes the inheritance and collaboration
    236279# diagrams that involve STL classes more complete and accurate.
    237280
     
    249292SIP_SUPPORT            = NO
    250293
    251 # For Microsoft's IDL there are propget and propput attributes to indicate getter
    252 # 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 the
    254 # documentation. This will only work if the methods are indeed getting or
     294# 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
    255298# setting a simple type. If this is not the case, or you want to show the
    256299# methods anyway, you should set this option to NO.
     
    272315
    273316SUBGROUPING            = 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
     323INLINE_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
     332INLINE_SIMPLE_STRUCTS  = NO
    274333
    275334# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
     
    283342TYPEDEF_HIDES_STRUCT   = NO
    284343
    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
     353LOOKUP_CACHE_SIZE      = 0
    300354
    301355#---------------------------------------------------------------------------
     
    306360# documentation are documented, even if no documentation was available.
    307361# Private class members and static file members will be hidden unless
    308 # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
     362# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES
    309363
    310364EXTRACT_ALL            = NO
     
    314368
    315369EXTRACT_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
     374EXTRACT_PACKAGE        = NO
    316375
    317376# If the EXTRACT_STATIC tag is set to YES all static members of a file
     
    337396# 'anonymous_namespace{file}', where file will be replaced with the base
    338397# name of the file that contains the anonymous namespace. By default
    339 # anonymous namespace are hidden.
     398# anonymous namespaces are hidden.
    340399
    341400EXTRACT_ANON_NSPACES   = NO
     
    397456SHOW_INCLUDE_FILES     = YES
    398457
     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
     462FORCE_LOCAL_INCLUDES   = NO
     463
    399464# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
    400465# is inserted in the documentation for inline members.
     
    416481SORT_BRIEF_DOCS        = NO
    417482
    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.
    419490
    420491SORT_MEMBERS_CTORS_1ST = NO
     
    436507SORT_BY_SCOPE_NAME     = NO
    437508
     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
     516STRICT_PROTO_MATCHING  = NO
     517
    438518# The GENERATE_TODOLIST tag can be used to enable (YES) or
    439519# disable (NO) the todo list. This list is created by putting \todo
     
    461541
    462542# 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.
    464545
    465546ENABLED_SECTIONS       =
    466547
    467548# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
    468 # the initial value of a variable or define consists of for it to appear in
     549# the initial value of a variable or macro consists of for it to appear in
    469550# the documentation. If the initializer consists of more lines than specified
    470551# 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 the
     552# The appearance of the initializer of individual variables and macros in the
    472553# documentation can be controlled using \showinitializer or \hideinitializer
    473554# command in the documentation regardless of this setting.
     
    480561
    481562SHOW_USED_FILES        = YES
    482 
    483 # If the sources in your project are distributed over multiple directories
    484 # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
    485 # in the documentation. The default is NO.
    486 
    487 SHOW_DIRECTORIES       = NO
    488563
    489564# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
     
    510585FILE_VERSION_FILTER    =
    511586
    512 # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
    513 # doxygen. The layout file controls the global structure of the generated output files
    514 # in an output format independent way. The create the layout file that represents
    515 # doxygen's defaults, run doxygen with the -l option. You can optionally specify a
    516 # file name after the option, if omitted DoxygenLayout.xml will be used as the name
    517 # 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.
    518593
    519594LAYOUT_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
     605CITE_BIB_FILES         =
    520606
    521607#---------------------------------------------------------------------------
     
    547633WARN_IF_DOC_ERROR      = YES
    548634
    549 # This WARN_NO_PARAMDOC option can be abled to get warnings for
     635# The WARN_NO_PARAMDOC option can be enabled to get warnings for
    550636# functions that are documented, but have no documentation for their parameters
    551637# or return value. If set to NO (the default) doxygen will only warn about
     
    579665# with spaces.
    580666
    581 INPUT                  = . doc
     667INPUT                  = . \
     668                         doc
    582669
    583670# This tag can be used to specify the character encoding of the source files
     
    593680# and *.h) to filter out the source-files in the directories. If left
    594681# 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
    597685
    598686FILE_PATTERNS          = *.cpp \
     
    610698RECURSIVE              = NO
    611699
    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
    613701# excluded from the INPUT source files. This way you can easily exclude a
    614702# 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.
    615705
    616706EXCLUDE                =
    617707
    618 # The EXCLUDE_SYMLINKS tag can be used select whether or not files or
    619 # directories that are symbolic links (a Unix filesystem feature) are excluded
     708# 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
    620710# from the input.
    621711
     
    628718# for example use the pattern */test/*
    629719
    630 EXCLUDE_PATTERNS       = */.git/* \
    631                          */.svn/* \
    632                          */cmake/* \
    633                          */build/*
     720EXCLUDE_PATTERNS       = */.git/*
    634721
    635722# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
     
    665752# the \image command).
    666753
    667 IMAGE_PATH             =
     754IMAGE_PATH             = doc/img
    668755
    669756# The INPUT_FILTER tag can be used to specify a program that doxygen should
     
    673760# input file. Doxygen will then use the output that the filter program writes
    674761# 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.
    677766
    678767INPUT_FILTER           =
     
    684773# The filters are a list of the form:
    685774# 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_FILTER
    687 # 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.
    688777
    689778FILTER_PATTERNS        =
     
    694783
    695784FILTER_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
     792FILTER_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
     799USE_MDFILE_AS_MAINPAGE =
    696800
    697801#---------------------------------------------------------------------------
     
    713817# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
    714818# 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.
    716820
    717821STRIP_CODE_COMMENTS    = YES
     
    783887GENERATE_HTML          = YES
    784888
    785 # If the HTML_FOOTER_DESCRIPTION tag is set to YES, Doxygen will
    786 # add generated date, project name and doxygen version to HTML footer.
    787 
    788 HTML_FOOTER_DESCRIPTION= NO
    789 
    790889# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
    791890# If a relative path is entered the value of OUTPUT_DIRECTORY will be
     
    802901# The HTML_HEADER tag can be used to specify a personal HTML header for
    803902# 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!
    805911
    806912HTML_HEADER            =
     
    814920# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
    815921# 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 doxygen
    817 # will generate a default style sheet. Note that doxygen will try to copy
    818 # the style sheet file to the HTML output directory, so don't put your own
    819 # 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.
    820926
    821927HTML_STYLESHEET        =
    822928
    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
     937HTML_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
     946HTML_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
     956HTML_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
     962HTML_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
     971HTML_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
     977HTML_TIMESTAMP         = NO
    828978
    829979# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
    830980# 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.
    834982
    835983HTML_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
     994HTML_INDEX_NUM_ENTRIES = 100
    836995
    837996# If the GENERATE_DOCSET tag is set to YES, additional index files
     
    8431002# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
    8441003# 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.
    8461006
    8471007GENERATE_DOCSET        = NO
     
    8611021DOCSET_BUNDLE_ID       = org.doxygen.Project
    8621022
     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
     1027DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
     1028
     1029# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
     1030
     1031DOCSET_PUBLISHER_NAME  = Publisher
     1032
    8631033# If the GENERATE_HTMLHELP tag is set to YES, additional index files
    8641034# will be generated that can be used as input for tools like the
     
    9051075TOC_EXPAND             = NO
    9061076
    907 # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
    908 # are set, an additional index file will be generated that can be used as input for
    909 # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
    910 # 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.
    9111081
    9121082GENERATE_QHP           = NO
     
    9301100QHP_VIRTUAL_FOLDER     = doc
    9311101
    932 # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
    933 # For more information please see
     1102# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
     1103# add. For more information please see
    9341104# http://doc.trolltech.com/qthelpproject.html#custom-filters
    9351105
    9361106QHP_CUST_FILTER_NAME   =
    9371107
    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>.
    9401112
    9411113QHP_CUST_FILTER_ATTRS  =
    9421114
    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
    9441117# 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>.
    9461120
    9471121QHP_SECT_FILTER_ATTRS  =
     
    9541128QHG_LOCATION           =
    9551129
    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
     1139GENERATE_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
     1145ECLIPSE_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.
    9591152
    9601153DISABLE_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   = 4
    9661154
    9671155# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
     
    9721160# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
    9731161# 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.
    9741164
    9751165GENERATE_TREEVIEW      = NONE
    9761166
    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
     1172ENUM_VALUES_PER_LINE   = 4
    9811173
    9821174# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
     
    9851177
    9861178TREEVIEW_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
     1183EXT_LINKS_IN_WINDOW    = NO
    9871184
    9881185# Use this tag to change the font size of Latex formulas included
     
    9941191FORMULA_FONTSIZE       = 10
    9951192
    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
     1199FORMULA_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
     1208USE_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
     1215MATHJAX_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
     1227MATHJAX_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
     1232MATHJAX_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
     1237MATHJAX_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.
    10001246
    10011247SEARCHENGINE           = 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
     1257SERVER_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
     1267EXTERNAL_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
     1275SEARCHENGINE_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
     1281SEARCHDATA_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
     1288EXTERNAL_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
     1297EXTRA_SEARCH_MAPPINGS  =
    10021298
    10031299#---------------------------------------------------------------------------
     
    10181314# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
    10191315# 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.
    10201319
    10211320LATEX_CMD_NAME         = latex
     
    10341333
    10351334# 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 and
    1037 # executive. If left blank a4wide will be used.
     1335# by the printer. Possible values are: a4, letter, legal and
     1336# executive. If left blank a4 will be used.
    10381337
    10391338PAPER_TYPE             = a4wide
     
    10511350LATEX_HEADER           =
    10521351
     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
     1357LATEX_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
     1364LATEX_EXTRA_FILES      =
     1365
    10531366# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
    10541367# is prepared for conversion to pdf (using ps2pdf). The pdf file will
     
    10771390LATEX_HIDE_INDICES     = NO
    10781391
    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.
    10801396
    10811397LATEX_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
     1403LATEX_BIB_STYLE        = plain
    10821404
    10831405#---------------------------------------------------------------------------
     
    11121434RTF_HYPERLINKS         = NO
    11131435
    1114 # Load stylesheet definitions from file. Syntax is similar to doxygen's
     1436# Load style sheet definitions from file. Syntax is similar to doxygen's
    11151437# config file, i.e. a series of assignments. You only have to provide
    11161438# replacements, missing definitions are set to their default value.
     
    11851507
    11861508XML_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
     1517GENERATE_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
     1523DOCBOOK_OUTPUT         = docbook
    11871524
    11881525#---------------------------------------------------------------------------
     
    12571594
    12581595# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
    1259 # in the INCLUDE_PATH (see below) will be search if a #include is found.
     1596# pointed to by INCLUDE_PATH will be searched when a #include is found.
    12601597
    12611598SEARCH_INCLUDES        = YES
     
    12821619# instead of the = operator.
    12831620
    1284 PREDEFINED             = DOXYGEN PRINTF_ATTRIBUTE(x,y)=
     1621PREDEFINED             = DOXYGEN \
     1622                         PRINTF_ATTRIBUTE(x,y)=
    12851623
    12861624# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
    12871625# this tag can be used to specify a list of macro names that should be expanded.
    12881626# 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.
    12901629
    12911630EXPAND_AS_DEFINED      =
    12921631
    12931632# 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.
    12981636
    12991637SKIP_FUNCTION_MACROS   = YES
     
    13031641#---------------------------------------------------------------------------
    13041642
    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:
    13091646#
    13101647# TAGFILES = file1 file2 ...
     
    13121649#
    13131650# 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.
    13211655
    13221656TAGFILES               =
     
    13391673EXTERNAL_GROUPS        = YES
    13401674
     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
     1679EXTERNAL_PAGES         = YES
     1680
    13411681# The PERL_PATH should be the absolute path and name of the perl script
    13421682# interpreter (i.e. the result of `which perl').
     
    13511691# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
    13521692# 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.
    13561695
    13571696CLASS_DIAGRAMS         = YES
     
    13791718HAVE_DOT               = NO
    13801719
    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
     1726DOT_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.
    13891734
    13901735DOT_FONTNAME           = FreeSans
     
    13951740DOT_FONTSIZE           = 10
    13961741
    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.
    14011745
    14021746DOT_FONTPATH           =
     
    14051749# will generate a graph for each documented class showing the direct and
    14061750# indirect inheritance relations. Setting this tag to YES will force the
    1407 # the CLASS_DIAGRAMS tag to NO.
     1751# CLASS_DIAGRAMS tag to NO.
    14081752
    14091753CLASS_GRAPH            = YES
     
    14261770
    14271771UML_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
     1780UML_LIMIT_NUM_FIELDS   = 10
    14281781
    14291782# If set to YES, the inheritance and collaboration graphs will show the
     
    14631816
    14641817# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
    1465 # will graphical hierarchy of all classes instead of a textual one.
     1818# will generate a graphical hierarchy of all classes instead of a textual one.
    14661819
    14671820GRAPHICAL_HIERARCHY    = YES
    14681821
    1469 # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
     1822# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
    14701823# then doxygen will show the dependencies a directory has on other directories
    14711824# in a graphical way. The dependency relations are determined by the #include
     
    14751828
    14761829# 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).
    14791834
    14801835DOT_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
     1844INTERACTIVE_SVG        = NO
    14811845
    14821846# The tag DOT_PATH can be used to specify the path where the dot tool can be
     
    14901854
    14911855DOTFILE_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
     1861MSCFILE_DIRS           =
    14921862
    14931863# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
  • vendor/current/lib/tevent/pytevent.c

    r740 r988  
    2424
    2525#include <Python.h>
     26#include "replace.h"
    2627#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
     40void init_tevent(void);
    2741
    2842typedef struct {
     
    4963        PyObject_HEAD
    5064        struct tevent_timer *timer;
     65        PyObject *callback;
    5166} TeventTimer_Object;
    5267
     
    5671} TeventFd_Object;
    5772
    58 staticforward PyTypeObject TeventContext_Type;
    59 staticforward PyTypeObject TeventReq_Type;
    60 staticforward PyTypeObject TeventQueue_Type;
    61 staticforward PyTypeObject TeventSignal_Type;
    62 staticforward PyTypeObject TeventTimer_Type;
    63 staticforward PyTypeObject TeventFd_Type;
     73static PyTypeObject TeventContext_Type;
     74static PyTypeObject TeventReq_Type;
     75static PyTypeObject TeventQueue_Type;
     76static PyTypeObject TeventSignal_Type;
     77static PyTypeObject TeventTimer_Type;
     78static PyTypeObject TeventFd_Type;
    6479
    6580static int py_context_init(struct tevent_context *ev)
     
    87102}
    88103
    89 uint16_t py_get_fd_flags(struct tevent_fd *fde)
     104static uint16_t py_get_fd_flags(struct tevent_fd *fde)
    90105{
    91106        /* FIXME */
     
    174189        }
    175190
    176         if (!PyString_Check(name)) {
     191        if (!PyStr_Check(name)) {
    177192                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 */
    182198                PyErr_SetNone(PyExc_RuntimeError);
    183                 return NULL;
    184         }
     199                Py_DECREF(name);
     200                return NULL;
     201        }
     202
     203        Py_DECREF(name);
    185204
    186205        Py_RETURN_NONE;
     
    213232        PyObject *callback = private_data, *ret;
    214233
    215         ret = PyObject_CallFunction(callback, "");
     234        ret = PyObject_CallFunction(callback, discard_const_p(char, ""));
    216235        Py_XDECREF(ret);
    217236}
     
    278297}
    279298
    280 #ifdef TEVENT_DEPRECATED
    281 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 #endif
    311 
    312299static void py_tevent_signal_handler(struct tevent_context *ev,
    313300                                        struct tevent_signal *se,
     
    319306        PyObject *callback = (PyObject *)private_data, *ret;
    320307
    321         ret = PyObject_CallFunction(callback, "ii", signum, count);
     308        ret = PyObject_CallFunction(callback, discard_const_p(char, "ii"), signum, count);
    322309        Py_XDECREF(ret);
    323310}
     
    330317
    331318static PyTypeObject TeventSignal_Type = {
    332         .tp_name = "Signal",
     319        .tp_name = "tevent.Signal",
    333320        .tp_basicsize = sizeof(TeventSignal_Object),
    334321        .tp_dealloc = (destructor)py_tevent_signal_dealloc,
     
    367354                                       void *private_data)
    368355{
    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        }
    371364        Py_XDECREF(ret);
    372365}
    373366
    374 static PyObject *py_tevent_context_add_timer(TeventContext_Object *self, PyObject *args)
    375 {
     367static 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
     376static int py_tevent_timer_traverse(TeventTimer_Object *self, visitproc visit, void *arg)
     377{
     378        Py_VISIT(self->callback);
     379        return 0;
     380}
     381
     382static PyObject* py_tevent_timer_get_active(TeventTimer_Object *self) {
     383        return PyBool_FromLong(self->timer != NULL);
     384}
     385
     386struct 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
     395static 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
     404struct TeventTimer_Object_ref {
     405        TeventTimer_Object *obj;
     406};
     407
     408static 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
     415static 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         */
    376445        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;
    389447
    390448        ret = PyObject_New(TeventTimer_Object, &TeventTimer_Type);
    391449        if (ret == NULL) {
    392450                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);
    397473
    398474        return (PyObject *)ret;
     475}
     476
     477static 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
     487static 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);
    399500}
    400501
     
    406507        PyObject *callback = private_data, *ret;
    407508
    408         ret = PyObject_CallFunction(callback, "i", flags);
     509        ret = PyObject_CallFunction(callback, discard_const_p(char, "i"), flags);
    409510        Py_XDECREF(ret);
    410511}
     512
     513static void py_tevent_fp_dealloc(TeventFd_Object *self)
     514{
     515        talloc_free(self->fd);
     516        PyObject_Del(self);
     517}
     518
     519static 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};
    411525
    412526static PyObject *py_tevent_context_add_fd(TeventContext_Object *self, PyObject *args)
     
    435549        return (PyObject *)ret;
    436550}
    437 
    438 #ifdef TEVENT_DEPRECATED
    439 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 #endif
    445551
    446552static PyMethodDef py_tevent_context_methods[] = {
     
    453559        { "loop_once", (PyCFunction)py_tevent_context_loop_once,
    454560                METH_NOARGS, "S.loop_once()" },
    455 #ifdef TEVENT_DEPRECATED
    456         { "loop_until", (PyCFunction)py_tevent_context_loop_until,
    457                 METH_VARARGS, "S.loop_until(callback)" },
    458 #endif
    459561        { "add_signal", (PyCFunction)py_tevent_context_add_signal,
    460562                METH_VARARGS, "S.add_signal(signum, sa_flags, handler) -> signal" },
    461563        { "add_timer", (PyCFunction)py_tevent_context_add_timer,
    462564                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" },
    463567        { "add_fd", (PyCFunction)py_tevent_context_add_fd,
    464568                METH_VARARGS, "S.add_fd(fd, flags, handler) -> fd" },
    465 #ifdef TEVENT_DEPRECATED
    466         { "allow_nesting", (PyCFunction)py_tevent_context_set_allow_nesting,
    467                 METH_NOARGS, "Whether to allow nested tevent loops." },
    468 #endif
    469569        { NULL },
    470570};
     
    501601
    502602static 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        },
    505608        { NULL }
    506609};
     
    590693
    591694static 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        },
    594700        { NULL },
    595701};
     
    617723
    618724static 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        },
    621730        { NULL }
    622731};
     
    635744        TeventContext_Object *ret;
    636745
    637         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwnames, &name))
     746        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", discard_const_p(char *, kwnames), &name))
    638747                return NULL;
    639748
     
    661770
    662771static PyTypeObject TeventContext_Type = {
    663         .tp_name = "_tevent.Context",
     772        .tp_name = "tevent.Context",
    664773        .tp_new = py_tevent_context_new,
    665774        .tp_basicsize = sizeof(TeventContext_Object),
     
    683792static PyObject *py_backend_list(PyObject *self)
    684793{
    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;
    688798
    689799        ret = PyList_New(0);
     
    695805        if (backends == NULL) {
    696806                PyErr_SetNone(PyExc_RuntimeError);
    697                 Py_DECREF(ret);
    698                 return NULL;
     807                goto err;
    699808        }
    700809        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;
    702820        }
    703821
     
    705823
    706824        return ret;
     825
     826err:
     827        Py_XDECREF(ret);
     828        Py_XDECREF(string);
     829        talloc_free(backends);
     830        return NULL;
    707831}
    708832
     
    717841};
    718842
    719 void init_tevent(void)
     843#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
     844
     845#if PY_MAJOR_VERSION >= 3
     846static 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
     855PyObject * module_init(void);
     856PyObject * module_init(void)
    720857{
    721858        PyObject *m;
    722859
    723860        if (PyType_Ready(&TeventContext_Type) < 0)
    724                 return;
     861                return NULL;
    725862
    726863        if (PyType_Ready(&TeventQueue_Type) < 0)
    727                 return;
     864                return NULL;
    728865
    729866        if (PyType_Ready(&TeventReq_Type) < 0)
    730                 return;
     867                return NULL;
    731868
    732869        if (PyType_Ready(&TeventSignal_Type) < 0)
    733                 return;
     870                return NULL;
    734871
    735872        if (PyType_Ready(&TeventTimer_Type) < 0)
    736                 return;
     873                return NULL;
    737874
    738875        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
    742883        if (m == NULL)
    743                 return;
     884                return NULL;
    744885
    745886        Py_INCREF(&TeventContext_Type);
     
    760901        Py_INCREF(&TeventFd_Type);
    761902        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
     910PyMODINIT_FUNC PyInit__tevent(void);
     911PyMODINIT_FUNC PyInit__tevent(void)
     912{
     913        return module_init();
     914}
     915#else
     916void init_tevent(void);
     917void init_tevent(void)
     918{
     919        module_init();
     920}
     921#endif
  • vendor/current/lib/tevent/testsuite.c

    r740 r988  
    55
    66   Copyright (C) Stefan Metzmacher 2006-2009
     7   Copyright (C) Jeremy Allison    2013
    78
    89     ** NOTE! The following LGPL license applies to the tevent
     
    2526
    2627#include "includes.h"
    27 #include "lib/events/events.h"
     28#include "lib/tevent/tevent.h"
    2829#include "system/filesys.h"
     30#include "system/select.h"
     31#include "system/network.h"
    2932#include "torture/torture.h"
     33#include "torture/local/proto.h"
     34#ifdef HAVE_PTHREAD
     35#include <pthread.h>
     36#include <assert.h>
     37#endif
    3038
    3139static int fde_count;
    3240
    33 static void fde_handler(struct tevent_context *ev_ctx, struct tevent_fd *f,
     41static void fde_handler_read(struct tevent_context *ev_ctx, struct tevent_fd *f,
    3442                        uint16_t flags, void *private_data)
    3543{
     
    4048#endif
    4149        kill(getpid(), SIGALRM);
     50
    4251        read(fd[0], &c, 1);
     52        fde_count++;
     53}
     54
     55static 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;
    4360        write(fd[1], &c, 1);
     61}
     62
     63
     64/* This will only fire if the fd's returned from pipe() are bi-directional. */
     65static 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);
    4476        fde_count++;
     77}
     78
     79/* This will only fire if the fd's returned from pipe() are bi-directional. */
     80static 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);
    4586}
    4687
     
    5293}
    5394
    54 static void count_handler(struct tevent_context *ev_ctx, struct signal_event *te,
     95static void count_handler(struct tevent_context *ev_ctx, struct tevent_signal *te,
    5596                          int signum, int count, void *info, void *private_data)
    5697{
     
    66107        const char *backend = (const char *)test_data;
    67108        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;
    69113#ifdef SA_RESTART
    70114        struct tevent_signal *se1 = NULL;
    71115#endif
     116#ifdef SA_RESETHAND
    72117        struct tevent_signal *se2 = NULL;
     118#endif
    73119#ifdef SA_SIGINFO
    74120        struct tevent_signal *se3 = NULL;
     
    76122        int finished=0;
    77123        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);
    81127        if (ev_ctx == NULL) {
    82128                torture_comment(test, "event backend '%s' not supported\n", backend);
     
    84130        }
    85131
    86         torture_comment(test, "Testing event backend '%s'\n", backend);
     132        torture_comment(test, "backend '%s' - %s\n",
     133                        backend, __FUNCTION__);
    87134
    88135        /* reset globals */
     
    90137
    91138        /* 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);
    100157
    101158#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");
    103161#endif
    104162#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");
    106165#endif
    107166#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
    112170
    113171        t = timeval_current();
    114172        while (!finished) {
    115173                errno = 0;
    116                 if (event_loop_once(ev_ctx) == -1) {
     174                if (tevent_loop_once(ev_ctx) == -1) {
    117175                        talloc_free(ev_ctx);
    118176                        torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno)));
     
    120178        }
    121179
    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);
    124184
    125185        while (alarm_count < fde_count+1) {
    126                 if (event_loop_once(ev_ctx) == -1) {
     186                if (tevent_loop_once(ev_ctx) == -1) {
    127187                        break;
    128188                }
     
    136196
    137197        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
    138206
    139207#ifdef SA_SIGINFO
     
    147215}
    148216
     217struct 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
     234static 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
     307static 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
     355static 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
     433struct 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
     450static 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
     576static 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
     591static 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
     678static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
     679static bool do_shutdown = false;
     680
     681static void test_event_threaded_lock(void)
     682{
     683        int ret;
     684        ret = pthread_mutex_lock(&threaded_mutex);
     685        assert(ret == 0);
     686}
     687
     688static void test_event_threaded_unlock(void)
     689{
     690        int ret;
     691        ret = pthread_mutex_unlock(&threaded_mutex);
     692        assert(ret == 0);
     693}
     694
     695static 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
     711static 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
     719static 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
     737static 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
     757static 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... */
     814static struct torture_context *thread_test_ctx;
     815static pthread_t thread_map[NUM_TEVENT_THREADS];
     816static unsigned thread_counter;
     817
     818/* Called in master thread context */
     819static 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. */
     841static 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
     865static 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
     872static 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
     933struct reply_state {
     934        struct tevent_thread_proxy *reply_tp;
     935        pthread_t thread_id;
     936        int *p_finished;
     937};
     938
     939static 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 */
     949static 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 */
     961static 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
     990static 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
     1072static 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
    1491134struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
    1501135{
    1511136        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);
    1531138        int i;
    1541139
    1551140        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",
    1571147                                               test_event_context,
    1581148                                               (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
    1601175
    1611176        return suite;
  • vendor/current/lib/tevent/tevent.c

    r740 r988  
    113113static void tevent_backend_init(void)
    114114{
     115        static bool done;
     116
     117        if (done) {
     118                return;
     119        }
     120
     121        done = true;
     122
    115123        tevent_select_init();
    116124        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
    117132        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;
    121155}
    122156
     
    160194        }
    161195
     196        ev->last_zero_timer = NULL;
    162197        for (te = ev->timer_events; te; te = tn) {
    163198                tn = te->next;
     
    186221        }
    187222
     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
    188234        return 0;
    189235}
     
    200246  NOTE: use tevent_context_init() inside of samba!
    201247*/
    202 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
    203                                                       const struct tevent_ops *ops)
     248struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
     249                                               const struct tevent_ops *ops,
     250                                               void *additional_data)
    204251{
    205252        struct tevent_context *ev;
     
    212259
    213260        ev->ops = ops;
     261        ev->additional_data = additional_data;
    214262
    215263        ret = ev->ops->context_init(ev);
     
    230278                                                  const char *name)
    231279{
    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);
    249288}
    250289
     
    392431/*
    393432  schedule an immediate event
    394   return NULL on failure
    395433*/
    396434void _tevent_schedule_immediate(struct tevent_immediate *im,
     
    492530        }
    493531
     532        tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
    494533        ret = ev->ops->loop_once(ev, location);
     534        tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
    495535
    496536        if (ev->nesting.level > 0) {
     
    552592
    553593        while (!finished(private_data)) {
     594                tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
    554595                ret = ev->ops->loop_once(ev, location);
     596                tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
    555597                if (ret != 0) {
    556598                        break;
  • vendor/current/lib/tevent/tevent.h

    r740 r988  
    4040struct tevent_immediate;
    4141struct tevent_signal;
     42struct tevent_thread_proxy;
    4243
    4344/**
     
    112113
    113114/**
    114  * @brief Create a event_context structure and name it.
     115 * @brief Create a event_context structure and select a specific backend.
    115116 *
    116117 * This must be the first events call, and all subsequent calls pass this
     
    120121 * @param[in]  mem_ctx  The memory context to use.
    121122 *
    122  * @param[in]  name     The name for the tevent context.
     123 * @param[in]  name     The name of the backend to use.
    123124 *
    124125 * @return              An allocated tevent context, NULL on error.
    125126 */
    126127struct 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 */
     139struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
     140                                               const struct tevent_ops *ops,
     141                                               void *additional_data);
    127142
    128143/**
     
    137152
    138153/**
    139  * @brief Set the default tevent backent.
     154 * @brief Set the default tevent backend.
    140155 *
    141156 * @param[in]  backend  The name of the backend to set.
     
    163178 * @note To cancel the monitoring of a file descriptor, call talloc_free()
    164179 * 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.
    165185 */
    166186struct tevent_fd *tevent_add_fd(struct tevent_context *ev,
     
    306326 * @note To cancel a signal handler, call talloc_free() on the event returned
    307327 * from this function.
     328 *
     329 * @see tevent_num_signals, tevent_sa_info_queue_count
    308330 */
    309331struct tevent_signal *tevent_add_signal(struct tevent_context *ev,
     
    327349#endif
    328350
     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 */
     361size_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 */
     374size_t tevent_sa_info_queue_count(void);
     375
    329376#ifdef DOXYGEN
    330377/**
     
    502549int tevent_set_debug_stderr(struct tevent_context *ev);
    503550
     551enum 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
     573typedef 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 */
     586void 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 */
     601void tevent_get_trace_callback(struct tevent_context *ev,
     602                               tevent_trace_callback_t *cb,
     603                               void *private_data);
     604
    504605/**
    505606 * @}
     
    517618 * are considered too low-level to be used in larger computations. To
    518619 * 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. These
    520  * requests are much easier to compose than the low-level event
     620 * 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
    521622 * handlers called from tevent_add_fd.
    522623 *
     
    840941#endif
    841942
     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 */
     951typedef 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 */
     976void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn);
     977
    842978#ifdef DOXYGEN
    843979/**
     
    852988 * @endcode
    853989 *
    854  * Tevent_req_create() creates the state variable as a talloc child of
    855  * its result. The state variable should be used as the talloc parent
    856  * for all temporary variables that are allocated during the async
     990 * 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
    857993 * computation. This way, when the user of the async computation frees
    858994 * the request, the state as a talloc child will be free'd along with
     
    9961132#endif
    9971133
     1134#ifdef DOXYGEN
     1135/**
     1136 * @brief Indicate out of memory to a request
     1137 *
     1138 * @param[in]  req      The request being processed.
     1139 */
     1140void tevent_req_oom(struct tevent_req *req);
     1141#else
     1142void _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
    9981148/**
    9991149 * @brief Finish a request before the caller had the change to set the callback.
     
    10031153 * the engine. To present the illusion of a callback to the user of the API,
    10041154 * the implementation can call this helper function which triggers an
    1005  * immediate timed event. This way the caller can use the same calling
     1155 * immediate event. This way the caller can use the same calling
    10061156 * conventions, independent of whether the request was actually deferred.
    10071157 *
     
    10271177 * @param[in]  req      The finished request.
    10281178 *
    1029  * @param[in]  ev       The tevent_context for the timed event.
     1179 * @param[in]  ev       The tevent_context for the immediate event.
    10301180 *
    10311181 * @return              The given request will be returned.
     
    10331183struct tevent_req *tevent_req_post(struct tevent_req *req,
    10341184                                   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 */
     1225void tevent_req_defer_callback(struct tevent_req *req,
     1226                               struct tevent_context *ev);
    10351227
    10361228/**
     
    12191411 * @param[in]  secs     The seconds to set.
    12201412 *
    1221  * @param[in]  usecs    The milliseconds to set.
     1413 * @param[in]  usecs    The microseconds to set.
    12221414 *
    12231415 * @return              A timeval structure with the given values.
     
    12541446 * @param[in]  secs      The seconds to add to the timeval.
    12551447 *
    1256  * @param[in]  usecs     The milliseconds to add to the timeval.
     1448 * @param[in]  usecs     The microseconds to add to the timeval.
    12571449 *
    12581450 * @return               The timeval structure with the new time.
     
    12661458 * @param[in]  secs     The seconds of the offset from now.
    12671459 *
    1268  * @param[in]  usecs    The milliseconds of the offset from now.
     1460 * @param[in]  usecs    The microseconds of the offset from now.
    12691461 *
    12701462 * @return              A timval with the given offset in the future.
     
    12921484
    12931485struct tevent_queue;
     1486struct tevent_queue_entry;
    12941487
    12951488#ifdef DOXYGEN
     
    13031496 * @return              An allocated tevent queue on success, NULL on error.
    13041497 *
    1305  * @see tevent_start()
    1306  * @see tevent_stop()
     1498 * @see tevent_queue_start()
     1499 * @see tevent_queue_stop()
    13071500 */
    13081501struct tevent_queue *tevent_queue_create(TALLOC_CTX *mem_ctx,
     
    13261519 *
    13271520 * @see tevent_queue_add()
     1521 * @see tevent_queue_add_entry()
     1522 * @see tevent_queue_add_optimize_empty()
    13281523 */
    13291524typedef void (*tevent_queue_trigger_fn_t)(struct tevent_req *req,
     
    13401535 *
    13411536 * @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.
    13431540 *
    13441541 * @param[in]  private_data The private data passed to the trigger function.
     
    13541551
    13551552/**
     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 */
     1578struct 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 */
     1618struct 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/**
    13561626 * @brief Start a tevent queue.
    13571627 *
     
    13791649 */
    13801650size_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 */
     1661bool 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 */
     1678struct 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 */
     1694bool tevent_queue_wait_recv(struct tevent_req *req);
    13811695
    13821696typedef int (*tevent_nesting_hook)(struct tevent_context *ev,
     
    13861700                                   void *stack_ptr,
    13871701                                   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 */
     1718struct 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 */
     1748void 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
    13881753#ifdef TEVENT_DEPRECATED
    13891754#ifndef _DEPRECATED_
  • vendor/current/lib/tevent/tevent.pc.in

    r740 r988  
    88Version: @PACKAGE_VERSION@
    99Requires: talloc
    10 Libs: -L${libdir} -ltevent
    11 Cflags: @LIB_RPATH@ -I${includedir}
     10Libs: @LIB_RPATH@ -L${libdir} -ltevent
     11Cflags: -I${includedir}
    1212URL: http://samba.org/
  • vendor/current/lib/tevent/tevent_debug.c

    r414 r988  
    9595}
    9696
     97void 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
     105void 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
     113void 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  
    55
    66   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
    89
    910     ** NOTE! The following LGPL license applies to the tevent
     
    4041
    4142        pid_t pid;
     43
     44        bool panic_force_replay;
     45        bool *panic_state;
     46        bool (*panic_fallback)(struct tevent_context *ev, bool replay);
    4247};
    4348
     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
     56static 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
     72static 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
     89static 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
    44130/*
    45131  called when a epoll call fails
    46132*/
    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();
     133static 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        }
    52169}
    53170
     
    79196{
    80197        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
    81209        epoll_ev->pid = getpid();
    82210        talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
    83         if (epoll_ev->epoll_fd == -1) {
    84                 return -1;
    85         }
     211
    86212        return 0;
    87213}
    88214
    89 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
     215static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
    90216
    91217/*
    92218  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
    94220  demonstration of why this is needed
    95221 */
     
    97223{
    98224        struct tevent_fd *fde;
     225        bool *caller_panic_state = epoll_ev->panic_state;
     226        bool panic_triggered = false;
    99227
    100228        if (epoll_ev->pid == getpid()) {
     
    105233        epoll_ev->epoll_fd = epoll_create(64);
    106234        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
     268static 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) {
    107288                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}
    120352
    121353/*
     
    125357{
    126358        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;
    130363        fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
    131364
    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        }
    134376
    135377        ZERO_STRUCT(event);
    136378        event.events = epoll_map_flags(fde->flags);
     379        if (mpx_fde != NULL) {
     380                event.events |= epoll_map_flags(mpx_fde->flags);
     381        }
    137382        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
    141408        fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
    142 
    143409        /* only if we want to read we want to tell the event handler about errors */
    144410        if (fde->flags & TEVENT_FD_READ) {
    145411                fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
    146412        }
     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        }
    147423}
    148424
     
    153429{
    154430        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;
    158435        fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
    159436
    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*/
     480static 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        }
    162500
    163501        ZERO_STRUCT(event);
    164502        event.events = epoll_map_flags(fde->flags);
     503        if (mpx_fde != NULL) {
     504                event.events |= epoll_map_flags(mpx_fde->flags);
     505        }
    165506        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;
    191526        /* only if we want to read we want to tell the event handler about errors */
    192527        if (fde->flags & TEVENT_FD_READ) {
    193528                fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
    194529        }
    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
     542static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
    198543{
    199544        bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
    200545        bool want_read = (fde->flags & TEVENT_FD_READ);
    201546        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        }
    206564
    207565        /* there's already an event */
     
    229587
    230588/*
     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*/
     593static 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/*
    231621  event loop handling using epoll
    232622*/
     
    237627        struct epoll_event events[MAXEVENTS];
    238628        int timeout = -1;
    239 
    240         if (epoll_ev->epoll_fd == -1) return -1;
     629        int wait_errno;
    241630
    242631        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 */
    244633                timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
    245634        }
     
    250639        }
    251640
     641        tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
    252642        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) {
    255647                if (tevent_common_check_signal(epoll_ev->ev)) {
    256648                        return 0;
     
    258650        }
    259651
    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);
    262654                return -1;
    263655        }
     
    270662
    271663        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,
    273665                                                       struct tevent_fd);
    274666                uint16_t flags = 0;
     667                struct tevent_fd *mpx_fde = NULL;
    275668
    276669                if (fde == NULL) {
    277                         epoll_panic(epoll_ev, "epoll_wait() gave bad data");
     670                        epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
    278671                        return -1;
    279672                }
     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                }
    280681                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);
    290687                                continue;
    291688                        }
     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                        }
    292699                        flags |= TEVENT_FD_READ;
    293700                }
    294701                if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
    295702                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;
    296727                if (flags) {
    297728                        fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
     
    310741        int ret;
    311742        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);
    312749
    313750        epoll_ev = talloc_zero(ev, struct epoll_event_context);
     
    333770        struct tevent_context *ev = fde->event_ctx;
    334771        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;
    344823
    345824        return tevent_common_fd_destructor(fde);
     
    357836                                            const char *location)
    358837{
    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);
    361841        struct tevent_fd *fde;
    362 
    363         epoll_check_reopen(epoll_ev);
     842        bool panic_triggered = false;
    364843
    365844        fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
     
    370849        talloc_set_destructor(fde, epoll_event_fd_destructor);
    371850
    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);
    373859
    374860        return fde;
     
    382868        struct tevent_context *ev;
    383869        struct epoll_event_context *epoll_ev;
     870        bool panic_triggered = false;
    384871
    385872        if (fde->flags == flags) return;
    386873
    387874        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);
    389877
    390878        fde->flags = flags;
    391879
     880        epoll_ev->panic_state = &panic_triggered;
    392881        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
    399892*/
    400893static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
    401894{
    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);
    404898        struct timeval tval;
     899        bool panic_triggered = false;
    405900
    406901        if (ev->signal_events &&
     
    419914        }
    420915
     916        epoll_ev->panic_state = &panic_triggered;
     917        epoll_ev->panic_force_replay = true;
    421918        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;
    422925
    423926        return epoll_event_loop(epoll_ev, &tval);
     
    430933        .get_fd_flags           = tevent_common_fd_get_flags,
    431934        .set_fd_flags           = epoll_event_set_fd_flags,
    432         .add_timer              = tevent_common_add_timer,
     935        .add_timer              = tevent_common_add_timer_v2,
    433936        .schedule_immediate     = tevent_common_schedule_immediate,
    434937        .add_signal             = tevent_common_add_signal,
  • vendor/current/lib/tevent/tevent_immediate.c

    r414 r988  
    8989        im->additional_data     = NULL;
    9090
    91         DLIST_ADD_END(ev->immediate_events, im, struct tevent_immediate *);
     91        DLIST_ADD_END(ev->immediate_events, im);
    9292        talloc_set_destructor(im, tevent_common_immediate_destructor);
    9393
  • vendor/current/lib/tevent/tevent_internal.h

    r740 r988  
    7575
    7676        /**
     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        /**
    7789         * @brief Internal state of the request
    7890         *
     
    141153                 */
    142154                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;
    143161
    144162                /**
     
    253271                void *hook_private;
    254272        } 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
     287const struct tevent_ops *tevent_find_ops_byname(const char *name);
    257288
    258289int tevent_common_context_destructor(struct tevent_context *ev);
     
    281312                                             const char *handler_name,
    282313                                             const char *location);
     314struct 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);
    283321struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
    284322
     
    305343bool tevent_select_init(void);
    306344bool tevent_poll_init(void);
     345void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
     346                                       struct tevent_fd *fde);
     347bool tevent_poll_mt_init(void);
    307348#ifdef HAVE_EPOLL
    308349bool tevent_epoll_init(void);
     350void tevent_epoll_set_panic_fallback(struct tevent_context *ev,
     351                        bool (*panic_fallback)(struct tevent_context *ev,
     352                                               bool replay));
    309353#endif
     354#ifdef HAVE_SOLARIS_PORTS
     355bool tevent_port_init(void);
     356#endif
     357
     358
     359void tevent_trace_point_callback(struct tevent_context *ev,
     360                                 enum tevent_trace_point);
  • vendor/current/lib/tevent/tevent_liboop.c

    r740 r988  
    22   Unix SMB/CIFS implementation.
    33   main select loop and event handling
    4    wrapper for http://liboop.org/
     4   wrapper for http://git.lysator.liu.se/liboop/
    55
    66   Copyright (C) Stefan Metzmacher 2005
  • vendor/current/lib/tevent/tevent_poll.c

    r740 r988  
    3131
    3232struct 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
    3350        /*
    3451         * These two arrays are maintained together.
    3552         */
    3653        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;
    4261};
    4362
     63static 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
    4499/*
    45   create a select_event_context structure.
     100  create a poll_event_context structure.
    46101*/
    47102static int poll_event_context_init(struct tevent_context *ev)
    48103{
    49104        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);
    50113
    51114        poll_ev = talloc_zero(ev, struct poll_event_context);
     
    53116                return -1;
    54117        }
     118        poll_ev->ev = ev;
     119        poll_ev->signal_fd = -1;
    55120        ev->additional_data = poll_ev;
     121        talloc_set_destructor(poll_ev, poll_event_context_destructor);
    56122        return 0;
     123}
     124
     125static 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
     138static 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
     182static 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
     196static 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));
    57214}
    58215
     
    63220{
    64221        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;
    67223        uint64_t del_idx = fde->additional_flags;
    68224
     
    74230                ev->additional_data, struct poll_event_context);
    75231
    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);
    82243done:
    83244        return tevent_common_fd_destructor(fde);
     245}
     246
     247static 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);
    84284}
    85285
     
    98298        struct poll_event_context *poll_ev = talloc_get_type_abort(
    99299                ev->additional_data, struct poll_event_context);
    100         struct pollfd *pfd;
    101300        struct tevent_fd *fde;
    102301
    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);
    106307        if (fde == NULL) {
    107308                return NULL;
    108309        }
    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         */
    154328        return fde;
    155329}
     
    160334static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
    161335{
    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;
    164338        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;
    166376
    167377        if (flags & TEVENT_FD_READ) {
     
    171381                pollflags |= (POLLOUT);
    172382        }
    173 
    174383        poll_ev->fds[idx].events = pollflags;
    175384
    176         fde->flags = flags;
     385        poll_event_wake_pollthread(poll_ev);
     386}
     387
     388static 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;
    177487}
    178488
    179489/*
    180   event loop handling using select()
     490  event loop handling using poll()
    181491*/
    182492static int poll_event_loop_poll(struct tevent_context *ev,
     
    185495        struct poll_event_context *poll_ev = talloc_get_type_abort(
    186496                ev->additional_data, struct poll_event_context);
    187         struct tevent_fd *fde;
    188497        int pollrtn;
    189498        int timeout = -1;
     499        int poll_errno;
     500        struct tevent_fd *fde = NULL;
     501        struct tevent_fd *next = NULL;
     502        unsigned i;
    190503
    191504        if (ev->signal_events && tevent_common_check_signal(ev)) {
     
    198511        }
    199512
     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);
    200520        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) {
    203525                tevent_common_check_signal(ev);
    204526                return 0;
    205         }
    206 
    207         if (pollrtn == -1 && errno == EBADF) {
    208                 /* the socket is dead! this should never
    209                    happen as the socket should have first been
    210                    made readable and that should have removed
    211                    the event, so this must be a bug. This is a
    212                    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;
    217527        }
    218528
     
    223533        }
    224534
    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;
    247588                        }
    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;
    258628                        }
    259629                }
     
    287657
    288658        return poll_event_loop_poll(ev, &tval);
     659}
     660
     661static 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;
    289689}
    290690
     
    295695        .get_fd_flags           = tevent_common_fd_get_flags,
    296696        .set_fd_flags           = poll_event_set_fd_flags,
    297         .add_timer              = tevent_common_add_timer,
     697        .add_timer              = tevent_common_add_timer_v2,
    298698        .schedule_immediate     = tevent_common_schedule_immediate,
    299699        .add_signal             = tevent_common_add_signal,
    300700        .loop_once              = poll_event_loop_once,
    301         .loop_wait              = tevent_common_loop_wait,
     701        .loop_wait              = poll_event_loop_wait,
    302702};
    303703
     
    306706        return tevent_register_backend("poll", &poll_event_ops);
    307707}
     708
     709static 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  
    134134                                           void *private_data)
    135135{
    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);
    138139
    139140        if (!q->running) {
     141                return;
     142        }
     143
     144        if (!q->list) {
    140145                return;
    141146        }
     
    143148        q->list->triggered = true;
    144149        q->list->trigger(q->list->req, q->list->private_data);
     150}
     151
     152static 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;
    145228}
    146229
     
    153236        struct tevent_queue_entry *e;
    154237
    155         e = talloc_zero(req, struct tevent_queue_entry);
     238        e = tevent_queue_add_internal(queue, ev, req,
     239                                      trigger, private_data, false);
    156240        if (e == NULL) {
    157241                return false;
    158242        }
    159243
    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
     247struct 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
     258struct 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
     269void 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;
    172280        }
    173281
    174282        if (queue->list->triggered) {
    175                 return true;
     283                return;
    176284        }
    177285
     
    180288                                  tevent_queue_immediate_trigger,
    181289                                  queue);
    182 
     290}
     291
     292void tevent_queue_stop(struct tevent_queue *queue)
     293{
     294        queue->running = false;
     295}
     296
     297size_t tevent_queue_length(struct tevent_queue *queue)
     298{
     299        return queue->length;
     300}
     301
     302bool tevent_queue_running(struct tevent_queue *queue)
     303{
     304        return queue->running;
     305}
     306
     307struct tevent_queue_wait_state {
     308        uint8_t dummy;
     309};
     310
     311static void tevent_queue_wait_trigger(struct tevent_req *req,
     312                                      void *private_data);
     313
     314struct 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
     339static void tevent_queue_wait_trigger(struct tevent_req *req,
     340                                         void *private_data)
     341{
     342        tevent_req_done(req);
     343}
     344
     345bool 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);
    183356        return true;
    184357}
    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  
    5252}
    5353
     54static int tevent_req_destructor(struct tevent_req *req);
     55
    5456struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
    5557                                    void *pdata,
     
    6264        void *data;
    6365
    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);
    6569        if (req == NULL) {
    6670                return NULL;
    6771        }
     72        ZERO_STRUCTP(req);
    6873        req->internal.private_type      = type;
    6974        req->internal.create_location   = location;
    70         req->internal.finish_location   = NULL;
    7175        req->internal.state             = TEVENT_REQ_IN_PROGRESS;
    7276        req->internal.trigger           = tevent_create_immediate(req);
     
    8589        req->data = data;
    8690
     91        talloc_set_destructor(req, tevent_req_destructor);
     92
    8793        *ppdata = data;
    8894        return req;
    8995}
    9096
     97static int tevent_req_destructor(struct tevent_req *req)
     98{
     99        tevent_req_received(req);
     100        return 0;
     101}
     102
    91103void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
    92104{
    93105        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        }
    94111        if (req->async.fn != NULL) {
    95112                req->async.fn(req);
    96113        }
     114}
     115
     116static 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);
    97132}
    98133
     
    101136                              const char *location)
    102137{
     138        /*
     139         * make sure we do not timeout after
     140         * the request was already finished
     141         */
     142        TALLOC_FREE(req->internal.timer);
     143
    103144        req->internal.state = state;
     145        req->internal.finish_location = location;
     146
     147        tevent_req_cleanup(req);
     148
    104149        _tevent_req_notify_callback(req, location);
    105150}
     
    124169}
    125170
     171void _tevent_req_oom(struct tevent_req *req, const char *location)
     172{
     173        tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
     174}
     175
    126176bool _tevent_req_nomem(const void *p,
    127177                       struct tevent_req *req,
     
    131181                return false;
    132182        }
    133         tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
     183        _tevent_req_oom(req, location);
    134184        return true;
    135185}
     
    150200                               void *private_data)
    151201{
    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);
    154205
    155206        tevent_req_finish(req, req->internal.state,
     
    165216}
    166217
     218void tevent_req_defer_callback(struct tevent_req *req,
     219                               struct tevent_context *ev)
     220{
     221        req->internal.defer_callback_ev = ev;
     222}
     223
    167224bool tevent_req_is_in_progress(struct tevent_req *req)
    168225{
     
    176233void tevent_req_received(struct tevent_req *req)
    177234{
    178         TALLOC_FREE(req->data);
     235        talloc_set_destructor(req, NULL);
     236
    179237        req->private_print = NULL;
     238        req->private_cancel = NULL;
    180239
    181240        TALLOC_FREE(req->internal.trigger);
     
    183242
    184243        req->internal.state = TEVENT_REQ_RECEIVED;
     244
     245        tevent_req_cleanup(req);
     246
     247        TALLOC_FREE(req->data);
    185248}
    186249
     
    218281                               void *private_data)
    219282{
    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);
    222286
    223287        TALLOC_FREE(req->internal.timer);
     
    276340        return req->private_cancel(req);
    277341}
     342
     343void 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  
    3636        /* the maximum file descriptor number in fd_events */
    3737        int maxfd;
    38 
    39         /* information for exiting from the event loop */
    40         int exit_code;
    4138};
    4239
     
    4744{
    4845        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);
    4952
    5053        select_ev = talloc_zero(ev, struct select_event_context);
     
    8689
    8790        if (ev) {
    88                 select_ev = talloc_get_type(ev->additional_data,
    89                                             struct select_event_context);
     91                select_ev = talloc_get_type_abort(ev->additional_data,
     92                                                  struct select_event_context);
    9093
    9194                if (select_ev->maxfd == fde->fd) {
     
    108111                                             const char *location)
    109112{
    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);
    112116        struct tevent_fd *fde;
    113117
     
    139143        struct tevent_fd *fde;
    140144        int selrtn;
     145        int select_errno;
    141146
    142147        /* we maybe need to recalculate the maxfd */
     
    151156        for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
    152157                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);
    153162                        errno = EBADF;
    154163                        return -1;
     
    168177        }
    169178
     179        tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
    170180        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 &&
    173185            select_ev->ev->signal_events) {
    174186                tevent_common_check_signal(select_ev->ev);
     
    176188        }
    177189
    178         if (selrtn == -1 && errno == EBADF) {
     190        if (selrtn == -1 && select_errno == EBADF) {
    179191                /* the socket is dead! this should never
    180192                   happen as the socket should have first been
     
    184196                tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
    185197                             "ERROR: EBADF on select_event_loop_once\n");
    186                 select_ev->exit_code = EBADF;
     198                errno = select_errno;
    187199                return -1;
    188200        }
     
    201213                        uint16_t flags = 0;
    202214
    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                        }
    205221                        if (flags) {
     222                                DLIST_DEMOTE(select_ev->ev->fd_events, fde);
    206223                                fde->handler(select_ev->ev, fde, flags, fde->private_data);
    207224                                break;
     
    218235static int select_event_loop_once(struct tevent_context *ev, const char *location)
    219236{
    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);
    222240        struct timeval tval;
    223241
     
    246264        .get_fd_flags           = tevent_common_fd_get_flags,
    247265        .set_fd_flags           = tevent_common_fd_set_flags,
    248         .add_timer              = tevent_common_add_timer,
     266        .add_timer              = tevent_common_add_timer_v2,
    249267        .schedule_immediate     = tevent_common_schedule_immediate,
    250268        .add_signal             = tevent_common_add_signal,
  • vendor/current/lib/tevent/tevent_signal.c

    r860 r988  
    1 /* 
     1/*
    22   Unix SMB/CIFS implementation.
    33
     
    3131#include "tevent_util.h"
    3232
    33 #define TEVENT_NUM_SIGNALS 64
    34 
    3533/* maximum number of SA_SIGINFO signals to hold in the queue.
    3634  NB. This *MUST* be a power of 2, in order for the ring buffer
     
    3836  for this. */
    3937
    40 #define TEVENT_SA_INFO_QUEUE_COUNT 64
     38#define TEVENT_SA_INFO_QUEUE_COUNT 256
     39
     40size_t tevent_num_signals(void)
     41{
     42        return TEVENT_NUM_SIGNALS;
     43}
     44
     45size_t tevent_sa_info_queue_count(void)
     46{
     47        return TEVENT_SA_INFO_QUEUE_COUNT;
     48}
    4149
    4250struct tevent_sigcounter {
     
    4553};
    4654
     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
    4760#define TEVENT_SIG_INCREMENT(s) (s).count++
     61#endif
    4862#define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
    4963#define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
     
    8397{
    8498        char c = 0;
    85         ssize_t res;
    8699        struct tevent_common_signal_list *sl;
    87100        struct tevent_context *ev = NULL;
     
    96109                        ev = sl->se->event_ctx;
    97110                        /* 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);
    99112                }
    100113        }
     
    174187static int tevent_signal_destructor(struct tevent_signal *se)
    175188{
    176         struct tevent_common_signal_list *sl;
    177         sl = talloc_get_type(se->additional_data,
    178                              struct tevent_common_signal_list);
     189        struct tevent_common_signal_list *sl =
     190                talloc_get_type_abort(se->additional_data,
     191                struct tevent_common_signal_list);
    179192
    180193        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                }
    182207        }
    183208
     
    188213                if (sig_state->oldact[se->signum]) {
    189214                        sigaction(se->signum, sig_state->oldact[se->signum], NULL);
     215                        talloc_free(sig_state->oldact[se->signum]);
    190216                        sig_state->oldact[se->signum] = NULL;
    191217                }
     
    210236{
    211237        char c[16];
    212         ssize_t res;
    213238        /* 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));
    215240}
    216241
     
    316341                if (sig_state->oldact[signum] == NULL) {
    317342                        talloc_free(se);
    318                         return NULL;                   
     343                        return NULL;
    319344                }
    320345                if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
     346                        talloc_free(sig_state->oldact[signum]);
     347                        sig_state->oldact[signum] = NULL;
    321348                        talloc_free(se);
    322349                        return NULL;
     
    339366}
    340367
     368struct tevent_se_exists {
     369        struct tevent_se_exists **myself;
     370};
     371
     372static int tevent_se_exists_destructor(struct tevent_se_exists *s)
     373{
     374        *s->myself = NULL;
     375        return 0;
     376}
    341377
    342378/*
     
    351387                return 0;
    352388        }
    353        
     389
    354390        for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
    355391                struct tevent_common_signal_list *sl, *next;
     
    367403                for (sl=sig_state->sig_handlers[i];sl;sl=next) {
    368404                        struct tevent_signal *se = sl->se;
     405                        struct tevent_se_exists *exists;
     406
    369407                        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
    370424#ifdef SA_SIGINFO
    371425                        if (se->sa_flags & SA_SIGINFO) {
     
    382436                                                % TEVENT_SA_INFO_QUEUE_COUNT;
    383437                                        se->handler(ev, se, i, 1,
    384                                                     (void*)&sig_state->sig_info[i][ofs], 
     438                                                    (void*)&sig_state->sig_info[i][ofs],
    385439                                                    se->private_data);
     440                                        if (!exists) {
     441                                                break;
     442                                        }
    386443                                }
    387444#ifdef SA_RESETHAND
    388                                 if (se->sa_flags & SA_RESETHAND) {
     445                                if (exists && (se->sa_flags & SA_RESETHAND)) {
    389446                                        talloc_free(se);
    390447                                }
    391448#endif
     449                                talloc_free(exists);
    392450                                continue;
    393451                        }
     
    395453                        se->handler(ev, se, i, count, NULL, se->private_data);
    396454#ifdef SA_RESETHAND
    397                         if (se->sa_flags & SA_RESETHAND) {
     455                        if (exists && (se->sa_flags & SA_RESETHAND)) {
    398456                                talloc_free(se);
    399457                        }
    400458#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) {
    405464                        uint32_t j;
    406465                        for (j=0;j<count;j++) {
     
    441500void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
    442501{
    443         struct tevent_common_signal_list *sl;
    444         sl = talloc_get_type(se->additional_data,
    445                              struct tevent_common_signal_list);
     502        struct tevent_common_signal_list *sl =
     503                talloc_get_type_abort(se->additional_data,
     504                struct tevent_common_signal_list);
    446505
    447506        tevent_common_signal_list_destructor(sl);
     
    450509                if (sig_state->oldact[se->signum]) {
    451510                        sigaction(se->signum, sig_state->oldact[se->signum], NULL);
     511                        talloc_free(sig_state->oldact[se->signum]);
    452512                        sig_state->oldact[se->signum] = NULL;
    453513                }
  • vendor/current/lib/tevent/tevent_standard.c

    r740 r988  
    22   Unix SMB/CIFS implementation.
    33   main select loop and event handling
    4    Copyright (C) Andrew Tridgell        2003-2005
    5    Copyright (C) Stefan Metzmacher      2005-2009
     4   Copyright (C) Stefan Metzmacher      2013
     5   Copyright (C) Jeremy Allison         2013
    66
    77     ** NOTE! The following LGPL license applies to the tevent
     
    2727
    2828  - we try to use epoll if configure detected support for it
    29     otherwise we use select()
     29    otherwise we use poll()
    3030  - 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()
    3232*/
    3333
    3434#include "replace.h"
    35 #include "system/filesys.h"
    36 #include "system/select.h"
    3735#include "tevent.h"
    3836#include "tevent_util.h"
    3937#include "tevent_internal.h"
    4038
    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;
     39struct 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;
    5644};
    5745
    58 /* use epoll if it is available */
    59 #if HAVE_EPOLL
     46static int std_event_context_init(struct tevent_context *ev);
     47
     48static const struct tevent_ops std_event_ops = {
     49        .context_init           = std_event_context_init,
     50};
     51
    6052/*
    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
     58static 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
     106static 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
     132static 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}
    74148/*
    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*/
     152static 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) {
    290166                        return -1;
    291167                }
    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);
    323212#endif
    324213
    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
     217fallback:
     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}
    568228
    569229_PRIVATE_ bool tevent_standard_init(void)
     
    571231        return tevent_register_backend("standard", &std_event_ops);
    572232}
    573 
  • vendor/current/lib/tevent/tevent_timed.c

    r740 r988  
    134134static int tevent_common_timed_destructor(struct tevent_timer *te)
    135135{
     136        if (te->event_ctx == NULL) {
     137                return 0;
     138        }
     139
    136140        tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
    137141                     "Destroying timer event %p \"%s\"\n",
    138142                     te, te->handler_name);
    139143
    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);
    143148
    144149        return 0;
     
    154159  return NULL on failure (memory allocation error)
    155160*/
    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;
     161static 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;
    164172
    165173        te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
     
    174182        te->additional_data     = NULL;
    175183
     184        if (ev->timer_events == NULL) {
     185                ev->last_zero_timer = NULL;
     186        }
     187
    176188        /* 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
    181223                        break;
    182224                }
    183225
    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);
    188230
    189231        talloc_set_destructor(te, tevent_common_timed_destructor);
     
    193235                     handler_name, te);
    194236        return te;
     237}
     238
     239struct 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
     260struct 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);
    195275}
    196276
     
    243323         * handler because in a semi-async inner event loop called from the
    244324         * 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        }
    245328        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);
    246333
    247334        /*
  • vendor/current/lib/tevent/tevent_util.c

    r414 r988  
    8989#undef FLAG_TO_SET
    9090}
     91
     92bool 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  
    5454  list_head->prev, which means we can add to the end of the list in
    5555  O(1) time
    56 
    57 
    58   Note that the 'type' arguments below are no longer needed, but
    59   are kept for now to prevent an incompatible argument change
    6056 */
    6157
     
    132128/*
    133129   add to the end of a list.
    134    Note that 'type' is ignored
    135130*/
    136 #define DLIST_ADD_END(list, p, type)                    \
     131#define DLIST_ADD_END(list, p) \
    137132do { \
    138133        if (!(list)) { \
     
    143138} while (0)
    144139
    145 /* promote an element to the from of a list */
     140/* promote an element to the front of a list */
    146141#define DLIST_PROMOTE(list, p) \
    147142do { \
     
    152147/*
    153148   demote an element to the end of a list.
    154    Note that 'type' is ignored
    155149*/
    156 #define DLIST_DEMOTE(list, p, type)                     \
     150#define DLIST_DEMOTE(list, p) \
    157151do { \
    158152        DLIST_REMOVE(list, p); \
    159         DLIST_ADD_END(list, p, NULL);           \
     153        DLIST_ADD_END(list, p); \
    160154} while (0)
    161155
     
    163157   concatenate two lists - putting all elements of the 2nd list at the
    164158   end of the first list.
    165    Note that 'type' is ignored
    166159*/
    167 #define DLIST_CONCATENATE(list1, list2, type)   \
     160#define DLIST_CONCATENATE(list1, list2) \
    168161do { \
    169162        if (!(list1)) { \
     
    184177int ev_set_blocking(int fd, bool set);
    185178size_t ev_str_list_length(const char **list);
     179bool ev_set_close_on_exec(int fd);
    186180
    187181/* Defined here so we can build against older talloc versions that don't
  • vendor/current/lib/tevent/tevent_wakeup.c

    r414 r988  
    4747
    4848        if (!tevent_req_set_endtime(req, ev, wakeup_time)) {
    49                 goto post;
     49                return tevent_req_post(req, ev);
    5050        }
    51 
    5251        return req;
    53 post:
    54         return tevent_req_post(req, ev);
    5552}
    5653
  • vendor/current/lib/tevent/wscript

    r740 r988  
    22
    33APPNAME = 'tevent'
    4 VERSION = '0.9.11'
     4VERSION = '0.9.28'
    55
    66blddir = 'bin'
     
    1111srcdir = '.'
    1212while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5:
    13     srcdir = '../' + srcdir
     13    srcdir = srcdir + '/..'
    1414sys.path.insert(0, srcdir + '/buildtools/wafsamba')
    1515
    16 import wafsamba, samba_dist, Options, Logs
     16import wafsamba, samba_dist, samba_utils, Options, Logs
    1717
    18 samba_dist.DIST_DIRS('lib/tevent:. lib/replace:lib/replace lib/talloc:lib/talloc buildtools:buildtools')
     18samba_dist.DIST_DIRS('lib/tevent:. lib/replace:lib/replace lib/talloc:lib/talloc buildtools:buildtools third_party/waf:third_party/waf')
    1919
    2020def set_options(opt):
     
    3636
    3737    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,
    3939                                     onlyif='talloc', implied_deps='replace talloc'):
    4040            conf.define('USING_SYSTEM_TEVENT', 1)
     41            if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytevent', 'tevent', minversion=VERSION):
     42                conf.define('USING_SYSTEM_PYTEVENT', 1)
    4143
    4244    if conf.CHECK_FUNCS('epoll_create', headers='sys/epoll.h'):
    4345        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)
    4463
    4564    conf.env.disable_python = getattr(Options.options, 'disable_python', False)
     
    4766    if not conf.env.disable_python:
    4867        # also disable if we don't have the python libs installed
     68        conf.find_program('python', var='PYTHON')
    4969        conf.check_tool('python')
    5070        conf.check_python_version((2,4,2))
     
    5676    conf.SAMBA_CONFIG_H()
    5777
     78    conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
     79
    5880def build(bld):
    5981    bld.RECURSE('lib/replace')
     
    6284    SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c
    6385             tevent_queue.c tevent_req.c tevent_select.c
    64              tevent_poll.c
     86             tevent_poll.c tevent_threads.c
    6587             tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c'''
    6688
     
    6890        SRC += ' tevent_epoll.c'
    6991
     92    if bld.CONFIG_SET('HAVE_SOLARIS_PORTS'):
     93        SRC += ' tevent_port.c'
     94
    7095    if bld.env.standalone_tevent:
    7196        bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
    72         bld.PKG_CONFIG_FILES('tevent.pc', vnum=VERSION)
    7397        private_library = False
    7498    else:
     
    84108                          abi_match='tevent_* _tevent_*',
    85109                          vnum=VERSION,
    86                           public_headers='tevent.h',
     110                          public_headers=('' if private_library else 'tevent.h'),
    87111                          public_headers_install=not private_library,
     112                          pc_files='tevent.pc',
    88113                          private_library=private_library)
    89114
    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')
    95130
    96131
     
    98133    '''test tevent'''
    99134    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)
    100141
    101142
Note: See TracChangeset for help on using the changeset viewer.