Commit Graph

392 Commits (93342ba60c4891f31698057164712bcfc9552b22)

Author SHA1 Message Date
David Wilson 93342ba60c Normalize docstring formatting 5 years ago
David Wilson 4e6aadc40a [stream-refactor] fix LogHandler.uncork() race
During early initialization under hackbench, it is possible for Broker
to be in LogHandler._send() while the main thread has already destroyed
_buffer. So we must synchronize them, but only while the handler is
corked.
5 years ago
David Wilson 90c989ee59 [stream-refactor] BufferedWriter must disconenct Stream, not Protocol
Fix a race where if Stream.on_receive() detects disconnect, it calls
Stream.on_disconnect(), which fires Stream 'disconnect' event, whereas
if BufferedWriter.on_transmit() detects disconnect, it called
Protocol.on_disconnect(), which did not fire the Stream 'disconnect'
event.

Since mitogen.parent listens on Stream's 'disconnect' event to reap
children, this was causing a very difficult to trigger test failure.

Triggered after <1000 runs on a Xeon E5530 with hyperthreading using
hackbench running at the same priority:

    $ hackbench -s 1048576 -l 100000000000 -g 4
5 years ago
David Wilson 11ae6f3873 core: better Side attribute docstrings 5 years ago
David Wilson b1379e6f45 [stream-refactor] send MITO002 earlier
Prevents 2.4 bootstrap from attempting to fetch os_fork too early.

Connection(None).connect(): pid:25098 stdin:81 stdout:81 stderr:79
ssh.localhost:2201: (partial): mitogen__has_sudo_nopw@localhost's password:
ssh.localhost:2201: (password prompt): mitogen__has_sudo_nopw@localhost's password:
ssh.localhost:2201: (unrecognized): mitogen__has_sudo_nopw@localhost's password:
BootstrapProtocol(ssh.localhost:2201): first stage started succcessfully
BootstrapProtocol(ssh.localhost:2201): first stage received bootstrap
ssh.localhost:2201: (partial): MIdmitogen.os_fork
ssh.localhost:2201: (unrecognized partial): MIdmitogen.os_fork
ssh.localhost:2201: failing connection due to TimeoutError(u'Failed to setup connection after 10.00 seconds',)
5 years ago
David Wilson 1d2bfc28da [stream-refactor] fix crash in detach() / during async/multiple_items_loop.yml 5 years ago
David Wilson 7c4621a010 [stream-refactor] make syntax 2.4 compatible 5 years ago
David Wilson 8d1b01d8ef Refactor Stream, introduce quasi-asynchronous connect, much more
Split Stream into many, many classes

  * mitogen.parent.Connection: Handles connection setup logic only.
    * Maintain references to stdout and stderr streams.
    * Manages TimerList timer to cancel connection attempt after
      deadline
    * Blocking setup code replaced by async equivalents running on the
      broker

  * mitogen.parent.Options: Tracks connection-specific options. This
    keeps the connection class small, but more importantly, it is
    generic to the future desire to build and execute command lines
    without starting a full connection.

  * mitogen.core.Protocol: Handles program behaviour relating to events
    on a stream. Protocol performs no IO of its own, instead deferring
    it to Stream and Side. This makes testing much easier, and means
    libssh can reimplement Stream and Side to reuse MitogenProtocol

  * mitogen.core.MitogenProtocol: Guts of the old Mitogen stream
    implementtion

  * mitogen.core.BufferedWriter: Guts of the old Mitogen buffered
    transmit implementation, made generic

  * mitogen.core.DelineatedProtocol: Guts of the old IoLogger, knows how
    to split up input and pass it on to a
    on_line_received()/on_partial_line_received() callback.

  * mitogen.parent.BootstrapProtocol: Asynchronous equivalent of the old
    blocking connect code. Waits for various prompts (MITO001 etc) and
    writes the bootstrap using a BufferedWriter. On success, switches
    the stream to MitogenProtocol.

  * mitogen.core.Message: move encoding parts of MitogenProtocol out to
    Message (where it belongs) and write a bunch of new tests for
    pickling.

  * The bizarre Stream.construct() is gone now, Option.__init__ is its
    own constructor. Should fix many LGTM errors.

* Update all connection methods:  Every connection method is updated to
  use async logic, defining protocols as required to handle interactive
  prompts like in SSH or su. Add new real integration tests for at least
  doas and su.

* Eliminate manual fd management: File descriptors are trapped in file
  objects at their point of origin, and Side is updated to use file
  objects rather than raw descriptors. This eliminates a whole class of
  bugs where unrelated FDs could be closed by the wrong component. Now
  an FD's open/closed status is fused to it everywhere in the library.

* Halve file descriptor usage: now FD open/close state is tracked by
  its file object, we don't need to duplicate FDs everywhere so that
  receive/transmit side can be closed independently. Instead both sides
  back on to the same file object. Closes #26, Closes #470.

* Remove most uses of dup/dup2: Closes #256. File descriptors are
  trapped in a common file object and shared among classes. The
  remaining few uses for dup/dup2 are as close to minimal as possible.

* Introduce mitogen.parent.Process: uniform interface for subprocesses
  created either via mitogen.fork or the subprocess module. Remove all
  the crap where we steal a pid from subprocess guts. Now we use
  subprocess to manage its processes as it should be. Closes #169 by
  using the new Timers facility to poll for a slow-to-exit subprocess.

* Fix su password race: Closes #363. DelineatedProtocol naturally
  retries partially received lines, preventing the cause of the original
  race.

* Delete old blocking IO utility functions
  iter_read()/write_all()/discard_until().

Closes #26
Closes #147
Closes #169
Closes #256
Closes #363
Closes #419
Closes #470
5 years ago
David Wilson 37beb3a5c5 core: teach iter_split() to break on callback returning False. 5 years ago
David Wilson 33ecc8a5d2 issue #507: log fatal errors to syslog.
Next round should log entire exception text, but this is useful enough
already.
5 years ago
David Wilson 46ebd56c7a core/master: docstring, repr, and debug log message cleanups
Debug output is vastly more readable now.
5 years ago
David Wilson c7ebb39ad4 core: introduce Protocol, DelimitedProtocol and BufferedWriter.
They aren't wired in yet as of this commit, and continue duplicating
other code.
5 years ago
David Wilson d368971749 core: introduce mitogen.core.pipe()
It's used in later commit. This is an os.pipe() wrapper that traps the
file descriptors in a file object, to ensure leaked objects will
eventually be collected, and a central place exists to track open/closed
status.
5 years ago
David Wilson d1f5e0663d core: move message encoding to Message.pack(), add+refactor tests.
The old inline pack is still present in the old location but will be
removed in a followup commit.
5 years ago
David Wilson aba396d4c5 core: bootstrap FD management improvements
- open fd 0/1/2 with correct file mode
- trap reserve_tty_fd in a file object, since all other FD manual FD
  management is going away.
5 years ago
David Wilson 4f0a946f30 core: pending timers should keep broker alive. 5 years ago
David Wilson 237a3babaf core: more succinct iter_split(). 5 years ago
David Wilson dfefc4c05c core: replace UTF8_CODEC with encodings.utf_8.encode() function. 5 years ago
David Wilson 3f90030c1e core: docstring style cleanups, dead code. 5 years ago
David Wilson 5aca9d6c3f core: split out iter_split() for use in parent.py. 5 years ago
David Wilson a5536c3514 core: eliminate some quadratric behaviour from IoLogger
This is the same problem as used to afflict Stream: large input buffers
containing many small messages cause intense string copying. This
eliminates the worst of it.
5 years ago
David Wilson 2fbc77a155 issue #170: implement timers. 5 years ago
Jordan Webb 1a02a86331
Add buildah transport 5 years ago
David Wilson 8f940e2ccb issue #590: teach importer to handle self-replacing modules 5 years ago
David Wilson ee62c57c9d issue #576: fix Kwargs minor version check.
Unicode kwargs were introduced in Python 2.6.5, not 2.6.0.
5 years ago
David Wilson 87c8ab4323 issue #550: fix up TTY ioctls on WSL 2016 Anniversary Update 5 years ago
David Wilson 18b984a0b4 issue #535: activate Corker on 2.4 in master too. 5 years ago
David Wilson 06e52ca89f issue #535: wire mitogen.os_fork into Broker and Pool. 5 years ago
David Wilson 63f4864b21 issue #535: introduce mitogen.os_fork module and Corker class. 5 years ago
David Wilson eb9ec26622 issue #535: core: unicode.encode() may take importer lock on 2.x
Found on Python 2.4, where import happens immediately following connect.

- Main thread executes import statement, triggers request to parent
- Broker thread attempts to deliver request via Router
- Router discovers parent has disconnected, prepares a dead message
- .dead() calls unicode.encode() to format reason string
- .encode() attemptsto import a codec module
- deadlock

----

(gdb) pystack
/usr/local/python2.4.6/lib/python2.4/encodings/__init__.py (69): search_function
<stdin> (733): dead
<stdin> (2717): _maybe_send_dead
<stdin> (2724): _invoke
<stdin> (2749): _async_route
<stdin> (1635): _receive_one
<stdin> (1603): _internal_receive
<stdin> (1613): on_receive
<stdin> (2931): _call
<stdin> (2942): _loop_once
<stdin> (2988): _do_broker_main
<stdin> (545): _profile_hook
<stdin> (3007): _broker_main
/usr/local/python2.4.6/lib/python2.4/threading.py (420): run
/usr/local/python2.4.6/lib/python2.4/threading.py (424): __bootstrap
5 years ago
David Wilson b3f592acee issue #535: core/select: support selecting from Latches. 5 years ago
David Wilson 7d0480e8bd core: increase cookie field lengths to 64-bit; closes #545. 5 years ago
David Wilson ca63c26e01 core: Make Latch.put(obj=) optional. 5 years ago
David Wilson 9bcd2ec56c issue #542: return of select poller, new selection logic 5 years ago
David Wilson 2a8567b432 core: serialize calls to _service_stub_main().
See comment.
5 years ago
David Wilson 1f77d24bec Update copyright year everywhere. 5 years ago
David Wilson 7ff4e6694c issue #536: rework how 2.3-compatible simplejson is served
Regardless of the version of simplejson loaded in the master, load up
the ModuleResponder cache with our 2.4-compatible version.

To cope with simplejson being loaded due to modules like ec2_group that
try to import it before importing 'json', also update target.py to
remove it from the whitelist if a local 'json' module import succeeds.
5 years ago
David Wilson 78ec634dab issue #481: core: preserve stderr TTY FD if one is present.
Since 802de6a8d5, sudo on CentOS 5 had
begun failing due to a TTY FD leak in the parent process being fixed.

The old versions of sudo doesn't hang around after starting a child --
they exec the privilege-escalated child process on top of themselves,
meaning no spare copy of the TTY FD is kept alive by sudo.

When the child starts up, it replaces stdio with IoLoggers, including
the inherited stderr FD connected to DiagLogStream/the slave PTY. When
the last process closes a slave PTY, the kernel sends SIGHUP to any
processes still having it as the controlling TTY.

Therefore we must either ignore SIGHUP until the first stage has been
waited on (since the first stage also preserve the FD), or dup the
inherited TTY FD and keep it around forever.

Wasting one FD seems less annoying than modifying process signals for
all potential library users, so that is the approach taken here.
5 years ago
David Wilson 5ae7464011 core: cProfile is not available in 2.4. 5 years ago
David Wilson 0e193c223c issue #508: master: minify all Mitogen/ansible_mitogen sources.
Minify-safe files are marked with a magical "# !mitogen: minify_safe"
comment anywhere in the file, which activates the minifier. The result
is naturally cached by ModuleResponder, therefore lru_cache is gone too.

Given:

    import os, mitogen
    @mitogen.main()
    def main(router):
        c = router.ssh(hostname='k3')
        c.call(os.getpid)
        router.sudo(via=c)

SSH footprint drops from 56.2 KiB to 42.75 KiB (-23.9%)
Ansible "shell: hostname" drops 149.26 KiB to 117.42 KiB (-21.3%)
5 years ago
David Wilson 960392cf50 core: tidy up existing profiling code and support MITOGEN_PROFILE_FMT 5 years ago
David Wilson 3606580f05 issue #260: redundant if statement. 5 years ago
David Wilson 696cee57dd issue #260: hide force-disconnect messages.
Parent is always force-disconnected, and now it shows up quite visibly
on every exit.
5 years ago
David Wilson 26c6c6d048 issue #498: fix shutdown crash
Traceback (most recent call last):
      File "<stdin>", line 2707, in _invoke
      File "<stdin>", line 2480, in _on_del_route
    NameError: global name 'target_id' is not defined
5 years ago
David Wilson a18a083c94 issue #260: avoid start_transmit()/on_transmit()/stop_transmit()
Previous transmit sequence was:
        Router._async_route -> Stream._send -> Broker._start_transmit ->
        Broker.loop -> Stream.on_transmit -> socket.write ->
        Broker.stop_transmit

New sequence, when socket buffer can hold message is:
        Router._async_route -> Stream._send -> socket.write

bench/roundtrip.py
        Before: 240 usec
        after: 178 usec

Stat before:
       5088.276050      task-clock (msec)         #    0.997 CPUs utilized
           185,568      context-switches          #    0.036 M/sec
                 0      cpu-migrations            #    0.000 K/sec
            18,923      page-faults               #    0.004 M/sec
    13,063,871,501      cycles                    #    2.567 GHz
    12,834,579,684      instructions              #    0.98  insn per cycle
     2,669,820,684      branches                  #  524.700 M/sec
       107,296,033      branch-misses             #    4.02% of all branches

       5.105018296 seconds time elapsed

       2.350970000 seconds user
       0.345497000 seconds sys

Stat after:
       4019.208047      task-clock (msec)         #    0.998 CPUs utilized
           249,471      context-switches          #    0.062 M/sec
                 0      cpu-migrations            #    0.000 K/sec
            20,990      page-faults               #    0.005 M/sec
    10,312,535,979      cycles                    #    2.566 GHz
    11,586,365,995      instructions              #    1.12  insn per cycle
     2,392,933,370      branches                  #  595.374 M/sec
        75,432,205      branch-misses             #    3.15% of all branches

       4.028763347 seconds time elapsed

       3.367051000 seconds user
       0.652962000 seconds sys
5 years ago
David Wilson d4a0b70e15 core: ensure broker profiling output reaches disk
Profiler hasn't been used much since the hard exit was added.
5 years ago
David Wilson 0c0d34241b core: Latch._wake improvements
os.write() can fail with EINTR due to signals, so wrap it in
io_op(). Closes #483.

Masking EBADF looks like it is/was almost certainly papering over a bug,
remove it and suffer the bug reports. Closes #495.
5 years ago
David Wilson e2478dcb9f issue #498: wrap Router dict mutations in a lock 5 years ago
David Wilson ec789513dc ssh: tidy up logs and stream names. 5 years ago
David Wilson 16a2de65c4 issue #493: another Py3.x fix. 5 years ago