[Spice-devel] [PATCH 4/4] vdi_port refactor: introduce old pci_vdi_port

Alon Levy alevy at redhat.com
Thu Dec 30 05:07:26 PST 2010


This patch is a little dirty due to EOL convertion to windows format.

 + add pci_vdi_port with PCIVDIPort taken from last commit before
  changing to virtio-serial (a17ccbf323768c3cb977f0f062366ba7cf7f19db)
 + move handle_error to VDIPort (identical in VIRTIOVDIPort and PCIVDIPort)
 + make VDService create first a virtio, then init, the pci, then init,
  stopping when the first init succeeds, and reporting to log which was
  created.
---
 common/vdlog.h                |    1 +
 vdservice/pci_vdi_port.cpp    |  124 ++++++++++++++++++++++++++++++++++
 vdservice/pci_vdi_port.h      |   54 +++++++++++++++
 vdservice/vdi_port.cpp        |  150 ++++++++++++++++++++++------------------
 vdservice/vdi_port.h          |    3 +
 vdservice/vdservice.cpp       |   30 +++++++-
 vdservice/vdservice.vcproj    |   16 +++++
 vdservice/virtio_vdi_port.cpp |   15 ----
 8 files changed, 307 insertions(+), 86 deletions(-)
 create mode 100644 vdservice/pci_vdi_port.cpp
 create mode 100644 vdservice/pci_vdi_port.h

diff --git a/common/vdlog.h b/common/vdlog.h
index 419248a..bb2eb28 100644
--- a/common/vdlog.h
+++ b/common/vdlog.h
@@ -18,6 +18,7 @@
 #ifndef _H_VDLOG
 #define _H_VDLOG
 
+#include <stdio.h>
 #include <tchar.h>
 #include <crtdbg.h>
 #include <windows.h>
diff --git a/vdservice/pci_vdi_port.cpp b/vdservice/pci_vdi_port.cpp
new file mode 100644
index 0000000..3baefd9
--- /dev/null
+++ b/vdservice/pci_vdi_port.cpp
@@ -0,0 +1,124 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdio.h"
+#include "pci_vdi_port.h"
+#include "vdlog.h"
+
+#define VDI_PORT_DEV_NAME   TEXT("\\\\.\\VDIPort")
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#define METHOD_BUFFERED     0
+#define FILE_ANY_ACCESS     0
+
+#define CTL_CODE(DeviceType, Function, Method, Access) (                   \
+    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+
+#define FIRST_AVAIL_IO_FUNC 0x800
+#define RED_TUNNEL_CTL_FUNC FIRST_AVAIL_IO_FUNC
+
+#define IOCTL_RED_TUNNEL_SET_EVENT \
+    CTL_CODE(FILE_DEVICE_UNKNOWN, RED_TUNNEL_CTL_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+PCIVDIPort::PCIVDIPort()
+    : _handle (INVALID_HANDLE_VALUE)
+    , _event (NULL)
+{
+}
+
+PCIVDIPort::~PCIVDIPort()
+{
+    if (_handle != INVALID_HANDLE_VALUE) {
+        CloseHandle(_handle);
+    }
+    if (_event) {
+        CloseHandle(_event);
+    }
+}
+
+bool PCIVDIPort::init()
+{
+    DWORD io_ret_len;
+    _handle = CreateFile(VDI_PORT_DEV_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                         OPEN_EXISTING, 0, NULL);
+    if (_handle == INVALID_HANDLE_VALUE) {
+        vd_printf("CreateFile() failed: %u", GetLastError());
+        return false;
+    }
+    _event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (_event == NULL) {
+        vd_printf("CreateEvent() failed: %u", GetLastError());
+        return false;
+    }
+    if (!DeviceIoControl(_handle, IOCTL_RED_TUNNEL_SET_EVENT, &_event, sizeof(_event),
+                         NULL, 0, &io_ret_len, NULL)) {
+        vd_printf("DeviceIoControl() failed: %u", GetLastError());
+        return false;
+    }
+    return true;
+}
+
+int PCIVDIPort::write()
+{
+    int size;
+    int n;
+
+    if (_write.start == _write.end) {
+        return 0;
+    }
+    if (_write.start < _write.end) {
+        size = (int)(_write.end - _write.start);
+    } else {
+        size = (int)(&_write.ring[BUF_SIZE] - _write.start);
+    }
+    if (!WriteFile(_handle, _write.start, size, (LPDWORD)&n, NULL)) {
+        return handle_error();
+    }
+    _write.start = _write.ring + (_write.start - _write.ring + n) % BUF_SIZE;
+    return n;
+}
+
+int PCIVDIPort::read()
+{
+    int size;
+    int n;
+
+    if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) {
+        return 0;
+    }
+    if (_read.start == _read.end) {
+        _read.start = _read.end = _read.ring;
+    }
+    if (_read.start <= _read.end) {
+        size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
+    } else {
+        size = (int)(_read.start - _read.end - 1);
+    }
+    if (!ReadFile(_handle, _read.end, size, (LPDWORD)&n, NULL)) {
+        return handle_error();
+    }
+    _read.end = _read.ring + (_read.end - _read.ring + n) % BUF_SIZE;
+    return n;
+}
+
+void PCIVDIPort::handle_event(int event)
+{
+    // do nothing - the event merely serves to wake us up, then we call read/write
+    // at VDService::execute start of while(_running) loop.
+}
diff --git a/vdservice/pci_vdi_port.h b/vdservice/pci_vdi_port.h
new file mode 100644
index 0000000..40a0589
--- /dev/null
+++ b/vdservice/pci_vdi_port.h
@@ -0,0 +1,54 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_PCI_VDI_PORT
+#define _H_PCI_VDI_PORT
+
+#include "vdi_port.h"
+
+#define BUF_READ    (1 << 0)
+#define BUF_WRITE   (1 << 1)
+#define BUF_ALL     (BUF_READ | BUF_WRITE)
+
+class PCIVDIPort : public VDIPort {
+public:
+    PCIVDIPort();
+    ~PCIVDIPort();
+    virtual bool init();
+    virtual const char *name() { return "PCIVDIPort"; }
+    virtual int write();
+    virtual int read();
+    virtual unsigned get_num_events() { return 1; }
+    virtual void fill_events(HANDLE *handle) {
+        handle[0] = _event;
+    }
+    virtual void handle_event(int event);
+
+private:
+    HANDLE _handle;
+    HANDLE _event;
+};
+
+// Ring notes:
+// _end is one after the end of data
+// _start==_end means empty ring
+// _start-1==_end (modulo) means full ring
+// _start-1 is never used
+// ring_write & read on right side of the ring (update _end)
+// ring_read & write from left (update _start)
+
+#endif
diff --git a/vdservice/vdi_port.cpp b/vdservice/vdi_port.cpp
index f9fbcdf..9638dc0 100644
--- a/vdservice/vdi_port.cpp
+++ b/vdservice/vdi_port.cpp
@@ -1,76 +1,90 @@
+#include "vdlog.h"
 #include "vdi_port.h"
 
 VDIPort::VDIPort()
 {
-    ZeroMemory(&_write, offsetof(VDIPortBuffer, ring));
-    _write.start = _write.end = _write.ring;
-    ZeroMemory(&_read, offsetof(VDIPortBuffer, ring));
-    _read.start = _read.end = _read.ring;
-}
-
-
-size_t VDIPort::read_ring_size()
-{
-    return (BUF_SIZE + _read.end - _read.start) % BUF_SIZE;
-}
-
-size_t VDIPort::write_ring_free_space()
-{
-    return (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE;
-}
-
-size_t VDIPort::ring_write(const void* buf, size_t size)
-{
-    size_t free_size = (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE;
-    size_t n;
-
-    if (size > free_size) {
-        size = free_size;
-    }
-    if (_write.end < _write.start) {
-        memcpy(_write.end, buf, size);
-    } else {
-        n = MIN(size, (size_t)(&_write.ring[BUF_SIZE] - _write.end));
-        memcpy(_write.end, buf, n);
-        if (size > n) {
-            memcpy(_write.ring, (uint8_t*)buf + n, size - n);
-        }
-    }
-    _write.end = _write.ring + (_write.end - _write.ring + size) % BUF_SIZE;
-    return size;
-}
-
-size_t VDIPort::read_ring_continuous_remaining_size()
-{
-    DWORD size;
-
-    if (_read.start <= _read.end) {
-        size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
-    } else {
-        size = (DWORD)(_read.start - _read.end - 1);
-    }
-    return size;
-}
+    ZeroMemory(&_write, offsetof(VDIPortBuffer, ring));
+    _write.start = _write.end = _write.ring;
+    ZeroMemory(&_read, offsetof(VDIPortBuffer, ring));
+    _read.start = _read.end = _read.ring;
+}
+
+size_t VDIPort::read_ring_size()
+{
+    return (BUF_SIZE + _read.end - _read.start) % BUF_SIZE;
+}
+
+size_t VDIPort::write_ring_free_space()
+{
+    return (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE;
+}
+
+size_t VDIPort::ring_write(const void* buf, size_t size)
+{
+    size_t free_size = (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE;
+    size_t n;
+
+    if (size > free_size) {
+        size = free_size;
+    }
+    if (_write.end < _write.start) {
+        memcpy(_write.end, buf, size);
+    } else {
+        n = MIN(size, (size_t)(&_write.ring[BUF_SIZE] - _write.end));
+        memcpy(_write.end, buf, n);
+        if (size > n) {
+            memcpy(_write.ring, (uint8_t*)buf + n, size - n);
+        }
+    }
+    _write.end = _write.ring + (_write.end - _write.ring + size) % BUF_SIZE;
+    return size;
+}
+
+size_t VDIPort::read_ring_continuous_remaining_size()
+{
+    DWORD size;
+
+    if (_read.start <= _read.end) {
+        size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
+    } else {
+        size = (DWORD)(_read.start - _read.end - 1);
+    }
+    return size;
+}
+
+size_t VDIPort::ring_read(void* buf, size_t size)
+{
+    size_t n;
+    size_t m = 0;
+
+    if (_read.start == _read.end) {
+        return 0;
+    }
+    if (_read.start < _read.end) {
+        n = MIN(size, (size_t)(_read.end - _read.start));
+        memcpy(buf, _read.start, n);
+    } else {
+        n = MIN(size, (size_t)(&_read.ring[BUF_SIZE] - _read.start));
+        memcpy(buf, _read.start, n);
+        if (size > n) {
+            m = MIN(size - n, (size_t)(_read.end - _read.ring));
+            memcpy((uint8_t*)buf + n, _read.ring, m);
+        }
+    }
+    _read.start = _read.ring + (_read.start - _read.ring + n + m) % BUF_SIZE;
+    return n + m;
+}
 
-size_t VDIPort::ring_read(void* buf, size_t size)
+int VDIPort::handle_error()
 {
-    size_t n;
-    size_t m = 0;
-
-    if (_read.start == _read.end) {
-        return 0;
-    }
-    if (_read.start < _read.end) {
-        n = MIN(size, (size_t)(_read.end - _read.start));
-        memcpy(buf, _read.start, n);
-    } else {
-        n = MIN(size, (size_t)(&_read.ring[BUF_SIZE] - _read.start));
-        memcpy(buf, _read.start, n);
-        if (size > n) {
-            m = MIN(size - n, (size_t)(_read.end - _read.ring));
-            memcpy((uint8_t*)buf + n, _read.ring, m);
-        }
+    switch (GetLastError()) {
+    case ERROR_CONNECTION_INVALID:
+        vd_printf("port reset");
+        _write.start = _write.end = _write.ring;
+        _read.start = _read.end = _read.ring;
+        return VDI_PORT_RESET;
+    default:
+        vd_printf("port io failed: %u", GetLastError());
+        return VDI_PORT_ERROR;
     }
-    _read.start = _read.ring + (_read.start - _read.ring + n + m) % BUF_SIZE;
-    return n + m;
 }
diff --git a/vdservice/vdi_port.h b/vdservice/vdi_port.h
index cc4cb53..63b04bb 100644
--- a/vdservice/vdi_port.h
+++ b/vdservice/vdi_port.h
@@ -49,6 +49,7 @@ public:
     size_t read_ring_size();
     size_t read_ring_continuous_remaining_size();
 
+    virtual const char *name() = 0;
     virtual bool init() = 0;
     virtual unsigned get_num_events() = 0;
     virtual void fill_events(HANDLE *handle) = 0;
@@ -57,6 +58,8 @@ public:
     virtual int read() = 0;
 
 protected:
+    int handle_error();
+
     VDIPortBuffer _write;
     VDIPortBuffer _read;
 };
diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index 7b0cadb..175587c 100644
--- a/vdservice/vdservice.cpp
+++ b/vdservice/vdservice.cpp
@@ -23,6 +23,7 @@
 #include <tlhelp32.h>
 #include "vdcommon.h"
 #include "virtio_vdi_port.h"
+#include "pci_vdi_port.h"
 
 //#define DEBUG_VDSERVICE
 
@@ -401,6 +402,16 @@ VOID WINAPI VDService::main(DWORD argc, TCHAR* argv[])
 #endif //DEBUG_VDSERVICE
 }
 
+VDIPort *create_virtio_vdi_port()
+{
+    return new VirtioVDIPort();
+}
+
+VDIPort *create_pci_vdi_port()
+{
+    return new PCIVDIPort();
+}
+
 bool VDService::execute()
 {
     SECURITY_ATTRIBUTES sec_attr;
@@ -434,12 +445,25 @@ bool VDService::execute()
         CloseHandle(pipe);
         return false;
     }
-    _vdi_port = new VirtioVDIPort();
-    if (!_vdi_port->init()) {
-        delete _vdi_port;
+
+    bool init = false;
+    {
+        VDIPort* (*creators[])(void) = { create_virtio_vdi_port, create_pci_vdi_port };
+        for (int i = 0 ; i < sizeof(creators)/sizeof(creators[0]); ++i) {
+            _vdi_port = creators[i]();
+            init = _vdi_port->init();
+            if (init) {
+                break;
+            }
+            delete _vdi_port;
+        }
+    }
+    if (!init) {
+        vd_printf("Failed to create VDIPort instance");
         CloseHandle(pipe);
         return false;
     }
+    vd_printf("created %s", _vdi_port->name());
     _events_count = VD_STATIC_EVENTS_COUNT + _vdi_port->get_num_events() + 1 /*for agent*/;
     _events = new HANDLE[_events_count];
     _events_vdi_port_base = VD_STATIC_EVENTS_COUNT;
diff --git a/vdservice/vdservice.vcproj b/vdservice/vdservice.vcproj
index 32ec7c8..bbb1b75 100644
--- a/vdservice/vdservice.vcproj
+++ b/vdservice/vdservice.vcproj
@@ -335,6 +335,10 @@
 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 			>
 			<File
+				RelativePath=".\pci_vdi_port.h"
+				>
+			</File>
+			<File
 				RelativePath=".\resource.h"
 				>
 			</File>
@@ -350,6 +354,10 @@
 				RelativePath="..\common\vdlog.h"
 				>
 			</File>
+			<File
+				RelativePath=".\virtio_vdi_port.h"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Resource Files"
@@ -367,6 +375,10 @@
 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 			>
 			<File
+				RelativePath=".\pci_vdi_port.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\vdi_port.cpp"
 				>
 			</File>
@@ -378,6 +390,10 @@
 				RelativePath=".\vdservice.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\virtio_vdi_port.cpp"
+				>
+			</File>
 		</Filter>
 	</Files>
 	<Globals>
diff --git a/vdservice/virtio_vdi_port.cpp b/vdservice/virtio_vdi_port.cpp
index 278a88b..4f24a26 100644
--- a/vdservice/virtio_vdi_port.cpp
+++ b/vdservice/virtio_vdi_port.cpp
@@ -48,7 +48,6 @@ VirtioVDIPort::~VirtioVDIPort()
 
 bool VirtioVDIPort::init()
 {
-    vd_printf("creating VirtioVDIPort");
     _handle = CreateFile(VIOSERIAL_PORT_PATH, GENERIC_READ | GENERIC_WRITE , 0, NULL,
                          OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
     if (_handle == INVALID_HANDLE_VALUE) {
@@ -156,17 +155,3 @@ void VirtioVDIPort::read_completion()
     _read.bytes = bytes;
     _read.pending = false;
 }
-
-int VirtioVDIPort::handle_error()
-{
-    switch (GetLastError()) {
-    case ERROR_CONNECTION_INVALID:
-        vd_printf("port reset");
-        _write.start = _write.end = _write.ring;
-        _read.start = _read.end = _read.ring;
-        return VDI_PORT_RESET;
-    default:
-        vd_printf("port io failed: %u", GetLastError());
-        return VDI_PORT_ERROR;
-    }
-}
-- 
1.7.3.4



More information about the Spice-devel mailing list