[pypy-commit] pypy reverse-debugger: Remove the runtime part, move it to http://bitbucket.org/pypy/revdb/
arigo
pypy.commits at gmail.com
Thu Sep 8 16:37:36 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r86966:9f8dd66da2a9
Date: 2016-09-08 18:01 +0200
http://bitbucket.org/pypy/pypy/changeset/9f8dd66da2a9/
Log: Remove the runtime part, move it to http://bitbucket.org/pypy/revdb/
diff --git a/rpython/translator/revdb/ancillary.py b/rpython/translator/revdb/ancillary.py
deleted file mode 100644
--- a/rpython/translator/revdb/ancillary.py
+++ /dev/null
@@ -1,57 +0,0 @@
-import py
-import os, sys
-
-
-def build(tmpdir):
- import cffi
- ffibuilder = cffi.FFI()
-
- ffibuilder.cdef("""
- int ancil_send_fds(int, const int *, unsigned);
- int ancil_recv_fds(int, int *, unsigned);
- """)
-
- local_dir = os.path.dirname(os.path.abspath(__file__))
- src_dir = os.path.join(local_dir, 'src-revdb')
-
- ffibuilder.set_source("_ancillary_cffi", """
- #include <ancillary.h>
- """, include_dirs=[src_dir],
- sources=[os.path.join(src_dir, 'fd_send.c'),
- os.path.join(src_dir, 'fd_recv.c')])
-
- ffibuilder.compile(tmpdir=tmpdir, verbose=True)
-
-def import_(verbose=False):
- import rpython
- basedir = py.path.local(rpython.__file__).dirpath()
- tmpdir = str(basedir.ensure('_cache', 'ancillary', dir=1))
- if verbose:
- print tmpdir
- old_sys_path = sys.path[:]
- sys.path.insert(0, tmpdir)
- try:
- import _ancillary_cffi
- except ImportError:
- build(tmpdir)
- import _ancillary_cffi
- sys.path[:] = old_sys_path
- return _ancillary_cffi.ffi, _ancillary_cffi.lib
-
-
-def send_fds(pipe_num, fd_list):
- ffi, lib = import_()
- if lib.ancil_send_fds(pipe_num, fd_list, len(fd_list)) < 0:
- raise OSError(ffi.errno, "ancil_send_fds() failed")
-
-def recv_fds(pipe_num, fd_count):
- ffi, lib = import_()
- p = ffi.new("int[]", fd_count)
- result = lib.ancil_recv_fds(pipe_num, p, fd_count)
- if result < 0:
- raise OSError(ffi.errno, "ancil_recv_fds() failed")
- return [p[i] for i in xrange(result)]
-
-
-if __name__ == '__main__':
- import_(verbose=True)
diff --git a/rpython/translator/revdb/interact.py b/rpython/translator/revdb/interact.py
deleted file mode 100644
--- a/rpython/translator/revdb/interact.py
+++ /dev/null
@@ -1,492 +0,0 @@
-import sys, os, re
-import subprocess, socket
-import traceback, linecache
-from contextlib import contextmanager
-try:
- import readline
-except ImportError:
- pass
-
-from rpython.translator.revdb.process import ReplayProcessGroup
-from rpython.translator.revdb.process import Breakpoint
-
-r_cmdline = re.compile(r"([a-zA-Z0-9_]\S*|.)\s*(.*)")
-r_dollar_num = re.compile(r"\$(\d+)\b")
-
-
-class RevDebugControl(object):
-
- def __init__(self, revdb_log_filename, executable=None,
- pygments_background=None):
- with open(revdb_log_filename, 'rb') as f:
- header = f.readline()
- assert header.endswith('\n')
- fields = header[:-1].split('\t')
- if len(fields) < 2 or fields[0] != 'RevDB:':
- raise ValueError("file %r is not a RevDB log" % (
- revdb_log_filename,))
- if executable is None:
- executable = fields[1]
- if not os.path.isfile(executable):
- raise ValueError("executable %r not found" % (executable,))
- linecacheoutput = self.getlinecacheoutput(pygments_background)
- self.pgroup = ReplayProcessGroup(executable, revdb_log_filename,
- linecacheoutput)
- self.print_extra_pending_info = None
-
- def interact(self):
- self.last_command = 'help'
- self.previous_time = None
- self.previous_thread = 0
- while True:
- prompt = self.print_lines_before_prompt()
- try:
- while True:
- cmdline = self.display_prompt(prompt)
- self.run_command(cmdline)
- prompt = self.print_lines_before_prompt()
- except KeyboardInterrupt:
- rtime = self.previous_time or 1
- print
- print 'KeyboardInterrupt: restoring state at time %d...' % (
- rtime,)
- self.pgroup.recreate_subprocess(rtime)
- print "(type 'q' or Ctrl-D to quit)"
- self.last_command = ''
- self.previous_thread = '?'
- self.previous_time = '?'
-
- def print_lines_before_prompt(self):
- last_time = self.pgroup.get_current_time()
- if last_time != self.previous_time:
- print
- if self.pgroup.get_current_thread() != self.previous_thread:
- self.previous_thread = self.pgroup.get_current_thread()
- if self.previous_thread == 0:
- print ('-------------------- in main thread #0 '
- '--------------------')
- else:
- print ('-------------------- in non-main thread '
- '#%d --------------------' % (self.previous_thread,))
- self.pgroup.update_watch_values()
- last_time = self.pgroup.get_current_time()
- if self.print_extra_pending_info:
- print self.print_extra_pending_info
- self.print_extra_pending_info = None
- if last_time != self.previous_time:
- self.pgroup.show_backtrace(complete=0)
- self.previous_time = last_time
- prompt = '(%d)$ ' % last_time
- return prompt
-
- def display_prompt(self, prompt):
- try:
- cmdline = raw_input(prompt).strip()
- except EOFError:
- print
- cmdline = 'quit'
- if not cmdline:
- cmdline = self.last_command
- return cmdline
-
- def run_command(self, cmdline):
- match = r_cmdline.match(cmdline)
- if not match:
- return
- self.last_command = cmdline
- command, argument = match.groups()
- try:
- runner = getattr(self, 'command_' + command)
- except AttributeError:
- print >> sys.stderr, "no command '%s', try 'help'" % (command,)
- else:
- try:
- runner(argument)
- except KeyboardInterrupt:
- raise
- except Exception as e:
- traceback.print_exc()
- print >> sys.stderr
- print >> sys.stderr, 'Something went wrong. You are now',
- print >> sys.stderr, 'in a pdb; press Ctrl-D to continue.'
- import pdb; pdb.post_mortem(sys.exc_info()[2])
- print >> sys.stderr
- print >> sys.stderr, 'You are back running %s.' % (
- sys.argv[0],)
-
- def command_help(self, argument):
- """Display commands summary"""
- print 'Available commands:'
- lst = dir(self)
- commands = [(name[len('command_'):], getattr(self, name))
- for name in lst
- if name.startswith('command_')]
- seen = {}
- for name, func in commands:
- seen.setdefault(func, []).append(name)
- for _, func in commands:
- if func in seen:
- names = seen.pop(func)
- names.sort(key=len, reverse=True)
- docstring = func.__doc__ or 'undocumented'
- print '\t%-16s %s' % (', '.join(names), docstring)
-
- def command_quit(self, argument):
- """Exit the debugger"""
- self.pgroup.close()
- sys.exit(0)
- command_q = command_quit
-
- def command_go(self, argument):
- """Jump to time ARG"""
- arg = int(argument or self.pgroup.get_current_time())
- self.pgroup.jump_in_time(arg)
-
- def command_info(self, argument):
- """Display various info ('info help' for more)"""
- display = getattr(self, 'cmd_info_' + argument, self.cmd_info_help)
- return display()
-
- def cmd_info_help(self):
- """Display info topics summary"""
- print 'Available info topics:'
- for name in dir(self):
- if name.startswith('cmd_info_'):
- command = name[len('cmd_info_'):]
- docstring = getattr(self, name).__doc__ or 'undocumented'
- print '\tinfo %-12s %s' % (command, docstring)
-
- def cmd_info_paused(self):
- """List current paused subprocesses"""
- lst = [str(n) for n in sorted(self.pgroup.paused)]
- print ', '.join(lst)
-
- def _bp_kind(self, num):
- break_at = self.pgroup.all_breakpoints.num2break.get(num, '??')
- if break_at[0] == 'B':
- kind = 'breakpoint'
- name = break_at[4:]
- elif break_at[0] == 'W':
- kind = 'watchpoint'
- name = self.pgroup.all_breakpoints.sources.get(num, '??')
- elif num == -3:
- kind = 'stoppoint'
- name = 'explicit stop'
- elif num == -4:
- kind = 'switchpoint'
- name = 'thread switch'
- else:
- kind = '?????point'
- name = repr(break_at)
- return kind, name
-
- def _bp_new(self, source_expr, break_code, break_at, nids=None):
- b = self.pgroup.edit_breakpoints()
- new = 1
- while new in b.num2break:
- new += 1
- b.set_num2break(new, break_code, break_at)
- b.sources[new] = source_expr
- if break_code == 'W':
- b.watchvalues[new] = ''
- if nids:
- b.watchuids[new] = self.pgroup.nids_to_uids(nids)
- return new
-
- def cmd_info_breakpoints(self):
- """List current breakpoints and watchpoints"""
- lst = self.pgroup.all_breakpoints.num2break.keys()
- if lst:
- for num in sorted(lst):
- kind, name = self._bp_kind(num)
- print '\t%s %d: %s' % (kind, num, name)
- else:
- print 'no breakpoints/watchpoints.'
- cmd_info_watchpoints = cmd_info_breakpoints
-
- def move_forward(self, steps):
- self.remove_tainting()
- try:
- self.pgroup.go_forward(steps)
- return None
- except Breakpoint as b:
- self.hit_breakpoints(b)
- return b
-
- def move_backward(self, steps):
- try:
- self.pgroup.go_backward(steps)
- return None
- except Breakpoint as b:
- self.hit_breakpoints(b, backward=True)
- return b
-
- def hit_breakpoints(self, b, backward=False):
- printing = []
- for num in b.regular_breakpoint_nums():
- kind, name = self._bp_kind(num)
- printing.append('%s %s%s: %s' % (
- 'Reverse-hit' if backward else 'Hit',
- kind,
- '' if kind == 'stoppoint' else ' %d' % (num,),
- name))
- self.print_extra_pending_info = '\n'.join(printing)
- if self.pgroup.get_current_time() != b.time:
- target_time = b.time
- if backward and any(self._bp_kind(num)[0] == 'watchpoint'
- for num in b.regular_breakpoint_nums()):
- target_time += 1
- self.pgroup.jump_in_time(target_time)
-
- def remove_tainting(self):
- if self.pgroup.is_tainted():
- self.pgroup.jump_in_time(self.pgroup.get_current_time())
- assert not self.pgroup.is_tainted()
-
- def command_step(self, argument):
- """Run forward ARG steps (default 1)"""
- arg = int(argument or '1')
- self.move_forward(arg)
- command_s = command_step
-
- def command_bstep(self, argument):
- """Run backward ARG steps (default 1)"""
- arg = int(argument or '1')
- self.move_backward(arg)
- command_bs = command_bstep
-
- @contextmanager
- def _stack_id_break(self, stack_id):
- # add temporarily a breakpoint that hits when we enter/leave
- # a frame from/to the frame identified by 'stack_id'
- b = self.pgroup.edit_breakpoints()
- b.stack_id = stack_id
- try:
- yield
- finally:
- b.stack_id = 0
-
- @contextmanager
- def _thread_num_break(self, thread_num):
- # add temporarily a breakpoint that hits when we enter/leave
- # the given thread
- b = self.pgroup.edit_breakpoints()
- b.thread_num = thread_num
- try:
- yield
- finally:
- b.thread_num = -1
-
- def command_next(self, argument):
- """Run forward for one step, skipping calls"""
- while True:
- stack_id = self.pgroup.get_stack_id(is_parent=False)
- with self._stack_id_break(stack_id):
- b = self.move_forward(1)
- while b is not None:
- # if we hit a regular breakpoint, stop
- if any(b.regular_breakpoint_nums()):
- return
- # we hit only calls and returns inside stack_id. If the
- # last one of these is a "return", then we're now back inside
- # stack_id, so stop
- if b.nums[-1] == -2:
- break
- # else, the last one is a "call", so we entered another frame.
- # Continue running until the next call/return event occurs
- # inside stack_id
- with self._stack_id_break(stack_id):
- b = self.move_forward(self.pgroup.get_max_time() -
- self.pgroup.get_current_time())
- # and then look at that 'b' again (closes the loop)
-
- # we might be at a "<<" position on the same line as before,
- # which returns a get_hiddenpos_level() value of 1. Continue
- # until we reach a get_hiddenpos_level() value of 0.
- if b is None or self.pgroup.get_hiddenpos_level() == 0:
- break
- command_n = command_next
-
- def command_bnext(self, argument):
- """Run backward for one step, skipping calls"""
- while True:
- stack_id = self.pgroup.get_stack_id(is_parent=False)
- with self._stack_id_break(stack_id):
- b = self.move_backward(1)
- while b is not None:
- # if we hit a regular breakpoint, stop
- if any(b.regular_breakpoint_nums()):
- return
- # we hit only calls and returns inside stack_id. If the
- # first one of these is a "call", then we're now back inside
- # stack_id, so stop
- if b.nums[0] == -1:
- break
- # else, the first one is a "return", so before, we were
- # inside a different frame. Continue running until the next
- # call/return event occurs inside stack_id
- with self._stack_id_break(stack_id):
- b = self.move_backward(self.pgroup.get_current_time() - 1)
- # and then look at that 'b' again (closes the loop)
-
- # we might be at a "<<" position on the same line as before,
- # which returns a get_hiddenpos_level() value of 1. Continue
- # until we reach a get_hiddenpos_level() value of 0.
- if self.pgroup.get_hiddenpos_level() == 0:
- break
- command_bn = command_bnext
-
- def command_finish(self, argument):
- """Run forward until the current function finishes"""
- stack_id = self.pgroup.get_stack_id(is_parent=True)
- if stack_id == 0:
- print 'No caller.'
- else:
- with self._stack_id_break(stack_id):
- self.command_continue('')
-
- def command_bfinish(self, argument):
- """Run backward until the current function is called"""
- stack_id = self.pgroup.get_stack_id(is_parent=True)
- if stack_id == 0:
- print 'No caller.'
- else:
- with self._stack_id_break(stack_id):
- self.command_bcontinue('')
-
- def command_continue(self, argument):
- """Run forward"""
- self.move_forward(self.pgroup.get_max_time() -
- self.pgroup.get_current_time())
- command_c = command_continue
-
- def command_bcontinue(self, argument):
- """Run backward"""
- self.move_backward(self.pgroup.get_current_time() - 1)
- command_bc = command_bcontinue
-
- def _cmd_thread(self, argument, cmd_continue):
- argument = argument.lstrip('#')
- if argument:
- arg = int(argument)
- if arg == self.pgroup.get_current_thread():
- print 'Thread #%d is already the current one.' % (arg,)
- return
- else:
- # use the current thread number to detect switches to any
- # other thread (this works because revdb.c issues a
- # breakpoint whenever there is a switch FROM or TO the
- # thread '#arg').
- arg = self.pgroup.get_current_thread()
- #
- with self._thread_num_break(arg):
- cmd_continue('')
-
- def command_nthread(self, argument):
- """Run forward until thread switch (optionally to #ARG)"""
- self._cmd_thread(argument, self.command_continue)
-
- def command_bthread(self, argument):
- """Run backward until thread switch (optionally to #ARG)"""
- self._cmd_thread(argument, self.command_bcontinue)
-
- def command_print(self, argument):
- """Print an expression or execute a line of code"""
- # locate which $NUM appear used in the expression
- nids = map(int, r_dollar_num.findall(argument))
- self.pgroup.print_cmd(argument, nids=nids)
- command_p = command_print
- locals()['command_!'] = command_print
-
- def command_backtrace(self, argument):
- """Show the backtrace"""
- self.pgroup.show_backtrace(complete=1)
- command_bt = command_backtrace
-
- def command_list(self, argument):
- """Show the current function"""
- self.pgroup.show_backtrace(complete=2)
-
- def command_locals(self, argument):
- """Show the locals"""
- self.pgroup.show_locals()
-
- def command_break(self, argument):
- """Add a breakpoint"""
- if not argument:
- print "Break where?"
- return
- num = self._bp_new(argument, 'B', argument)
- self.pgroup.update_breakpoints()
- b = self.pgroup.edit_breakpoints()
- if num not in b.num2break:
- print "Breakpoint not added"
- else:
- kind, name = self._bp_kind(num)
- print "Breakpoint %d added: %s" % (num, name)
- command_b = command_break
-
- def command_delete(self, argument):
- """Delete a breakpoint/watchpoint"""
- b = self.pgroup.edit_breakpoints()
- try:
- arg = int(argument)
- except ValueError:
- for arg in b.num2break:
- if self._bp_kind(arg)[1] == argument:
- break
- else:
- print "No such breakpoint/watchpoint: %s" % (argument,)
- return
- if arg not in b.num2break:
- print "No breakpoint/watchpoint number %d" % (arg,)
- else:
- kind, name = self._bp_kind(arg)
- b.num2break.pop(arg, '')
- b.sources.pop(arg, '')
- b.watchvalues.pop(arg, '')
- b.watchuids.pop(arg, '')
- print "%s %d deleted: %s" % (kind.capitalize(), arg, name)
- command_del = command_delete
-
- def command_watch(self, argument):
- """Add a watchpoint (use $NUM in the expression to watch)"""
- if not argument:
- print "Watch what?"
- return
- #
- ok_flag, compiled_code = self.pgroup.compile_watchpoint_expr(argument)
- if not ok_flag:
- print compiled_code # the error message
- print 'Watchpoint not added'
- return
- #
- nids = map(int, r_dollar_num.findall(argument))
- ok_flag, text = self.pgroup.check_watchpoint_expr(compiled_code, nids)
- if not ok_flag:
- print text
- print 'Watchpoint not added'
- return
- #
- new = self._bp_new(argument, 'W', compiled_code, nids=nids)
- self.pgroup.update_watch_values()
- print "Watchpoint %d added" % (new,)
-
- def getlinecacheoutput(self, pygments_background):
- if not pygments_background or pygments_background == 'off':
- return
- try:
- from pygments import highlight
- from pygments.lexers import PythonLexer
- from pygments.formatters import TerminalFormatter
- except ImportError as e:
- print >> sys.stderr, 'ImportError: %s' % (e,)
- return None
- #
- lexer = PythonLexer()
- fmt = TerminalFormatter(bg=pygments_background)
- #
- def linecacheoutput(filename, lineno):
- line = linecache.getline(filename, lineno)
- return highlight(line, lexer, fmt)
- return linecacheoutput
diff --git a/rpython/translator/revdb/message.py b/rpython/translator/revdb/message.py
deleted file mode 100644
--- a/rpython/translator/revdb/message.py
+++ /dev/null
@@ -1,120 +0,0 @@
-
-INIT_VERSION_NUMBER = 0xd80100
-
-
-# See the corresponding answers for details about messages.
-
-CMD_FORK = -1 # Message(CMD_FORK)
-CMD_QUIT = -2 # Message(CMD_QUIT)
-CMD_FORWARD = -3 # Message(CMD_FORWARD, steps, breakpoint_mode)
-CMD_FUTUREIDS = -4 # Message(CMD_FUTUREIDS, extra=list-of-8bytes-uids)
-CMD_PING = -5 # Message(CMD_PING)
-# extra commands which are not handled by revdb.c, but
-# by revdb.register_debug_command()
-CMD_PRINT = 1 # Message(CMD_PRINT, extra=expression)
-CMD_BACKTRACE = 2 # Message(CMD_BACKTRACE)
-CMD_LOCALS = 3 # Message(CMD_LOCALS)
-CMD_BREAKPOINTS = 4 # Message(CMD_BREAKPOINTS, stack_id,
- # extra="\0-separated names")
-CMD_STACKID = 5 # Message(CMD_STACKID, parent-flag)
-CMD_ATTACHID = 6 # Message(CMD_ATTACHID, small-num, unique-id)
-CMD_COMPILEWATCH= 7 # Message(CMD_COMPILEWATCH, extra=expression)
-CMD_CHECKWATCH = 8 # Message(CMD_CHECKWATCH, extra=compiled_code)
-CMD_WATCHVALUES = 9 # Message(CMD_WATCHVALUES, extra=texts)
-
-
-# the first message sent by the first child:
-# Message(ANSWER_INIT, INIT_VERSION_NUMBER, total_stop_points)
-ANSWER_INIT = -20
-
-# sent when the child is done and waiting for the next command:
-# Message(ANSWER_READY, current_time, currently_created_objects)
-ANSWER_READY = -21
-
-# sent after CMD_FORK:
-# Message(ANSWER_FORKED, child_pid)
-ANSWER_FORKED = -22
-
-# sent when a child reaches the end (should not occur with process.py)
-# Message(ANSWER_AT_END) (the child exits afterwards)
-ANSWER_AT_END = -23
-
-# breakpoint detected in CMD_FORWARD:
-# Message(ANSWER_BREAKPOINT, break_time, break_created_objects, bpkt_num)
-# if breakpoint_mode=='b': sent immediately when seeing a breakpoint,
-# followed by ANSWER_STD with the same time
-# if breakpoint_mode=='r': sent when we're done going forward, about
-# the most recently seen breakpoint
-# if breakpoint_mode=='i': ignored, never sent
-ANSWER_BREAKPOINT = -24
-
-# sent after an Attempted to do I/O or access raw memory, as the last message
-ANSWER_ATTEMPT_IO = -25
-
-
-# print one line of a file to the console, for CMD_PRINT
-# Message(ANSWER_LINECACHE, linenum, extra=filename)
-ANSWER_LINECACHE = 19
-
-# print text to the console, for CMD_PRINT and others
-# Message(ANSWER_TEXT, extra=text)
-ANSWER_TEXT = 20
-
-# CMD_STACKID returns the id of the current or parent frame (depending
-# on the 'parent-flag' passed in), or 0 if not found. The id can be just
-# the stack depth, or it can be the unique id of the frame object. When
-# used in CMD_BREAKPOINTS, it means "break if we are entering/leaving a
-# frame from/to the given frame".
-# Message(ANSWER_STACKID, stack-id)
-ANSWER_STACKID = 21
-
-# sent from CMD_PRINT to record the existence of a recallable object
-# Message(ANSWER_NEXTNID, unique-id)
-ANSWER_NEXTNID = 22
-
-# sent after CMD_COMPILEWATCH:
-# Message(ANSWER_WATCH, ok_flag, extra=marshalled_code)
-# sent after CMD_CHECKWATCH:
-# Message(ANSWER_WATCH, ok_flag, extra=result_of_expr)
-ANSWER_WATCH = 23
-
-# sent sometimes after CMD_BREAKPOINTS:
-# Message(ANSWER_CHBKPT, bkpt_num, extra=new_breakpoint_text)
-ANSWER_CHBKPT = 24
-
-
-# ____________________________________________________________
-
-
-class Message(object):
- """Represent messages sent and received to subprocesses
- started with --revdb-replay.
- """
-
- def __init__(self, cmd, arg1=0, arg2=0, arg3=0, extra=""):
- self.cmd = cmd
- self.arg1 = arg1
- self.arg2 = arg2
- self.arg3 = arg3
- self.extra = extra
-
- def __repr__(self):
- cmd = self.cmd
- for key, value in globals().items():
- if (key.startswith('CMD_') or key.startswith('ANSWER_')) and (
- value == cmd):
- cmd = key
- break
- return 'Message(%s, %d, %d, %d, %r)' % (cmd, self.arg1,
- self.arg2, self.arg3,
- self.extra)
-
- def __eq__(self, other):
- return (self.cmd == other.cmd and
- self.arg1 == other.arg1 and
- self.arg2 == other.arg2 and
- self.arg3 == other.arg3 and
- self.extra == other.extra)
-
- def __ne__(self, other):
- return not (self == other)
diff --git a/rpython/translator/revdb/process.py b/rpython/translator/revdb/process.py
deleted file mode 100644
--- a/rpython/translator/revdb/process.py
+++ /dev/null
@@ -1,637 +0,0 @@
-import sys, os, struct, socket, errno, subprocess
-import linecache
-from rpython.translator.revdb import ancillary
-from rpython.translator.revdb.message import *
-
-
-class Breakpoint(Exception):
- def __init__(self, time):
- self.time = time # time of the previous stop_point
- self.nums = [] # list of breakpoint numbers that occurred, in order
-
- def record_num(self, num):
- self.nums.append(num)
-
- def regular_breakpoint_nums(self):
- for num in self.nums:
- if num != -1 and num != -2:
- yield num
-
- def __repr__(self):
- return 'Breakpoint(%d, %r)' % (self.time, self.nums)
- __str__ = __repr__
-
-
-class AllBreakpoints(object):
-
- def __init__(self):
- self.num2break = {} # {small number: encoded break/watchpoint}
- self.sources = {} # {small number: src text}
- self.watchvalues = {} # {small number: resulting text}
- self.watchuids = {} # {small number: [uid...]}
- self.stack_id = 0 # breaks when leaving/entering a frame from/to
- # the frame identified by 'stack_id'
- self.thread_num = -1 # breaks when leaving/entering the thread_num
-
- def __repr__(self):
- return 'AllBreakpoints(%r, %r, %r, %r, %r)' % (
- self.num2break, self.watchvalues, self.watchuids,
- self.stack_id, self.thread_num)
-
- def compare(self, other):
- if (self.num2break == other.num2break and
- self.stack_id == other.stack_id and
- self.thread_num == other.thread_num):
- if self.watchvalues == other.watchvalues:
- return 2 # completely equal
- else:
- return 1 # equal, but watchvalues out-of-date
- else:
- return 0 # different
-
- def is_empty(self):
- return (len(self.num2break) == 0 and self.stack_id == 0
- and self.thread_num == -1)
-
- def duplicate(self):
- a = AllBreakpoints()
- a.num2break.update(self.num2break)
- a.stack_id = self.stack_id
- a.thread_num = self.thread_num
- return a
-
- def set_num2break(self, new, break_code, break_at):
- if len(break_at) > 0xFFFFFF:
- raise OverflowError("break/watchpoint too complex")
- self.num2break[new] = (break_code +
- chr(len(break_at) & 0xFF) +
- chr((len(break_at) >> 8) & 0xFF) +
- chr(len(break_at) >> 16) +
- break_at)
-
-
-class RecreateSubprocess(Exception):
- pass
-
-
-class ReplayProcess(object):
- """Represent one replaying subprocess.
-
- It can be either the one started with --revdb-replay, or a fork.
- """
-
- def __init__(self, pid, control_socket,
- breakpoints_cache=AllBreakpoints(),
- printed_objects=frozenset(),
- linecacheoutput=None):
- self.pid = pid
- self.control_socket = control_socket
- self.tainted = False
- self.breakpoints_cache = breakpoints_cache # don't mutate this
- self.printed_objects = printed_objects # don't mutate this
- # ^^^ frozenset containing the uids of the objects that are
- # either already discovered in this child
- # (if uid < currently_created_objects), or that will
- # automatically be discovered when we move forward
- self.linecacheoutput = linecacheoutput or linecache.getline
-
- def _recv_all(self, size):
- pieces = []
- while size > 0:
- data = self.control_socket.recv(size)
- if not data:
- raise EOFError
- size -= len(data)
- pieces.append(data)
- return ''.join(pieces)
-
- def send(self, msg):
- #print 'SENT:', self.pid, msg
- binary = struct.pack("iIqqq", msg.cmd, len(msg.extra),
- msg.arg1, msg.arg2, msg.arg3)
- self.control_socket.sendall(binary + msg.extra)
-
- def recv(self):
- binary = self._recv_all(struct.calcsize("iIqqq"))
- cmd, size, arg1, arg2, arg3 = struct.unpack("iIqqq", binary)
- extra = self._recv_all(size)
- msg = Message(cmd, arg1, arg2, arg3, extra)
- #print 'RECV:', self.pid, msg
- return msg
-
- def expect(self, cmd, arg1=0, arg2=0, arg3=0, extra=""):
- msg = self.recv()
- assert msg.cmd == cmd, msg
- if arg1 is not Ellipsis:
- assert msg.arg1 == arg1, msg
- if arg2 is not Ellipsis:
- assert msg.arg2 == arg2, msg
- if arg3 is not Ellipsis:
- assert msg.arg3 == arg3, msg
- if extra is not Ellipsis:
- assert msg.extra == extra, msg
- return msg
-
- def expect_ready(self):
- msg = self.expect(ANSWER_READY, Ellipsis, Ellipsis, Ellipsis)
- self.update_times(msg)
-
- def update_times(self, msg):
- self.current_time = msg.arg1
- self.currently_created_objects = msg.arg2
- self.current_thread = msg.arg3
-
- def clone(self, activate=False):
- """Fork this subprocess. Returns a new ReplayProcess() that is
- an identical copy.
- """
- self.send(Message(CMD_FORK, int(activate)))
- s1, s2 = socket.socketpair()
- ancillary.send_fds(self.control_socket.fileno(), [s2.fileno()])
- s2.close()
- msg = self.expect(ANSWER_FORKED, Ellipsis)
- child_pid = msg.arg1
- self.expect_ready()
- other = ReplayProcess(child_pid, s1,
- breakpoints_cache=self.breakpoints_cache,
- printed_objects=self.printed_objects,
- linecacheoutput=self.linecacheoutput)
- other.expect_ready()
- #print >> sys.stderr, 'CLONED', self.current_time
- return other
-
- def close(self):
- """Close this subprocess."""
- try:
- self.send(Message(CMD_QUIT))
- except socket.error:
- pass
-
- def forward(self, steps, breakpoint_mode):
- """Move this subprocess forward in time.
- Returns the Breakpoint or None.
- """
- assert not self.tainted
-
- # <DEBUGGING ONLY>
- currents = self.current_time, self.currently_created_objects
- self.send(Message(CMD_PING))
- self.expect_ready()
- assert currents == (self.current_time, self.currently_created_objects)
- # </DEBUGGING ONLY>
-
- self.send(Message(CMD_FORWARD, steps, ord(breakpoint_mode)))
- #
- # record all breakpoints that occur together during the *last* step
- bkpt = None
- while True:
- msg = self.recv()
- if msg.cmd != ANSWER_BREAKPOINT:
- break
- if bkpt is None or bkpt.time != msg.arg1:
- bkpt = Breakpoint(msg.arg1)
- bkpt.record_num(msg.arg3)
- assert msg.cmd == ANSWER_READY, msg
- self.update_times(msg)
- return bkpt
-
- def print_text_answer(self, pgroup=None):
- while True:
- msg = self.recv()
- if msg.cmd == ANSWER_TEXT:
- sys.stdout.write(msg.extra)
- sys.stdout.flush()
- elif msg.cmd == ANSWER_READY:
- self.update_times(msg)
- break
- elif msg.cmd == ANSWER_LINECACHE:
- line = self.linecacheoutput(msg.extra, msg.arg1)
- if line == '':
- line = '?'
- if msg.arg2: # strip?
- line = line.strip()
- else:
- line = line.rstrip('\r\n')
- sys.stdout.write(line + '\n')
- sys.stdout.flush()
- elif msg.cmd == ANSWER_NEXTNID and pgroup is not None:
- uid = msg.arg1
- if uid < pgroup.initial_uid:
- continue # created before the first stop point, ignore
- self.printed_objects = self.printed_objects.union([uid])
- new_nid = len(pgroup.all_printed_objects_lst)
- nid = pgroup.all_printed_objects.setdefault(uid, new_nid)
- if nid == new_nid:
- pgroup.all_printed_objects_lst.append(uid)
- sys.stdout.write('$%d = ' % nid)
- sys.stdout.flush()
- elif msg.cmd == ANSWER_ATTEMPT_IO:
- raise RecreateSubprocess
- elif msg.cmd == ANSWER_CHBKPT and pgroup is not None:
- # change the breakpoint definition. Needed for
- # ":linenum" breakpoints which must be expanded to the
- # current file only once
- b = pgroup.edit_breakpoints()
- assert b.num2break[msg.arg1][0] == 'B'
- if msg.extra:
- b.set_num2break(msg.arg1, 'B', msg.extra)
- else:
- del b.num2break[msg.arg1]
- else:
- print >> sys.stderr, "unexpected %r" % (msg,)
-
-
-class ReplayProcessGroup(object):
- """Handle a family of subprocesses.
- """
- MAX_SUBPROCESSES = 31 # maximum number of subprocesses
- STEP_RATIO = 0.25 # subprocess n is between subprocess n-1
- # and the end, at this fraction of interval
-
- def __init__(self, executable, revdb_log_filename, linecacheoutput=None):
- s1, s2 = socket.socketpair()
- initial_subproc = subprocess.Popen(
- [executable, '--revdb-replay', revdb_log_filename,
- str(s2.fileno())], preexec_fn=s1.close)
- s2.close()
- child = ReplayProcess(initial_subproc.pid, s1,
- linecacheoutput=linecacheoutput)
- msg = child.expect(ANSWER_INIT, INIT_VERSION_NUMBER, Ellipsis)
- self.total_stop_points = msg.arg2
- if self.total_stop_points == 0:
- raise ValueError("%r does not contain any stop point" %
- (revdb_log_filename,))
- child.expect_ready()
- self.initial_uid = child.currently_created_objects
-
- self.active = child
- self.paused = {1: child.clone()} # {time: subprocess}
- self.all_breakpoints = AllBreakpoints()
- self.all_printed_objects = {}
- self.all_printed_objects_lst = []
-
- def get_current_time(self):
- return self.active.current_time
-
- def get_currently_created_objects(self):
- return self.active.currently_created_objects
-
- def get_current_thread(self):
- return self.active.current_thread
-
- def _check_current_time(self, time):
- assert self.get_current_time() == time
- self.active.send(Message(CMD_FORWARD, 0))
- return self.active.expect(ANSWER_READY, time, Ellipsis, Ellipsis)
-
- def get_max_time(self):
- return self.total_stop_points
-
- def get_next_clone_time(self):
- # if 'active' has more printed_objects than the next process
- # already in 'paused', then we re-clone 'active'.
- cur_time = self.get_current_time()
- future = [time for time in self.paused if time > cur_time]
- if future:
- for futime in sorted(future):
- if (self.paused[futime].printed_objects !=
- frozenset(self.all_printed_objects_lst)):
- # 'futime' is the time of the first "future" childs
- # with an incomplete 'printed_objects'. This will
- # be re-cloned.
- return futime
- #
- if len(self.paused) >= self.MAX_SUBPROCESSES:
- next_time = self.total_stop_points + 1
- else:
- latest_done = max(self.paused)
- range_not_done = self.total_stop_points - latest_done
- next_time = latest_done + int(self.STEP_RATIO * range_not_done) + 1
- return next_time
-
- def is_tainted(self):
- return self.active.tainted
-
- def go_forward(self, steps, breakpoint_mode='b'):
- """Go forward, for the given number of 'steps' of time.
-
- If needed, it will leave clones at intermediate times.
- Does not close the active subprocess. Note that
- is_tainted() must return false in order to use this.
-
- breakpoint_mode:
- 'b' = regular mode where hitting a breakpoint stops
- 'i' = ignore breakpoints
- 'r' = record the occurrence of a breakpoint but continue
- """
- assert steps >= 0
- if breakpoint_mode != 'i':
- self.update_breakpoints()
- latest_bkpt = None
- while True:
- cur_time = self.get_current_time()
- if cur_time + steps > self.total_stop_points:
- steps = self.total_stop_points - cur_time
- next_clone = self.get_next_clone_time()
- rel_next_clone = next_clone - cur_time
- if rel_next_clone > steps:
- break
- assert rel_next_clone >= 0
- if rel_next_clone > 0:
- bkpt = self.active.forward(rel_next_clone, breakpoint_mode)
- if breakpoint_mode == 'r':
- latest_bkpt = bkpt or latest_bkpt
- elif bkpt:
- raise bkpt
- steps -= rel_next_clone
- if self.active.current_time in self.paused:
- self.paused[self.active.current_time].close()
- clone = self.active.clone()
- self.paused[clone.current_time] = clone
- bkpt = self.active.forward(steps, breakpoint_mode)
- if breakpoint_mode == 'r':
- bkpt = bkpt or latest_bkpt
- if bkpt:
- raise bkpt
-
- def go_backward(self, steps, ignore_breakpoints=False):
- """Go backward, for the given number of 'steps' of time.
-
- Closes the active process. Implemented as jump_in_time()
- and then forward-searching for breakpoint locations (if any).
- """
- assert steps >= 0
- initial_time = self.get_current_time()
- if self.all_breakpoints.is_empty() or ignore_breakpoints:
- self.jump_in_time(initial_time - steps)
- else:
- if self.all_breakpoints.watchvalues:
- first_steps = 97 # use smaller steps, because that's costly
- else:
- first_steps = 957
- self._backward_search_forward(
- search_start_time = initial_time - first_steps,
- search_stop_time = initial_time,
- search_go_on_until_time = initial_time - steps)
-
- def _backward_search_forward(self, search_start_time, search_stop_time,
- search_go_on_until_time=1):
- while True:
- self.jump_in_time(max(search_start_time, search_go_on_until_time))
- search_start_time = self.get_current_time()
- time_range_to_search = search_stop_time - search_start_time
- if time_range_to_search <= 0:
- print "[search end]"
- return
- print "[searching %d..%d]" % (search_start_time,
- search_stop_time)
- self.go_forward(time_range_to_search, breakpoint_mode='r')
- # If at least one breakpoint was found, the Breakpoint
- # exception is raised with the *last* such breakpoint.
- # Otherwise, we continue here. Search farther along a
- # 3-times-bigger range.
- search_stop_time = search_start_time
- search_start_time -= time_range_to_search * 3
-
- def _update_watchpoints_uids(self):
- if self.all_breakpoints.watchuids:
- uids = set()
- uids.update(*self.all_breakpoints.watchuids.values())
- #print self.all_breakpoints
- #print '\t===>', uids
- self.attach_printed_objects(uids, watch_env=True)
-
- def update_breakpoints(self):
- self._update_watchpoints_uids()
- cmp = self.all_breakpoints.compare(self.active.breakpoints_cache)
- #print 'compare:', cmp, self.all_breakpoints.watchvalues
- if cmp == 2:
- return # up-to-date
-
- # update the breakpoints/watchpoints
- self.active.breakpoints_cache = None
- num2break = self.all_breakpoints.num2break
- N = (max(num2break) + 1) if num2break else 0
- if cmp == 0:
- flat = [num2break.get(n, '\x00') for n in range(N)]
- arg1 = self.all_breakpoints.stack_id
- arg2 = self.all_breakpoints.thread_num
- extra = ''.join(flat)
- self.active.send(Message(CMD_BREAKPOINTS, arg1, arg2, extra=extra))
- self.active.print_text_answer(pgroup=self)
- else:
- assert cmp == 1
-
- # update the watchpoint values
- if any(name.startswith('W') for name in num2break.values()):
- watchvalues = self.all_breakpoints.watchvalues
- flat = []
- for n in range(N):
- text = ''
- name = num2break.get(n, '')
- if name.startswith('W'):
- text = watchvalues[n]
- flat.append(text)
- extra = '\x00'.join(flat)
- self.active.send(Message(CMD_WATCHVALUES, extra=extra))
- self.active.expect_ready()
-
- self.active.breakpoints_cache = self.all_breakpoints.duplicate()
-
- def update_watch_values(self):
- try:
- self._update_watchpoints_uids()
- except socket.error as e:
- print >> sys.stderr, "socket.error: %s" % (e,)
- print >> sys.stderr, "restarting at position 1"
- self.jump_in_time(1)
- self._update_watchpoints_uids()
- seen = set()
- for num, name in self.all_breakpoints.num2break.items():
- if name.startswith('W'):
- _, text = self.check_watchpoint_expr(name[4:])
- if text != self.all_breakpoints.watchvalues[num]:
- #print self.active.pid
- print 'updating watchpoint value: %s => %s' % (
- self.all_breakpoints.sources[num], text)
- self.all_breakpoints.watchvalues[num] = text
- seen.add(num)
- assert set(self.all_breakpoints.watchvalues) == seen
-
- def compile_watchpoint_expr(self, expr):
- self.active.send(Message(CMD_COMPILEWATCH, extra=expr))
- msg = self.active.expect(ANSWER_WATCH, Ellipsis, extra=Ellipsis)
- self.active.expect_ready()
- return msg.arg1, msg.extra
-
- def check_watchpoint_expr(self, compiled_code, nids=None):
- if nids:
- self.ensure_nids_to_uids(nids)
- uids = self.nids_to_uids(nids)
- self.attach_printed_objects(uids, watch_env=True)
- self.active.send(Message(CMD_CHECKWATCH, extra=compiled_code))
- msg = self.active.expect(ANSWER_WATCH, Ellipsis, extra=Ellipsis)
- self.active.expect_ready()
- return msg.arg1, msg.extra
-
- def _resume(self, from_time):
- clone_me = self.paused[from_time]
- if self.active is not None:
- self.active.close()
- self.active = clone_me.clone(activate=True)
-
- def jump_in_time(self, target_time):
- """Jump in time at the given 'target_time'.
-
- This function always closes the active subprocess.
- """
- if target_time < 1:
- target_time = 1
- if target_time > self.total_stop_points:
- target_time = self.total_stop_points
- uids = set()
- uids.update(*self.all_breakpoints.watchuids.values())
- self.ensure_printed_objects(uids, forced_time = target_time)
-
- def close(self):
- """Close all subprocesses.
- """
- for subp in [self.active] + self.paused.values():
- subp.close()
-
- def ensure_printed_objects(self, uids, forced_time=None):
- """Ensure that all the given unique_ids are loaded in the active
- child, if necessary by forking another child from earlier.
- """
- if forced_time is None:
- initial_time = self.get_current_time()
- child = self.active
- else:
- initial_time = forced_time
- stop_time = max(time for time in self.paused
- if time <= initial_time)
- child = self.paused[stop_time]
-
- while True:
- uid_limit = child.currently_created_objects
- missing_uids = [uid for uid in uids
- if uid < uid_limit
- and uid not in child.printed_objects]
- if not missing_uids:
- break
- # pick the earlier fork
- start_time = child.current_time
- stop_time = max(time for time in self.paused if time < start_time)
- child = self.paused[stop_time]
-
- # No missing_uids left: all uids are either already in
- # self.active.printed_objects, or in the future.
- future_uids = [uid for uid in uids if uid >= uid_limit]
- if child is self.active:
- assert not future_uids
- else:
- self._resume(stop_time)
- if future_uids:
- future_uids.sort()
- pack_uids = [struct.pack('q', uid) for uid in future_uids]
- pack_uids = ''.join(pack_uids)
- #print '%d: from %d: CMD_FUTUREIDS %r' % (
- # self.active.pid,
- # self.active.current_time,
- # future_uids)
- self.active.send(Message(CMD_FUTUREIDS, extra=pack_uids))
- self.active.expect_ready()
- self.active.printed_objects = (
- self.active.printed_objects.union(future_uids))
- self.go_forward(initial_time - self.get_current_time(),
- breakpoint_mode='i')
- assert self.active.printed_objects.issuperset(uids)
-
- def nids_to_uids(self, nids, skip_futures=False):
- uids = []
- for nid in set(nids):
- try:
- uid = self.all_printed_objects_lst[nid]
- except IndexError:
- continue
- if skip_futures and uid >= self.get_currently_created_objects():
- #print >> sys.stderr, (
- # "note: '$%d' refers to an object that is "
- # "only created later in time" % nid)
- continue
- uids.append(uid)
- return uids
-
- def ensure_nids_to_uids(self, nids):
- # Take the objects listed in nids which are alive at the
- # current time, and return a list of uids of them. This
- # might require some replaying.
- uids = []
- if nids:
- uids = self.nids_to_uids(nids, skip_futures=True)
- self.ensure_printed_objects(uids)
- return uids
-
- def attach_printed_objects(self, uids, watch_env):
- for uid in uids:
- nid = self.all_printed_objects[uid]
- #print '%d: %s => %s (watch_env=%d)' % (self.active.pid, nid, uid,
- # watch_env)
- self.active.send(Message(CMD_ATTACHID, nid, uid, int(watch_env)))
- self.active.expect_ready()
-
- def recreate_subprocess(self, target_time=None):
- # recreate a subprocess at the given time, or by default the
- # current time
- if target_time is None:
- target_time = self.get_current_time()
- self.active = None
- self.jump_in_time(target_time)
-
- def print_cmd(self, expression, nids=[]):
- """Print an expression.
- """
- uids = self.ensure_nids_to_uids(nids)
- self.active.tainted = True
- self.attach_printed_objects(uids, watch_env=False)
- self.active.send(Message(CMD_PRINT, extra=expression))
- try:
- self.active.print_text_answer(pgroup=self)
- except RecreateSubprocess:
- self.recreate_subprocess()
-
- def show_backtrace(self, complete=1):
- """Show the backtrace.
- """
- if complete:
- self.active.tainted = True
- self.active.send(Message(CMD_BACKTRACE, complete))
- try:
- self.active.print_text_answer()
- except RecreateSubprocess:
- self.recreate_subprocess()
-
- def show_locals(self):
- """Show the locals.
- """
- self.active.tainted = True
- self.active.send(Message(CMD_LOCALS))
- try:
- self.active.print_text_answer()
- except RecreateSubprocess:
- self.recreate_subprocess()
-
- def edit_breakpoints(self):
- return self.all_breakpoints
-
- def _stack_id(self, is_parent=0):
- self.active.send(Message(CMD_STACKID, is_parent))
- msg = self.active.expect(ANSWER_STACKID, Ellipsis, Ellipsis)
- self.active.expect_ready()
- return msg
-
- def get_stack_id(self, is_parent):
- return self._stack_id(is_parent).arg1
-
- def get_hiddenpos_level(self):
- return self._stack_id().arg2
diff --git a/rpython/translator/revdb/revdb.py b/rpython/translator/revdb/revdb.py
deleted file mode 100755
--- a/rpython/translator/revdb/revdb.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python2
-
-import sys, os
-
-
-if __name__ == '__main__':
- import argparse
- parser = argparse.ArgumentParser(description='Reverse debugger')
- parser.add_argument('log', metavar='LOG', help='log file name')
- parser.add_argument('-x', '--executable', dest='executable',
- help='name of the executable file '
- 'that recorded the log')
- parser.add_argument('-c', '--color', dest='color',
- help='colorize source code (dark,light,off)')
- options = parser.parse_args()
-
- sys.path.insert(0, os.path.abspath(
- os.path.join(__file__, '..', '..', '..', '..')))
-
- from rpython.translator.revdb.interact import RevDebugControl
- ctrl = RevDebugControl(options.log, executable=options.executable,
- pygments_background=options.color)
- ctrl.interact()
diff --git a/rpython/translator/revdb/src-revdb/fd_send.c b/rpython/translator/revdb/src-revdb/fd_send.c
deleted file mode 100644
--- a/rpython/translator/revdb/src-revdb/fd_send.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/***************************************************************************
- * libancillary - black magic on Unix domain sockets
- * (C) Nicolas George
- * fd_send.c - sending file descriptors
- ***************************************************************************/
-
-/*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _XPG4_2 /* Solaris sucks */
-# define _XPG4_2
-#endif
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <assert.h>
-#if defined(__FreeBSD__)
-# include <sys/param.h> /* FreeBSD sucks */
-#endif
-
-#include "ancillary.h"
-
-int
-ancil_send_fds_with_buffer(int sock, const int *fds, unsigned n_fds, void *buffer)
-{
- struct msghdr msghdr;
- char nothing = '!';
- struct iovec nothing_ptr;
- struct cmsghdr *cmsg;
- int i;
-
- nothing_ptr.iov_base = ¬hing;
- nothing_ptr.iov_len = 1;
- msghdr.msg_name = NULL;
- msghdr.msg_namelen = 0;
- msghdr.msg_iov = ¬hing_ptr;
- msghdr.msg_iovlen = 1;
- msghdr.msg_flags = 0;
- msghdr.msg_control = buffer;
- msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds;
- cmsg = CMSG_FIRSTHDR(&msghdr);
- cmsg->cmsg_len = msghdr.msg_controllen;
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- for(i = 0; i < n_fds; i++)
- ((int *)CMSG_DATA(cmsg))[i] = fds[i];
- return(sendmsg(sock, &msghdr, 0) >= 0 ? 0 : -1);
-}
-
-#ifndef SPARE_SEND_FDS
-int
-ancil_send_fds(int sock, const int *fds, unsigned n_fds)
-{
- ANCIL_FD_BUFFER(ANCIL_MAX_N_FDS) buffer;
-
- assert(n_fds <= ANCIL_MAX_N_FDS);
- return(ancil_send_fds_with_buffer(sock, fds, n_fds, &buffer));
-}
-#endif /* SPARE_SEND_FDS */
-
-#ifndef SPARE_SEND_FD
-int
-ancil_send_fd(int sock, int fd)
-{
- ANCIL_FD_BUFFER(1) buffer;
-
- return(ancil_send_fds_with_buffer(sock, &fd, 1, &buffer));
-}
-#endif /* SPARE_SEND_FD */
More information about the pypy-commit
mailing list