88import hashlib
99import re
1010import pwd
11+ import select
12+ import psycopg2
13+ from time import sleep
1114
1215
1316idx_ptrack = {
@@ -946,6 +949,34 @@ def compare_pgdata(self, original_pgdata, restored_pgdata):
946949 fail = True
947950 self .assertFalse (fail , error_message )
948951
952+ def get_asyc_connect (self , database = None , host = None , port = 5432 ):
953+ if not database :
954+ database = 'postgres'
955+ if not host :
956+ host = '127.0.0.1'
957+
958+ return psycopg2 .connect (
959+ database = "postgres" ,
960+ host = '127.0.0.1' ,
961+ port = port ,
962+ async = True
963+ )
964+
965+ def wait (self , connection ):
966+ while True :
967+ state = connection .poll ()
968+ if state == psycopg2 .extensions .POLL_OK :
969+ break
970+ elif state == psycopg2 .extensions .POLL_WRITE :
971+ select .select ([], [connection .fileno ()], [])
972+ elif state == psycopg2 .extensions .POLL_READ :
973+ select .select ([connection .fileno ()], [], [])
974+ else :
975+ raise psycopg2 .OperationalError ("poll() returned %s" % state )
976+
977+ def gdb_attach (self , pid ):
978+ return GDBobj ([str (pid )], self .verbose , attach = True )
979+
949980
950981class GdbException (Exception ):
951982 def __init__ (self , message = False ):
@@ -956,7 +987,7 @@ def __str__(self):
956987
957988
958989class GDBobj (ProbackupTest ):
959- def __init__ (self , cmd , verbose ):
990+ def __init__ (self , cmd , verbose , attach = False ):
960991 self .verbose = verbose
961992
962993 # Check gdb presense
@@ -972,84 +1003,159 @@ def __init__(self, cmd, verbose):
9721003 'gdb' ,
9731004 '--interpreter' ,
9741005 'mi2' ,
975- '--args'
976- ] + cmd
1006+ ]
1007+
1008+ if attach :
1009+ self .cmd = self .base_cmd + ['--pid' ] + cmd
1010+ else :
1011+ self .cmd = self .base_cmd + ['--args' ] + cmd
9771012
9781013 # Get version
9791014 gdb_version_number = re .search (
9801015 b"^GNU gdb [^\d]*(\d+)\.(\d)" ,
9811016 gdb_version )
9821017 self .major_version = int (gdb_version_number .group (1 ))
9831018 self .minor_version = int (gdb_version_number .group (2 ))
1019+
9841020 if self .verbose :
985- print ([' ' .join (map (str , self .base_cmd ))])
1021+ print ([' ' .join (map (str , self .cmd ))])
1022+
1023+ print (self .cmd )
9861024
9871025 self .proc = subprocess .Popen (
988- self .base_cmd ,
1026+ self .cmd ,
9891027 stdin = subprocess .PIPE ,
9901028 stdout = subprocess .PIPE ,
9911029 stderr = subprocess .STDOUT ,
992- bufsize = 0 , universal_newlines = True
1030+ bufsize = 0 ,
1031+ universal_newlines = True
9931032 )
9941033 self .gdb_pid = self .proc .pid
9951034
9961035 # discard data from pipe,
9971036 # is there a way to do it a less derpy way?
9981037 while True :
9991038 line = self .proc .stdout .readline ()
1039+
1040+ if 'No such process' in line :
1041+ raise GdbException (line )
1042+
10001043 if not line .startswith ('(gdb)' ):
10011044 pass
10021045 else :
10031046 break
10041047
10051048 def set_breakpoint (self , location ):
10061049 result = self ._execute ('break ' + location )
1007- success = False
10081050 for line in result :
1051+ print (line )
10091052 if line .startswith ('~"Breakpoint' ):
1010- success = True
1011- break
1012- if line .startswith ('^error' ) or line .startswith ('(gdb)' ):
1053+ return
1054+
1055+ elif line .startswith ('^error' ) or line .startswith ('(gdb)' ):
10131056 break
10141057
1015- if line .startswith ('&"break' ):
1058+ elif line .startswith ('&"break' ):
10161059 pass
10171060
1018- if line .startswith ('&"Function' ):
1061+ elif line .startswith ('&"Function' ):
10191062 raise GdbException (line )
10201063
1021- if line .startswith ('&"No line' ):
1064+ elif line .startswith ('&"No line' ):
10221065 raise GdbException (line )
1023- return success
10241066
1025- def run (self ):
1026- result = self ._execute ('run' )
1067+ elif line .startswith ('~"Make breakpoint pending on future shared' ):
1068+ raise GdbException (line )
1069+
1070+ raise GdbException (
1071+ 'Failed to set breakpoint.\n Output:\n {0}' .format (result )
1072+ )
1073+
1074+ def run_until_break (self ):
1075+ result = self ._execute ('run' , False )
10271076 for line in result :
10281077 if line .startswith ('*stopped,reason="breakpoint-hit"' ):
1029- return 'breakpoint-hit'
1030- if line .startswith ('*stopped,reason="exited-normally"' ):
1031- return 'exit correct'
1078+ return
1079+ raise GdbException (
1080+ 'Failed to run until breakpoint.\n '
1081+ )
10321082
1033- def continue_execution (self , sync = True ):
1083+ def continue_execution_until_running (self ):
10341084 result = self ._execute ('continue' )
1085+
1086+ running = False
10351087 for line in result :
1088+ if line .startswith ('*running' ):
1089+ running = True
1090+ break
1091+ if line .startswith ('*stopped,reason="breakpoint-hit"' ):
1092+ running = False
1093+ continue
1094+ if line .startswith ('*stopped,reason="exited-normally"' ):
1095+ running = False
1096+ continue
1097+ return running
1098+
1099+ def continue_execution_until_exit (self ):
1100+ result = self ._execute ('continue' , False )
1101+
1102+ for line in result :
1103+ if line .startswith ('*running' ):
1104+ continue
1105+ if line .startswith ('*stopped,reason="breakpoint-hit"' ):
1106+ continue
1107+ if line .startswith ('*stopped,reason="exited-normally"' ):
1108+ return
1109+ raise GdbException (
1110+ 'Failed to continue execution until exit.\n '
1111+ )
1112+
1113+ def continue_execution_until_break (self , ignore_count = 0 ):
1114+ if ignore_count > 0 :
1115+ result = self ._execute (
1116+ 'continue ' + str (ignore_count ),
1117+ False
1118+ )
1119+ else :
1120+ result = self ._execute ('continue' , False )
1121+
1122+ running = False
1123+ for line in result :
1124+ if line .startswith ('*running' ):
1125+ running = True
10361126 if line .startswith ('*stopped,reason="breakpoint-hit"' ):
10371127 return 'breakpoint-hit'
10381128 if line .startswith ('*stopped,reason="exited-normally"' ):
1039- return 'exit correct'
1129+ return 'exited-normally'
1130+ if running :
1131+ return 'running'
1132+
1133+ def stopped_in_breakpoint (self ):
1134+ output = []
1135+ while True :
1136+ line = self .proc .stdout .readline ()
1137+ output += [line ]
1138+ if self .verbose :
1139+ print (line )
1140+ if line .startswith ('*stopped,reason="breakpoint-hit"' ):
1141+ return True
1142+ return False
10401143
10411144 # use for breakpoint, run, continue
1042- def _execute (self , cmd ):
1145+ def _execute (self , cmd , running = True ):
10431146 output = []
10441147 self .proc .stdin .flush ()
10451148 self .proc .stdin .write (cmd + '\n ' )
10461149 self .proc .stdin .flush ()
10471150
10481151 while True :
1152+ sleep (1 )
10491153 line = self .proc .stdout .readline ()
10501154 output += [line ]
10511155 if self .verbose :
10521156 print (line )
10531157 if line == '^done\n ' or line .startswith ('*stopped' ):
10541158 break
1159+ if running and line .startswith ('*running' ):
1160+ break
10551161 return output
0 commit comments