[Spice-commits] 5 commits - vdagent/vdagent.cpp vdservice/pci_vdi_port.cpp vdservice/pci_vdi_port.h vdservice/vdi_port.h vdservice/vdservice.cpp vdservice/virtio_vdi_port.cpp vdservice/virtio_vdi_port.h
Arnon Gilboa
agilboa at kemper.freedesktop.org
Sun Sep 23 09:33:49 PDT 2012
vdagent/vdagent.cpp | 197 +++++++++++++++++++++---------------------
vdservice/pci_vdi_port.cpp | 3
vdservice/pci_vdi_port.h | 2
vdservice/vdi_port.h | 2
vdservice/vdservice.cpp | 23 +++-
vdservice/virtio_vdi_port.cpp | 26 +++--
vdservice/virtio_vdi_port.h | 6 -
7 files changed, 137 insertions(+), 122 deletions(-)
New commits:
commit 4929cb36f20b0a655f509af90ee3a71d5fad34f9
Author: Arnon Gilboa <agilboa at redhat.com>
Date: Sun Sep 16 11:48:09 2012 +0300
vdservice: stop service on virtio failure
read & write are async, and their completion is handled by handle_event(),
which returns status used by service execute loop.
previously an error in GetOverlappedResult caused vdservice hang.
rhbz#839564
diff --git a/vdservice/pci_vdi_port.cpp b/vdservice/pci_vdi_port.cpp
index 4deace1..7466fbc 100644
--- a/vdservice/pci_vdi_port.cpp
+++ b/vdservice/pci_vdi_port.cpp
@@ -124,8 +124,9 @@ int PCIVDIPort::read()
return n;
}
-void PCIVDIPort::handle_event(int event)
+bool 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.
+ return true;
}
diff --git a/vdservice/pci_vdi_port.h b/vdservice/pci_vdi_port.h
index caa990f..fcc76dc 100644
--- a/vdservice/pci_vdi_port.h
+++ b/vdservice/pci_vdi_port.h
@@ -41,7 +41,7 @@ public:
virtual int read();
virtual unsigned get_num_events() { return PCI_VDI_PORT_EVENT_COUNT; }
virtual void fill_events(HANDLE* handles);
- virtual void handle_event(int event);
+ virtual bool handle_event(int event);
private:
HANDLE _handle;
diff --git a/vdservice/vdi_port.h b/vdservice/vdi_port.h
index 50c4d29..a0fb20e 100644
--- a/vdservice/vdi_port.h
+++ b/vdservice/vdi_port.h
@@ -61,7 +61,7 @@ public:
virtual bool init() = 0;
virtual unsigned get_num_events() = 0;
virtual void fill_events(HANDLE* handles) = 0;
- virtual void handle_event(int event) = 0;
+ virtual bool handle_event(int event) = 0;
virtual int write() = 0;
virtual int read() = 0;
diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index b48cbeb..2b925fd 100644
--- a/vdservice/vdservice.cpp
+++ b/vdservice/vdservice.cpp
@@ -130,7 +130,6 @@ private:
bool _running;
VDLog* _log;
unsigned _events_count;
- unsigned _events_vdi_port_base;
};
VDService* VDService::_singleton = NULL;
@@ -185,7 +184,6 @@ VDService::VDService()
, _running (false)
, _log (NULL)
, _events_count(0)
- , _events_vdi_port_base(0)
{
ZeroMemory(&_agent_proc_info, sizeof(_agent_proc_info));
ZeroMemory(&_pipe_state, sizeof(_pipe_state));
@@ -536,13 +534,12 @@ bool VDService::execute()
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;
ZeroMemory(_events, _events_count);
vd_printf("Connected to server");
_events[VD_EVENT_PIPE_READ] = _pipe_state.read.overlap.hEvent;
_events[VD_EVENT_PIPE_WRITE] = _pipe_state.write.overlap.hEvent;
_events[VD_EVENT_CONTROL] = _control_event;
- _vdi_port->fill_events(&_events[_events_vdi_port_base]);
+ _vdi_port->fill_events(&_events[VD_STATIC_EVENTS_COUNT]);
_chunk_size = _chunk_port = 0;
read_pipe();
while (_running) {
@@ -602,12 +599,12 @@ bool VDService::execute()
}
}
} else {
- if (wait_ret >= WAIT_OBJECT_0 + _events_vdi_port_base &&
- wait_ret < WAIT_OBJECT_0 +
- _events_vdi_port_base + _vdi_port->get_num_events()) {
- _vdi_port->handle_event(wait_ret - VD_STATIC_EVENTS_COUNT - WAIT_OBJECT_0);
+ int vdi_event = wait_ret - VD_STATIC_EVENTS_COUNT - WAIT_OBJECT_0;
+ if (vdi_event >= 0 && vdi_event < _vdi_port->get_num_events()) {
+ _running = _vdi_port->handle_event(vdi_event);
} else {
vd_printf("WaitForMultipleObjects failed %lu", GetLastError());
+ _running = false;
}
}
}
diff --git a/vdservice/virtio_vdi_port.cpp b/vdservice/virtio_vdi_port.cpp
index 92eb129..be5568a 100644
--- a/vdservice/virtio_vdi_port.cpp
+++ b/vdservice/virtio_vdi_port.cpp
@@ -51,17 +51,21 @@ void VirtioVDIPort::fill_events(HANDLE* handles) {
handles[VIRTIO_VDI_PORT_EVENT_READ] = _read.overlap.hEvent;
}
-void VirtioVDIPort::handle_event(int event) {
+bool VirtioVDIPort::handle_event(int event) {
+ bool ret;
+
switch (event) {
case VIRTIO_VDI_PORT_EVENT_WRITE:
- write_completion();
+ ret = write_completion();
break;
case VIRTIO_VDI_PORT_EVENT_READ:
- read_completion();
+ ret = read_completion();
break;
default:
vd_printf("ERROR: unexpected event %d", event);
+ ret = false;
}
+ return ret;
}
bool VirtioVDIPort::init()
@@ -113,20 +117,21 @@ int VirtioVDIPort::write()
return ret;
}
-void VirtioVDIPort::write_completion()
+bool VirtioVDIPort::write_completion()
{
DWORD bytes;
if (!_write.pending) {
- return;
+ return true;
}
if (!GetOverlappedResult(_handle, &_write.overlap, &bytes, FALSE)) {
vd_printf("GetOverlappedResult failed: %lu", GetLastError());
- return;
+ return false;
}
_write.start = _write.ring + (_write.start - _write.ring + bytes) % BUF_SIZE;
_write.bytes = bytes;
_write.pending = false;
+ return true;
}
int VirtioVDIPort::read()
@@ -160,7 +165,7 @@ int VirtioVDIPort::read()
return ret;
}
-void VirtioVDIPort::read_completion()
+bool VirtioVDIPort::read_completion()
{
DWORD bytes;
@@ -169,13 +174,14 @@ void VirtioVDIPort::read_completion()
if (err == ERROR_OPERATION_ABORTED || err == ERROR_NO_SYSTEM_RESOURCES) {
_read.pending = false;
- return;
+ return true;
} else if (err != ERROR_MORE_DATA) {
vd_printf("GetOverlappedResult failed: %lu", err);
- return;
+ return false;
}
}
_read.end = _read.ring + (_read.end - _read.ring + bytes) % BUF_SIZE;
_read.bytes = bytes;
_read.pending = false;
+ return true;
}
diff --git a/vdservice/virtio_vdi_port.h b/vdservice/virtio_vdi_port.h
index 15b6811..d72edf4 100644
--- a/vdservice/virtio_vdi_port.h
+++ b/vdservice/virtio_vdi_port.h
@@ -17,13 +17,13 @@ public:
virtual bool init();
virtual unsigned get_num_events() { return VIRTIO_VDI_PORT_EVENT_COUNT; }
virtual void fill_events(HANDLE* handles);
- virtual void handle_event(int event);
+ virtual bool handle_event(int event);
virtual int write();
virtual int read();
private:
- void write_completion();
- void read_completion();
+ bool write_completion();
+ bool read_completion();
private:
static VirtioVDIPort* _singleton;
commit 1f56b3812fecf885280213aeb4bdedea7e42dd66
Author: Arnon Gilboa <agilboa at redhat.com>
Date: Thu Sep 13 17:23:02 2012 +0300
vdservice: retry virtio-serial read on ERROR_NO_SYSTEM_RESOURCES (1450)
as recommended by MS. seems like defined behavior of the driver.
rhbz#839564
diff --git a/vdservice/virtio_vdi_port.cpp b/vdservice/virtio_vdi_port.cpp
index 31a3862..92eb129 100644
--- a/vdservice/virtio_vdi_port.cpp
+++ b/vdservice/virtio_vdi_port.cpp
@@ -167,7 +167,7 @@ void VirtioVDIPort::read_completion()
if (!GetOverlappedResult(_handle, &_read.overlap, &bytes, FALSE)) {
DWORD err = GetLastError();
- if (err == ERROR_OPERATION_ABORTED) {
+ if (err == ERROR_OPERATION_ABORTED || err == ERROR_NO_SYSTEM_RESOURCES) {
_read.pending = false;
return;
} else if (err != ERROR_MORE_DATA) {
commit 18f70a3376a1e4a8c0d0a164a21b0be97f4c355a
Author: Arnon Gilboa <agilboa at redhat.com>
Date: Mon Sep 10 10:59:14 2012 +0300
vdservice: restart vdagent if killed manually
win7-only issue
rhbz#845222
diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index 696f3da..b48cbeb 100644
--- a/vdservice/vdservice.cpp
+++ b/vdservice/vdservice.cpp
@@ -590,6 +590,16 @@ bool VDService::execute()
restart_agent(false);
} else if (_system_version == SYS_VER_WIN_7_CLASS) {
kill_agent();
+ // Assume agent was killed due to console disconnect, and wait for agent
+ // normal restart due to console connect. If the agent is not alive yet,
+ // it was killed manually (or crashed), so let's restart it.
+ if (WaitForSingleObject(_control_event, VD_AGENT_RESTART_INTERVAL) ==
+ WAIT_OBJECT_0) {
+ handle_control_event();
+ }
+ if (_running && !_agent_alive) {
+ restart_agent(false);
+ }
}
} else {
if (wait_ret >= WAIT_OBJECT_0 + _events_vdi_port_base &&
commit 900ef2b4db2cae9a7ee9f159af6d7bc602005be9
Author: Arnon Gilboa <agilboa at redhat.com>
Date: Mon Sep 10 10:17:23 2012 +0300
vdagent: don't stop due to UIPI blocking
User Interface Privilege Isolation is usually used only for specific windows of
system security applications (anti-viruses etc.), so with this patch mouse will
be irresponsive for these windows but keep working for the rest. A complete
solution might be switching to server mouse mode while the agent is still active.
diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 3ffafe3..078e50f 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -429,9 +429,14 @@ bool VDAgent::send_input()
return false;
}
}
- if (!SendInput(1, &_input, sizeof(INPUT)) && GetLastError() != ERROR_ACCESS_DENIED) {
- vd_printf("SendInput failed: %lu", GetLastError());
- ret = _running = false;
+ if (!SendInput(1, &_input, sizeof(INPUT))) {
+ DWORD err = GetLastError();
+ // Don't stop agent due to UIPI blocking, which is usually only for specific windows
+ // of system security applications (anti-viruses etc.)
+ if (err != ERROR_SUCCESS && err != ERROR_ACCESS_DENIED) {
+ vd_printf("SendInput failed: %lu", err);
+ ret = _running = false;
+ }
}
_input_time = GetTickCount();
_desktop_layout->unlock();
commit 4e95b73ecf11000b23cd506fc70a686baf83df5c
Author: Arnon Gilboa <agilboa at redhat.com>
Date: Mon Sep 10 09:48:46 2012 +0300
vdagent: add message_queue for messages written to pipe
This is only part of the message corruption solution.
The other part is fixing virtio-serial / spice-qemu-char throttling code.
-replace write_[lock/unlock/completion] calls with [new/enqueue]_message
-remove clipboard specific _out_msg_* class members
-remove ugly loop - while (a->_out_msg && a->write_clipboard());
-add _message_mutex for message queue
-fix pending_write race using _write_mutex
-TODO: enqueue large message without dividing it to chunks in advance
rhbz #846427
diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index b8bad44..3ffafe3 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -94,10 +94,10 @@ private:
enum { CONTROL_STOP, CONTROL_DESKTOP_SWITCH };
void set_control_event(int control_command);
void handle_control_event();
- uint8_t* write_lock(DWORD bytes = 0);
- void write_unlock(DWORD bytes = 0);
+ VDPipeMessage* new_message(DWORD bytes = 0);
+ void enqueue_message(VDPipeMessage* msg);
bool write_message(uint32_t type, uint32_t size, void* data);
- bool write_clipboard();
+ bool write_clipboard(VDAgentMessage* msg, uint32_t size);
bool connect_pipe();
bool send_input();
void set_display_depth(uint32_t depth);
@@ -119,9 +119,6 @@ private:
HANDLE _clipboard_event;
VDAgentMessage* _in_msg;
uint32_t _in_msg_pos;
- VDAgentMessage* _out_msg;
- uint32_t _out_msg_pos;
- uint32_t _out_msg_size;
bool _pending_input;
bool _pending_write;
bool _running;
@@ -131,7 +128,9 @@ private:
VDPipeState _pipe_state;
mutex_t _write_mutex;
mutex_t _control_mutex;
+ mutex_t _message_mutex;
std::queue<int> _control_queue;
+ std::queue<VDPipeMessage*> _message_queue;
bool _logon_desktop;
bool _display_setting_initialized;
@@ -167,9 +166,6 @@ VDAgent::VDAgent()
, _clipboard_event (NULL)
, _in_msg (NULL)
, _in_msg_pos (0)
- , _out_msg (NULL)
- , _out_msg_pos (0)
- , _out_msg_size (0)
, _pending_input (false)
, _pending_write (false)
, _running (false)
@@ -193,6 +189,7 @@ VDAgent::VDAgent()
ZeroMemory(&_pipe_state, sizeof(VDPipeState));
MUTEX_INIT(_write_mutex);
MUTEX_INIT(_control_mutex);
+ MUTEX_INIT(_message_mutex);
_singleton = this;
}
@@ -538,7 +535,7 @@ bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port
}
DWORD msg_size = VD_MESSAGE_HEADER_SIZE + sizeof(VDAgentReply);
- reply_pipe_msg = (VDPipeMessage*)write_lock(msg_size);
+ reply_pipe_msg = new_message(msg_size);
if (!reply_pipe_msg) {
return false;
}
@@ -553,10 +550,7 @@ bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port
reply = (VDAgentReply*)reply_msg->data;
reply->type = VD_AGENT_MONITORS_CONFIG;
reply->error = display_count ? VD_AGENT_SUCCESS : VD_AGENT_ERROR;
- write_unlock(msg_size);
- if (!_pending_write) {
- write_completion(0, 0, &_pipe_state.write.overlap);
- }
+ enqueue_message(reply_pipe_msg);
return true;
}
@@ -669,7 +663,7 @@ bool VDAgent::send_announce_capabilities(bool request)
uint32_t internal_msg_size = sizeof(VDAgentAnnounceCapabilities) + VD_AGENT_CAPS_BYTES;
msg_size = VD_MESSAGE_HEADER_SIZE + internal_msg_size;
- caps_pipe_msg = (VDPipeMessage*)write_lock(msg_size);
+ caps_pipe_msg = new_message(msg_size);
if (!caps_pipe_msg) {
return false;
}
@@ -694,10 +688,7 @@ bool VDAgent::send_announce_capabilities(bool request)
for (uint32_t i = 0 ; i < caps_size; ++i) {
vd_printf("%X", caps->caps[i]);
}
- write_unlock(msg_size);
- if (!_pending_write) {
- write_completion(0, 0, &_pipe_state.write.overlap);
- }
+ enqueue_message(caps_pipe_msg);
return true;
}
@@ -750,11 +741,10 @@ bool VDAgent::handle_display_config(VDAgentDisplayConfig* display_config, uint32
}
msg_size = VD_MESSAGE_HEADER_SIZE + sizeof(VDAgentReply);
- reply_pipe_msg = (VDPipeMessage*)write_lock(msg_size);
+ reply_pipe_msg = new_message(msg_size);
if (!reply_pipe_msg) {
return false;
}
-
reply_pipe_msg->type = VD_AGENT_COMMAND;
reply_pipe_msg->opaque = port;
reply_pipe_msg->size = sizeof(VDAgentMessage) + sizeof(VDAgentReply);
@@ -766,10 +756,7 @@ bool VDAgent::handle_display_config(VDAgentDisplayConfig* display_config, uint32
reply = (VDAgentReply*)reply_msg->data;
reply->type = VD_AGENT_DISPLAY_CONFIG;
reply->error = VD_AGENT_SUCCESS;
- write_unlock(msg_size);
- if (!_pending_write) {
- write_completion(0, 0, &_pipe_state.write.overlap);
- }
+ enqueue_message(reply_pipe_msg);
return true;
}
@@ -778,16 +765,13 @@ bool VDAgent::handle_control(VDPipeMessage* msg)
switch (msg->type) {
case VD_AGENT_RESET: {
vd_printf("Agent reset");
- VDPipeMessage* ack = (VDPipeMessage*)write_lock(sizeof(VDPipeMessage));
+ VDPipeMessage* ack = new_message(sizeof(VDPipeMessage));
if (!ack) {
return false;
}
ack->type = VD_AGENT_RESET_ACK;
ack->opaque = msg->opaque;
- write_unlock(sizeof(VDPipeMessage));
- if (!_pending_write) {
- write_completion(0, 0, &_pipe_state.write.overlap);
- }
+ enqueue_message(ack);
break;
}
case VD_AGENT_SESSION_LOGON:
@@ -816,30 +800,30 @@ bool VDAgent::handle_control(VDPipeMessage* msg)
//FIXME: division to max size chunks should NOT be here, but in the service
// here we should write the max possible size to the pipe
-bool VDAgent::write_clipboard()
+bool VDAgent::write_clipboard(VDAgentMessage* msg, uint32_t size)
{
- ASSERT(_out_msg);
- DWORD n = MIN(sizeof(VDPipeMessage) + _out_msg_size - _out_msg_pos, VD_AGENT_MAX_DATA_SIZE);
- VDPipeMessage* pipe_msg = (VDPipeMessage*)write_lock(n);
- if (!pipe_msg) {
- return false;
- }
- pipe_msg->type = VD_AGENT_COMMAND;
- pipe_msg->opaque = VDP_CLIENT_PORT;
- pipe_msg->size = n - sizeof(VDPipeMessage);
- memcpy(pipe_msg->data, (char*)_out_msg + _out_msg_pos, n - sizeof(VDPipeMessage));
- write_unlock(n);
- if (!_pending_write) {
- write_completion(0, 0, &_pipe_state.write.overlap);
- }
- _out_msg_pos += (n - sizeof(VDPipeMessage));
- if (_out_msg_pos == _out_msg_size) {
- delete[] (uint8_t *)_out_msg;
- _out_msg = NULL;
- _out_msg_size = 0;
- _out_msg_pos = 0;
- }
- return true;
+ uint32_t pos = 0;
+ bool ret = true;
+
+ ASSERT(msg && size);
+ //FIXME: do it smarter - no loop, no memcopy
+ MUTEX_LOCK(_message_mutex);
+ while (pos < size) {
+ DWORD n = MIN(sizeof(VDPipeMessage) + size - pos, VD_AGENT_MAX_DATA_SIZE);
+ VDPipeMessage* pipe_msg = new_message(n);
+ if (!pipe_msg) {
+ ret = false;
+ break;
+ }
+ pipe_msg->type = VD_AGENT_COMMAND;
+ pipe_msg->opaque = VDP_CLIENT_PORT;
+ pipe_msg->size = n - sizeof(VDPipeMessage);
+ memcpy(pipe_msg->data, (char*)msg + pos, n - sizeof(VDPipeMessage));
+ enqueue_message(pipe_msg);
+ pos += (n - sizeof(VDPipeMessage));
+ }
+ MUTEX_UNLOCK(_message_mutex);
+ return ret;
}
bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
@@ -847,7 +831,7 @@ bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
VDPipeMessage* pipe_msg;
VDAgentMessage* msg;
- pipe_msg = (VDPipeMessage*)write_lock(VD_MESSAGE_HEADER_SIZE + size);
+ pipe_msg = new_message(VD_MESSAGE_HEADER_SIZE + size);
if (!pipe_msg) {
return false;
}
@@ -862,10 +846,7 @@ bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
if (size && data) {
memcpy(msg->data, data, size);
}
- write_unlock(VD_MESSAGE_HEADER_SIZE + size);
- if (!_pending_write) {
- write_completion(0, 0, &_pipe_state.write.overlap);
- }
+ enqueue_message(pipe_msg);
return true;
}
@@ -993,6 +974,8 @@ bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab, uint32
// VD_AGENT_CLIPBOARD_NONE and no data, so the client will know the request failed.
bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_request)
{
+ VDAgentMessage* msg;
+ uint32_t msg_size;
UINT format;
HANDLE clip_data;
uint8_t* new_data = NULL;
@@ -1008,10 +991,6 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
vd_printf("Unsupported clipboard type %u", clipboard_request->type);
return false;
}
- if (_out_msg) {
- vd_printf("clipboard change is already pending");
- return false;
- }
if (!IsClipboardFormatAvailable(format) || !OpenClipboard(_hwnd)) {
return false;
}
@@ -1047,14 +1026,13 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
CloseClipboard();
return false;
}
- _out_msg_pos = 0;
- _out_msg_size = sizeof(VDAgentMessage) + sizeof(VDAgentClipboard) + new_size;
- _out_msg = (VDAgentMessage*)new uint8_t[_out_msg_size];
- _out_msg->protocol = VD_AGENT_PROTOCOL;
- _out_msg->type = VD_AGENT_CLIPBOARD;
- _out_msg->opaque = 0;
- _out_msg->size = (uint32_t)(sizeof(VDAgentClipboard) + new_size);
- VDAgentClipboard* clipboard = (VDAgentClipboard*)_out_msg->data;
+ msg_size = sizeof(VDAgentMessage) + sizeof(VDAgentClipboard) + new_size;
+ msg = (VDAgentMessage*)new uint8_t[msg_size];
+ msg->protocol = VD_AGENT_PROTOCOL;
+ msg->type = VD_AGENT_CLIPBOARD;
+ msg->opaque = 0;
+ msg->size = (uint32_t)(sizeof(VDAgentClipboard) + new_size);
+ VDAgentClipboard* clipboard = (VDAgentClipboard*)msg->data;
clipboard->type = clipboard_request->type;
switch (clipboard_request->type) {
@@ -1070,7 +1048,8 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
break;
}
CloseClipboard();
- write_clipboard();
+ write_clipboard(msg, msg_size);
+ delete[] (uint8_t *)msg;
return true;
}
@@ -1281,8 +1260,8 @@ VOID CALLBACK VDAgent::write_completion(DWORD err, DWORD bytes, LPOVERLAPPED ove
{
VDAgent* a = _singleton;
VDPipeState* ps = &a->_pipe_state;
+ DWORD size_left;
- a->_pending_write = false;
if (!a->_running) {
return;
}
@@ -1291,40 +1270,57 @@ VOID CALLBACK VDAgent::write_completion(DWORD err, DWORD bytes, LPOVERLAPPED ove
a->_running = false;
return;
}
- if (!a->write_lock()) {
- a->_running = false;
- return;
- }
+ MUTEX_LOCK(a->_write_mutex);
ps->write.start += bytes;
if (ps->write.start == ps->write.end) {
ps->write.start = ps->write.end = 0;
- //DEBUG
- while (a->_out_msg && a->write_clipboard());
- } else if (WriteFileEx(ps->pipe, ps->write.data + ps->write.start,
- ps->write.end - ps->write.start, overlap, write_completion)) {
- a->_pending_write = true;
+ }
+
+ MUTEX_LOCK(a->_message_mutex);
+ size_left = sizeof(a->_pipe_state.write.data) - a->_pipe_state.write.end;
+ while (!a->_message_queue.empty()) {
+ VDPipeMessage* msg = a->_message_queue.front();
+ DWORD size = sizeof(VDPipeMessage) + msg->size;
+
+ if (size > size_left) {
+ break;
+ }
+ a->_message_queue.pop();
+ memcpy(a->_pipe_state.write.data + a->_pipe_state.write.end, msg, size);
+ a->_pipe_state.write.end += size;
+ size_left -= size;
+ delete msg;
+ }
+ MUTEX_UNLOCK(a->_message_mutex);
+
+ if (ps->write.start < ps->write.end) {
+ if (WriteFileEx(ps->pipe, ps->write.data + ps->write.start,
+ ps->write.end - ps->write.start, overlap, write_completion)) {
+ a->_pending_write = true;
+ } else {
+ vd_printf("WriteFileEx() failed: %lu", GetLastError());
+ a->_running = false;
+ }
} else {
- vd_printf("WriteFileEx() failed: %lu", GetLastError());
- a->_running = false;
+ a->_pending_write = false;
}
- a->write_unlock();
+ MUTEX_UNLOCK(a->_write_mutex);
}
-uint8_t* VDAgent::write_lock(DWORD bytes)
+VDPipeMessage* VDAgent::new_message(DWORD bytes)
{
- MUTEX_LOCK(_write_mutex);
- if (_pipe_state.write.end + bytes <= sizeof(_pipe_state.write.data)) {
- return &_pipe_state.write.data[_pipe_state.write.end];
- } else {
- MUTEX_UNLOCK(_write_mutex);
- vd_printf("write buffer is full");
- return NULL;
- }
+ return (VDPipeMessage*)(new char[bytes]);
}
-void VDAgent::write_unlock(DWORD bytes)
+void VDAgent::enqueue_message(VDPipeMessage* msg)
{
- _pipe_state.write.end += bytes;
+ MUTEX_LOCK(_message_mutex);
+ _message_queue.push(msg);
+ MUTEX_UNLOCK(_message_mutex);
+ MUTEX_LOCK(_write_mutex);
+ if (!_pending_write) {
+ write_completion(0, 0, &_pipe_state.write.overlap);
+ }
MUTEX_UNLOCK(_write_mutex);
}
More information about the Spice-commits
mailing list