Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: client/tests/kvm/scripts/virtio_console_guest.py

Issue 6246035: Merge remote branch 'cros/upstream' into master (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/autotest.git@master
Patch Set: patch Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 """
4 Auxiliary script used to send data between ports on guests.
5
6 @copyright: 2010 Red Hat, Inc.
7 @author: Jiri Zupka (jzupka@redhat.com)
8 @author: Lukas Doktor (ldoktor@redhat.com)
9 """
10 import threading
11 from threading import Thread
12 import os, select, re, random, sys, array
13 import fcntl, traceback, signal
14
15 DEBUGPATH = "/sys/kernel/debug"
16 SYSFSPATH = "/sys/class/virtio-ports/"
17
18 exiting = False
19
20 class VirtioGuest:
21 """
22 Test tools of virtio_ports.
23 """
24 LOOP_NONE = 0
25 LOOP_POLL = 1
26 LOOP_SELECT = 2
27
28 def __init__(self):
29 self.files = {}
30 self.exit_thread = threading.Event()
31 self.threads = []
32 self.ports = {}
33 self.poll_fds = {}
34 self.catch_signal = None
35 self.use_config = threading.Event()
36
37
38 def _readfile(self, name):
39 """
40 Read file and return content as string
41
42 @param name: Name of file
43 @return: Content of file as string
44 """
45 out = ""
46 try:
47 f = open(name, "r")
48 out = f.read()
49 f.close()
50 except:
51 print "FAIL: Cannot open file %s" % (name)
52
53 return out
54
55
56 def _get_port_status(self):
57 """
58 Get info about ports from kernel debugfs.
59
60 @return: Ports dictionary of port properties
61 """
62 ports = {}
63 not_present_msg = "FAIL: There's no virtio-ports dir in debugfs"
64 if (not os.path.ismount(DEBUGPATH)):
65 os.system('mount -t debugfs none %s' % (DEBUGPATH))
66 try:
67 if not os.path.isdir('%s/virtio-ports' % (DEBUGPATH)):
68 print not_present_msg
69 except:
70 print not_present_msg
71 else:
72 viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH))
73 for name in viop_names:
74 open_db_file = "%s/virtio-ports/%s" % (DEBUGPATH, name)
75 f = open(open_db_file, 'r')
76 port = {}
77 file = []
78 for line in iter(f):
79 file.append(line)
80 try:
81 for line in file:
82 m = re.match("(\S+): (\S+)", line)
83 port[m.group(1)] = m.group(2)
84
85 if (port['is_console'] == "yes"):
86 port["path"] = "/dev/hvc%s" % (port["console_vtermno"])
87 # Console works like a serialport
88 else:
89 port["path"] = "/dev/%s" % name
90
91 if (not os.path.exists(port['path'])):
92 print "FAIL: %s not exist" % port['path']
93
94 sysfspath = SYSFSPATH + name
95 if (not os.path.isdir(sysfspath)):
96 print "FAIL: %s not exist" % (sysfspath)
97
98 info_name = sysfspath + "/name"
99 port_name = self._readfile(info_name).strip()
100 if (port_name != port["name"]):
101 print ("FAIL: Port info not match \n%s - %s\n%s - %s" %
102 (info_name , port_name,
103 "%s/virtio-ports/%s" % (DEBUGPATH, name),
104 port["name"]))
105 except AttributeError:
106 print ("In file " + open_db_file +
107 " are bad data\n"+ "".join(file).strip())
108 print ("FAIL: Fail file data.")
109 return
110
111 ports[port['name']] = port
112 f.close()
113
114 return ports
115
116
117 def init(self, in_files):
118 """
119 Init and check port properties.
120 """
121 self.ports = self._get_port_status()
122
123 if self.ports == None:
124 return
125 for item in in_files:
126 if (item[1] != self.ports[item[0]]["is_console"]):
127 print self.ports
128 print "FAIL: Host console is not like console on guest side\n"
129 print "PASS: Init and check virtioconsole files in system."
130
131
132 class Switch(Thread):
133 """
134 Thread that sends data between ports.
135 """
136 def __init__ (self, in_files, out_files, event,
137 cachesize=1024, method=0):
138 """
139 @param in_files: Array of input files.
140 @param out_files: Array of output files.
141 @param method: Method of read/write access.
142 @param cachesize: Block to receive and send.
143 """
144 Thread.__init__(self, name="Switch")
145
146 self.in_files = in_files
147 self.out_files = out_files
148 self.exit_thread = event
149 self.method = method
150
151 self.cachesize = cachesize
152
153
154 def _none_mode(self):
155 """
156 Read and write to device in blocking mode
157 """
158 data = ""
159 while not self.exit_thread.isSet():
160 data = ""
161 for desc in self.in_files:
162 data += os.read(desc, self.cachesize)
163 if data != "":
164 for desc in self.out_files:
165 os.write(desc, data)
166
167
168 def _poll_mode(self):
169 """
170 Read and write to device in polling mode.
171 """
172
173 pi = select.poll()
174 po = select.poll()
175
176 for fd in self.in_files:
177 pi.register(fd, select.POLLIN)
178
179 for fd in self.out_files:
180 po.register(fd, select.POLLOUT)
181
182 while not self.exit_thread.isSet():
183 data = ""
184 t_out = self.out_files
185
186 readyf = pi.poll(1.0)
187 for i in readyf:
188 data += os.read(i[0], self.cachesize)
189
190 if data != "":
191 while ((len(t_out) != len(readyf)) and not
192 self.exit_thread.isSet()):
193 readyf = po.poll(1.0)
194 for desc in t_out:
195 os.write(desc, data)
196
197
198 def _select_mode(self):
199 """
200 Read and write to device in selecting mode.
201 """
202 while not self.exit_thread.isSet():
203 ret = select.select(self.in_files, [], [], 1.0)
204 data = ""
205 if ret[0] != []:
206 for desc in ret[0]:
207 data += os.read(desc, self.cachesize)
208 if data != "":
209 ret = select.select([], self.out_files, [], 1.0)
210 while ((len(self.out_files) != len(ret[1])) and not
211 self.exit_thread.isSet()):
212 ret = select.select([], self.out_files, [], 1.0)
213 for desc in ret[1]:
214 os.write(desc, data)
215
216
217 def run(self):
218 if (self.method == VirtioGuest.LOOP_POLL):
219 self._poll_mode()
220 elif (self.method == VirtioGuest.LOOP_SELECT):
221 self._select_mode()
222 else:
223 self._none_mode()
224
225
226 class Sender(Thread):
227 """
228 Creates a thread which sends random blocks of data to dst port.
229 """
230 def __init__(self, port, event, length):
231 """
232 @param port: Destination port
233 @param length: Length of the random data block
234 """
235 Thread.__init__(self, name="Sender")
236 self.port = port
237 self.exit_thread = event
238 self.data = array.array('L')
239 for i in range(max(length / self.data.itemsize, 1)):
240 self.data.append(random.randrange(sys.maxint))
241
242 def run(self):
243 while not self.exit_thread.isSet():
244 os.write(self.port, self.data)
245
246
247 def _open(self, in_files):
248 """
249 Open devices and return array of descriptors
250
251 @param in_files: Files array
252 @return: Array of descriptor
253 """
254 f = []
255
256 for item in in_files:
257 name = self.ports[item]["path"]
258 if (name in self.files):
259 f.append(self.files[name])
260 else:
261 try:
262 self.files[name] = os.open(name, os.O_RDWR)
263 if (self.ports[item]["is_console"] == "yes"):
264 print os.system("stty -F %s raw -echo" % (name))
265 print os.system("stty -F %s -a" % (name))
266 f.append(self.files[name])
267 except Exception, inst:
268 print "FAIL: Failed to open file %s" % (name)
269 raise inst
270 return f
271
272 @staticmethod
273 def pollmask_to_str(mask):
274 """
275 Conver pool mast to string
276
277 @param mask: poll return mask
278 """
279 str = ""
280 if (mask & select.POLLIN):
281 str += "IN "
282 if (mask & select.POLLPRI):
283 str += "PRI IN "
284 if (mask & select.POLLOUT):
285 str += "OUT "
286 if (mask & select.POLLERR):
287 str += "ERR "
288 if (mask & select.POLLHUP):
289 str += "HUP "
290 if (mask & select.POLLMSG):
291 str += "MSG "
292 return str
293
294
295 def poll(self, port, expected, timeout=500):
296 """
297 Pool event from device and print event like text.
298
299 @param file: Device.
300 """
301 in_f = self._open([port])
302
303 p = select.poll()
304 p.register(in_f[0])
305
306 mask = p.poll(timeout)
307
308 maskstr = VirtioGuest.pollmask_to_str(mask[0][1])
309 if (mask[0][1] & expected) == expected:
310 print "PASS: Events: " + maskstr
311 else:
312 emaskstr = VirtioGuest.pollmask_to_str(expected)
313 print "FAIL: Events: " + maskstr + " Expected: " + emaskstr
314
315
316 def lseek(self, port, pos, how):
317 """
318 Use lseek on the device. The device is unseekable so PASS is returned
319 when lseek command fails and vice versa.
320
321 @param port: Name of the port
322 @param pos: Offset
323 @param how: Relativ offset os.SEEK_{SET,CUR,END}
324 """
325 fd = self._open([port])[0]
326
327 try:
328 os.lseek(fd, pos, how)
329 except Exception, inst:
330 if inst.errno == 29:
331 print "PASS: the lseek failed as expected"
332 else:
333 print inst
334 print "FAIL: unknown error"
335 else:
336 print "FAIL: the lseek unexpectedly passed"
337
338
339 def blocking(self, port, mode=False):
340 """
341 Set port function mode blocking/nonblocking
342
343 @param port: port to set mode
344 @param mode: False to set nonblock mode, True for block mode
345 """
346 fd = self._open([port])[0]
347
348 try:
349 fl = fcntl.fcntl(fd, fcntl.F_GETFL)
350 if not mode:
351 fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
352 else:
353 fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
354
355 except Exception, inst:
356 print "FAIL: Setting (non)blocking mode: " + str(inst)
357 return
358
359 if mode:
360 print "PASS: set to blocking mode"
361 else:
362 print "PASS: set to nonblocking mode"
363
364
365 def __call__(self, sig, frame):
366 """
367 Call function. Used for signal handle.
368 """
369 if (sig == signal.SIGIO):
370 self.sigio_handler(sig, frame)
371
372
373 def sigio_handler(self, sig, frame):
374 """
375 Handler for sigio operation.
376
377 @param sig: signal which call handler.
378 @param frame: frame of caller
379 """
380 if self.poll_fds:
381 p = select.poll()
382 map(p.register, self.poll_fds.keys())
383
384 masks = p.poll(1)
385 print masks
386 for mask in masks:
387 self.poll_fds[mask[0]][1] |= mask[1]
388
389
390 def get_sigio_poll_return(self, port):
391 """
392 Return PASS, FAIL and poll walue in string format.
393
394 @param port: Port to check poll information.
395 """
396 fd = self._open([port])[0]
397
398 maskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][1])
399 if (self.poll_fds[fd][0] ^ self.poll_fds[fd][1]):
400 emaskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][0])
401 print "FAIL: Events: " + maskstr + " Expected: " + emaskstr
402 else:
403 print "PASS: Events: " + maskstr
404 self.poll_fds[fd][1] = 0
405
406
407 def set_pool_want_return(self, port, poll_value):
408 """
409 Set value to static variable.
410
411 @param port: Port which should be set excepted mask
412 @param poll_value: Value to check sigio signal.
413 """
414 fd = self._open([port])[0]
415 self.poll_fds[fd] = [poll_value, 0]
416 print "PASS: Events: " + VirtioGuest.pollmask_to_str(poll_value)
417
418
419 def catching_signal(self):
420 """
421 return: True if should set catch signal, False if ignore signal and
422 none when configuration is not changed.
423 """
424 ret = self.catch_signal
425 self.catch_signal = None
426 return ret
427
428
429 def async(self, port, mode=True, exp_val = 0):
430 """
431 Set port function mode async/sync.
432
433 @param port: port which should be pooled.
434 @param mode: False to set sync mode, True for sync mode.
435 @param exp_val: Value which should be pooled.
436 """
437 fd = self._open([port])[0]
438
439 try:
440 fcntl.fcntl(fd, fcntl.F_SETOWN, os.getpid())
441 fl = fcntl.fcntl(fd, fcntl.F_GETFL)
442
443 self.use_config.clear()
444 if mode:
445 fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_ASYNC)
446 self.poll_fds[fd] = [exp_val, 0]
447 self.catch_signal = True
448 else:
449 del self.poll_fds[fd]
450 fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_ASYNC)
451 self.catch_signal = False
452
453 os.kill(os.getpid(), signal.SIGUSR1)
454 self.use_config.wait()
455
456 except Exception, inst:
457 print "FAIL: Setting (a)sync mode: " + str(inst)
458 return
459
460 if mode:
461 print "PASS: Set to async mode"
462 else:
463 print "PASS: Set to sync mode"
464
465
466 def close(self, file):
467 """
468 Close open port.
469
470 @param file: File to close.
471 """
472 descriptor = None
473 path = self.ports[file]["path"]
474 if path != None:
475 if path in self.files.keys():
476 descriptor = self.files[path]
477 del self.files[path]
478 if descriptor != None:
479 try:
480 os.close(descriptor)
481 except Exception, inst:
482 print "FAIL: Closing the file: " + str(inst)
483 return
484 print "PASS: Close"
485
486
487 def open(self, in_file):
488 """
489 Direct open devices.
490
491 @param in_file: Array of files.
492 @return: Array of descriptors.
493 """
494 name = self.ports[in_file]["path"]
495 try:
496 self.files[name] = os.open(name, os.O_RDWR)
497 if (self.ports[in_file]["is_console"] == "yes"):
498 print os.system("stty -F %s raw -echo" % (name))
499 print "PASS: Open all filles correctly."
500 except Exception, inst:
501 print "%s\nFAIL: Failed open file %s" % (str(inst), name)
502
503
504 def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE):
505 """
506 Start a switch thread.
507
508 (There is a problem with multiple opens of a single file).
509
510 @param in_files: Array of input files.
511 @param out_files: Array of output files.
512 @param cachesize: Cachesize.
513 """
514 self.ports = self._get_port_status()
515
516 in_f = self._open(in_files)
517 out_f = self._open(out_files)
518
519 s = self.Switch(in_f, out_f, self.exit_thread, cachesize, mode)
520 s.start()
521 self.threads.append(s)
522 print "PASS: Start switch"
523
524
525 def exit_threads(self):
526 """
527 Function end all running data switch.
528 """
529 self.exit_thread.set()
530 for th in self.threads:
531 print "join"
532 th.join()
533 self.exit_thread.clear()
534
535 del self.threads[:]
536 for desc in self.files.itervalues():
537 os.close(desc)
538 self.files.clear()
539 print "PASS: All threads finished."
540
541
542 def die(self):
543 """
544 Quit consoleswitch.
545 """
546 self.exit_threads()
547 exit()
548
549
550 def send_loop_init(self, port, length):
551 """
552 Prepares the sender thread. Requires clean thread structure.
553 """
554 self.ports = self._get_port_status()
555 in_f = self._open([port])
556
557 self.threads.append(self.Sender(in_f[0], self.exit_thread, length))
558 print "PASS: Sender prepare"
559
560
561 def send_loop(self):
562 """
563 Start sender data transfer. Requires senderprepare run first.
564 """
565 self.threads[0].start()
566 print "PASS: Sender start"
567
568
569 def send(self, port, length=1, mode=True):
570 """
571 Send a data of some length
572
573 @param port: Port to write data
574 @param length: Length of data
575 @param mode: True = loop mode, False = one shoot mode
576 """
577 in_f = self._open([port])
578
579 data = ""
580 while len(data) < length:
581 data += "%c" % random.randrange(255)
582 try:
583 writes = os.write(in_f[0], data)
584 except Exception, inst:
585 print inst
586 if not writes:
587 writes = 0
588 if mode:
589 while (writes < length):
590 try:
591 writes += os.write(in_f[0], data)
592 except Exception, inst:
593 print inst
594 if writes >= length:
595 print "PASS: Send data length %d" % writes
596 else:
597 print ("FAIL: Partial send: desired %d, transfered %d" %
598 (length, writes))
599
600
601 def recv(self, port, length=1, buffer=1024, mode=True):
602 """
603 Recv a data of some length
604
605 @param port: Port to write data
606 @param length: Length of data
607 @param mode: True = loop mode, False = one shoot mode
608 """
609 in_f = self._open([port])
610
611 recvs = ""
612 try:
613 recvs = os.read(in_f[0], buffer)
614 except Exception, inst:
615 print inst
616 if mode:
617 while (len(recvs) < length):
618 try:
619 recvs += os.read(in_f[0], buffer)
620 except Exception, inst:
621 print inst
622 if len(recvs) >= length:
623 print "PASS: Recv data length %d" % len(recvs)
624 else:
625 print ("FAIL: Partial recv: desired %d, transfered %d" %
626 (length, len(recvs)))
627
628
629 def clean_port(self, port, buffer=1024):
630 in_f = self._open([port])
631 ret = select.select([in_f[0]], [], [], 1.0)
632 buf = ""
633 if ret[0]:
634 buf = os.read(in_f[0], buffer)
635 print ("PASS: Rest in socket: ") + str(buf[10])
636
637
638 def is_alive():
639 """
640 Check is only main thread is alive and if guest react.
641 """
642 if threading.activeCount() == 2:
643 print ("PASS: Guest is ok no thread alive")
644 else:
645 threads = ""
646 for thread in threading.enumerate():
647 threads += thread.name + ", "
648 print ("FAIL: On guest run thread. Active thread:" + threads)
649
650
651 def compile():
652 """
653 Compile virtio_console_guest.py to speed up.
654 """
655 import py_compile
656 py_compile.compile(sys.path[0] + "/virtio_console_guest.py")
657 print "PASS: compile"
658 sys.exit()
659
660
661 def guest_exit():
662 global exiting
663 exiting = True
664 os.kill(os.getpid(), signal.SIGUSR1)
665
666
667 def worker(virt):
668 """
669 Worker thread (infinite) loop of virtio_guest.
670 """
671 global exiting
672 print "PASS: Start"
673
674 while not exiting:
675 str = raw_input()
676 try:
677 exec str
678 except:
679 exc_type, exc_value, exc_traceback = sys.exc_info()
680 print "On Guest exception from: \n" + "".join(
681 traceback.format_exception(exc_type,
682 exc_value,
683 exc_traceback))
684
685
686 def sigusr_handler(sig, frame):
687 pass
688
689
690 def main():
691 """
692 Main function with infinite loop to catch signal from system.
693 """
694 if (len(sys.argv) > 1) and (sys.argv[1] == "-c"):
695 compile()
696
697 global exiting
698 virt = VirtioGuest()
699 slave = Thread(target=worker, args=(virt, ))
700 slave.start()
701 signal.signal(signal.SIGUSR1, sigusr_handler)
702 while not exiting:
703 signal.pause()
704 catch = virt.catching_signal()
705 if catch:
706 signal.signal(signal.SIGIO, virt)
707 elif catch == False:
708 signal.signal(signal.SIGIO, signal.SIG_DFL)
709 if (catch != None):
710 virt.use_config.set()
711 print "PASS: guest_exit"
712
713
714 if __name__ == "__main__":
715 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698