github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/lib/select_.py (about)

     1  # Copyright 2016 Google Inc. All Rights Reserved.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  from '__go__/syscall' import (
    16      FD_SETSIZE as _FD_SETSIZE,
    17      Select as _Select,
    18      FdSet as _FdSet,
    19      Timeval as _Timeval
    20  )
    21  import _syscall
    22  import math
    23  
    24  
    25  class error(Exception):
    26    pass
    27  
    28  
    29  def select(rlist, wlist, xlist, timeout=None):
    30    rlist_norm = _normalize_fd_list(rlist)
    31    wlist_norm = _normalize_fd_list(wlist)
    32    xlist_norm = _normalize_fd_list(xlist)
    33    all_fds = rlist_norm + wlist_norm + xlist_norm
    34    if not all_fds:
    35      nfd = 0
    36    else:
    37      nfd = max(all_fds) + 1
    38  
    39    rfds = _make_fdset(rlist_norm)
    40    wfds = _make_fdset(wlist_norm)
    41    xfds = _make_fdset(xlist_norm)
    42  
    43    if timeout is None:
    44      timeval = None
    45    else:
    46      timeval = _Timeval.new()
    47      frac, integer = math.modf(timeout)
    48      timeval.Sec = int(integer)
    49      timeval.Usec = int(frac * 1000000.0)
    50    _syscall.invoke(_Select, nfd, rfds, wfds, xfds, timeval)
    51    return ([rlist[i] for i, fd in enumerate(rlist_norm) if _fdset_isset(fd, rfds)],
    52            [wlist[i] for i, fd in enumerate(wlist_norm) if _fdset_isset(fd, wfds)],
    53            [xlist[i] for i, fd in enumerate(xlist_norm) if _fdset_isset(fd, xfds)])
    54  
    55  
    56  def _fdset_set(fd, fds):
    57    idx = fd / (_FD_SETSIZE / len(fds.Bits)) % len(fds.Bits)
    58    pos = fd % (_FD_SETSIZE / len(fds.Bits))
    59    fds.Bits[idx] |= 1 << pos
    60  
    61  
    62  def _fdset_isset(fd, fds):
    63    idx = fd / (_FD_SETSIZE / len(fds.Bits)) % len(fds.Bits)
    64    pos = fd % (_FD_SETSIZE / len(fds.Bits))
    65    return bool(fds.Bits[idx] & (1 << pos))
    66  
    67  
    68  def _make_fdset(fd_list):
    69    fds = _FdSet.new()
    70    for fd in fd_list:
    71      _fdset_set(fd, fds)
    72    return fds
    73  
    74  
    75  def _normalize_fd_list(fds):
    76    result = []
    77    # Python permits mutating the select fds list during fileno calls so we can't
    78    # just use simple iteration over the list. See test_select_mutated in
    79    # test_select.py
    80    i = 0
    81    while i < len(fds):
    82      fd = fds[i]
    83      if hasattr(fd, 'fileno'):
    84        fd = fd.fileno()
    85      result.append(fd)
    86      i += 1
    87    return result