server/red_worker: reuse dispatcher

This patch reuses Dispatcher in RedDispatcher. It adds two helpers
to red_worker to keep RedWorker opaque to the outside. The dispatcher is
abused in three places that use the underlying socket directly:
 once sending a READY after red_init completes
 once for each channel creation, replying with the RedChannel instance
  for cursor and display.

FDO Bugzilla: 42463

rfc->v1:
* move callbacks to red_worker.c including registration (Yonit)
* rename dispatcher to red_dispatcher in red_worker.c and red_dispatcher.c
* add accessor red_dispatcher_get_dispatcher
* s/dispatcher_handle_recv/dispatcher_handle_recv_read/ and change sig to
  just Dispatcher *dispatcher (was the SpiceCoreInterface one)
* remove SpiceCoreInterface parameter from dispatcher_init (Yonit)
* main_dispatcher needed it for channel_event so it has it in
  struct MainDispatcher
* add dispatcher_get_recv_fd for red_worker
This commit is contained in:
Alon Levy 2011-10-31 17:35:30 +02:00
parent ca5776f40e
commit 8e049ce3b0
4 changed files with 1017 additions and 567 deletions

View File

@ -37,6 +37,7 @@
#include "reds_gl_canvas.h"
#endif // USE_OPENGL
#include "reds.h"
#include "dispatcher.h"
#include "red_dispatcher.h"
#include "red_parse_qxl.h"
@ -58,7 +59,7 @@ struct AsyncCommand {
struct RedDispatcher {
QXLWorker base;
QXLInstance *qxl;
int channel;
Dispatcher dispatcher;
pthread_t worker_thread;
uint32_t pending;
int primary_active;
@ -93,19 +94,22 @@ static void red_dispatcher_set_display_peer(RedChannel *channel, RedClient *clie
int num_common_caps, uint32_t *common_caps, int num_caps,
uint32_t *caps)
{
RedWorkerMessageDisplayConnect payload;
RedDispatcher *dispatcher;
red_printf("");
dispatcher = (RedDispatcher *)channel->data;
RedWorkerMessage message = RED_WORKER_MESSAGE_DISPLAY_CONNECT;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &client, sizeof(RedClient *));
send_data(dispatcher->channel, &stream, sizeof(RedsStream *));
send_data(dispatcher->channel, &migration, sizeof(int));
payload.client = client;
payload.stream = stream;
payload.migration = migration;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_DISPLAY_CONNECT,
&payload);
}
static void red_dispatcher_disconnect_display_peer(RedChannelClient *rcc)
{
RedWorkerMessageDisplayDisconnect payload;
RedDispatcher *dispatcher;
if (!rcc->channel) {
@ -115,27 +119,28 @@ static void red_dispatcher_disconnect_display_peer(RedChannelClient *rcc)
dispatcher = (RedDispatcher *)rcc->channel->data;
red_printf("");
RedWorkerMessage message = RED_WORKER_MESSAGE_DISPLAY_DISCONNECT;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &rcc, sizeof(RedChannelClient *));
payload.rcc = rcc;
// TODO: we turned it to be sync, due to client_destroy . Should we support async? - for this we will need ref count
// for channels
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
&payload);
}
static void red_dispatcher_display_migrate(RedChannelClient *rcc)
{
RedWorkerMessageDisplayMigrate payload;
RedDispatcher *dispatcher;
if (!rcc->channel) {
return;
}
dispatcher = (RedDispatcher *)rcc->channel->data;
red_printf("channel type %u id %u", rcc->channel->type, rcc->channel->id);
RedWorkerMessage message = RED_WORKER_MESSAGE_DISPLAY_MIGRATE;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &rcc, sizeof(RedChannelClient *));
payload.rcc = rcc;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
&payload);
}
static void red_dispatcher_set_cursor_peer(RedChannel *channel, RedClient *client, RedsStream *stream,
@ -143,17 +148,20 @@ static void red_dispatcher_set_cursor_peer(RedChannel *channel, RedClient *clien
uint32_t *common_caps, int num_caps,
uint32_t *caps)
{
RedWorkerMessageCursorConnect payload;
RedDispatcher *dispatcher = (RedDispatcher *)channel->data;
red_printf("");
RedWorkerMessage message = RED_WORKER_MESSAGE_CURSOR_CONNECT;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &client, sizeof(RedClient *));
send_data(dispatcher->channel, &stream, sizeof(RedsStream *));
send_data(dispatcher->channel, &migration, sizeof(int));
payload.client = client;
payload.stream = stream;
payload.migration = migration;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_CURSOR_CONNECT,
&payload);
}
static void red_dispatcher_disconnect_cursor_peer(RedChannelClient *rcc)
{
RedWorkerMessageCursorDisconnect payload;
RedDispatcher *dispatcher;
if (!rcc->channel) {
@ -162,16 +170,16 @@ static void red_dispatcher_disconnect_cursor_peer(RedChannelClient *rcc)
dispatcher = (RedDispatcher *)rcc->channel->data;
red_printf("");
RedWorkerMessage message = RED_WORKER_MESSAGE_CURSOR_DISCONNECT;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &rcc, sizeof(RedChannelClient *));
payload.rcc = rcc;
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
&payload);
}
static void red_dispatcher_cursor_migrate(RedChannelClient *rcc)
{
RedWorkerMessageCursorMigrate payload;
RedDispatcher *dispatcher;
if (!rcc->channel) {
@ -179,8 +187,10 @@ static void red_dispatcher_cursor_migrate(RedChannelClient *rcc)
}
dispatcher = (RedDispatcher *)rcc->channel->data;
red_printf("channel type %u id %u", rcc->channel->type, rcc->channel->id);
RedWorkerMessage message = RED_WORKER_MESSAGE_CURSOR_MIGRATE;
write_message(dispatcher->channel, &message);
payload.rcc = rcc;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_CURSOR_MIGRATE,
&payload);
}
typedef struct RendererInfo {
@ -263,16 +273,16 @@ static void red_dispatcher_update_area(RedDispatcher *dispatcher, uint32_t surfa
QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
uint32_t num_dirty_rects, uint32_t clear_dirty_region)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE;
RedWorkerMessageUpdate payload;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
send_data(dispatcher->channel, &qxl_area, sizeof(QXLRect *));
send_data(dispatcher->channel, &qxl_dirty_rects, sizeof(QXLRect *));
send_data(dispatcher->channel, &num_dirty_rects, sizeof(uint32_t));
send_data(dispatcher->channel, &clear_dirty_region, sizeof(uint32_t));
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
payload.surface_id = surface_id;
payload.qxl_area = qxl_area;
payload.qxl_dirty_rects = qxl_dirty_rects;
payload.num_dirty_rects = num_dirty_rects;
payload.clear_dirty_region = clear_dirty_region;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_UPDATE,
&payload);
}
static AsyncCommand *async_command_alloc(RedDispatcher *dispatcher,
@ -297,13 +307,15 @@ static void red_dispatcher_update_area_async(RedDispatcher *dispatcher,
uint64_t cookie)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE_ASYNC;
AsyncCommand *cmd = async_command_alloc(dispatcher, message, cookie);
RedWorkerMessageUpdateAsync payload;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &cmd, sizeof(cmd));
send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
send_data(dispatcher->channel, qxl_area, sizeof(QXLRect));
send_data(dispatcher->channel, &clear_dirty_region, sizeof(uint32_t));
payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
payload.surface_id = surface_id;
payload.qxl_area = *qxl_area;
payload.clear_dirty_region = clear_dirty_region;
dispatcher_send_message(&dispatcher->dispatcher,
message,
&payload);
}
static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
@ -316,12 +328,12 @@ static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
static void red_dispatcher_add_memslot(RedDispatcher *dispatcher, QXLDevMemSlot *mem_slot)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT;
RedWorkerMessageAddMemslot payload;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, mem_slot, sizeof(QXLDevMemSlot));
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
payload.mem_slot = *mem_slot;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_ADD_MEMSLOT,
&payload);
}
static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
@ -331,21 +343,22 @@ static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slo
static void red_dispatcher_add_memslot_async(RedDispatcher *dispatcher, QXLDevMemSlot *mem_slot, uint64_t cookie)
{
RedWorkerMessageAddMemslotAsync payload;
RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC;
AsyncCommand *cmd = async_command_alloc(dispatcher, message, cookie);
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &cmd, sizeof(cmd));
send_data(dispatcher->channel, mem_slot, sizeof(QXLDevMemSlot));
payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
payload.mem_slot = *mem_slot;
dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
}
static void red_dispatcher_del_memslot(RedDispatcher *dispatcher, uint32_t slot_group_id, uint32_t slot_id)
{
RedWorkerMessageDelMemslot payload;
RedWorkerMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT;
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &slot_group_id, sizeof(uint32_t));
send_data(dispatcher->channel, &slot_id, sizeof(uint32_t));
payload.slot_group_id = slot_group_id;
payload.slot_id = slot_id;
dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
}
static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id, uint32_t slot_id)
@ -355,11 +368,11 @@ static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id
static void red_dispatcher_destroy_surfaces(RedDispatcher *dispatcher)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES;
RedWorkerMessageDestroySurfaces payload;
write_message(dispatcher->channel, &message);
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_DESTROY_SURFACES,
&payload);
}
static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
@ -369,11 +382,11 @@ static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
static void red_dispatcher_destroy_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie)
{
RedWorkerMessageDestroySurfacesAsync payload;
RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC;
AsyncCommand *cmd = async_command_alloc(dispatcher, message, cookie);
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &cmd, sizeof(cmd));
payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
}
static void red_dispatcher_destroy_primary_surface_complete(RedDispatcher *dispatcher)
@ -386,29 +399,38 @@ static void red_dispatcher_destroy_primary_surface_complete(RedDispatcher *dispa
update_client_mouse_allowed();
}
static void
red_dispatcher_destroy_primary_surface_sync(RedDispatcher *dispatcher,
uint32_t surface_id)
{
RedWorkerMessageDestroyPrimarySurface payload;
payload.surface_id = surface_id;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE,
&payload);
red_dispatcher_destroy_primary_surface_complete(dispatcher);
}
static void
red_dispatcher_destroy_primary_surface_async(RedDispatcher *dispatcher,
uint32_t surface_id, uint64_t cookie)
{
RedWorkerMessageDestroyPrimarySurfaceAsync payload;
RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC;
payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
payload.surface_id = surface_id;
dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
}
static void
red_dispatcher_destroy_primary_surface(RedDispatcher *dispatcher,
uint32_t surface_id, int async, uint64_t cookie)
{
RedWorkerMessage message;
AsyncCommand *cmd = NULL;
if (async) {
message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC;
cmd = async_command_alloc(dispatcher, message, cookie);
red_dispatcher_destroy_primary_surface_async(dispatcher, surface_id, cookie);
} else {
message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
}
write_message(dispatcher->channel, &message);
if (async) {
send_data(dispatcher->channel, &cmd, sizeof(cmd));
}
send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
if (!async) {
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
red_dispatcher_destroy_primary_surface_complete(dispatcher);
red_dispatcher_destroy_primary_surface_sync(dispatcher, surface_id);
}
}
@ -430,31 +452,43 @@ static void red_dispatcher_create_primary_surface_complete(RedDispatcher *dispat
memset(&dispatcher->surface_create, 0, sizeof(QXLDevSurfaceCreate));
}
static void
red_dispatcher_create_primary_surface_async(RedDispatcher *dispatcher, uint32_t surface_id,
QXLDevSurfaceCreate *surface, uint64_t cookie)
{
RedWorkerMessageCreatePrimarySurfaceAsync payload;
RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC;
dispatcher->surface_create = *surface;
payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
payload.surface_id = surface_id;
payload.surface = *surface;
dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
}
static void
red_dispatcher_create_primary_surface_sync(RedDispatcher *dispatcher, uint32_t surface_id,
QXLDevSurfaceCreate *surface)
{
RedWorkerMessageCreatePrimarySurface payload;
dispatcher->surface_create = *surface;
payload.surface_id = surface_id;
payload.surface = *surface;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE,
&payload);
red_dispatcher_create_primary_surface_complete(dispatcher);
}
static void
red_dispatcher_create_primary_surface(RedDispatcher *dispatcher, uint32_t surface_id,
QXLDevSurfaceCreate *surface, int async, uint64_t cookie)
{
RedWorkerMessage message;
AsyncCommand *cmd = NULL;
if (async) {
message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC;
cmd = async_command_alloc(dispatcher, message, cookie);
red_dispatcher_create_primary_surface_async(dispatcher, surface_id, surface, cookie);
} else {
message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
}
dispatcher->surface_create = *surface;
write_message(dispatcher->channel, &message);
if (async) {
send_data(dispatcher->channel, &cmd, sizeof(cmd));
}
send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
send_data(dispatcher->channel, surface, sizeof(QXLDevSurfaceCreate));
if (!async) {
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
red_dispatcher_create_primary_surface_complete(dispatcher);
red_dispatcher_create_primary_surface_sync(dispatcher, surface_id, surface);
}
}
@ -466,11 +500,11 @@ static void qxl_worker_create_primary_surface(QXLWorker *qxl_worker, uint32_t su
static void red_dispatcher_reset_image_cache(RedDispatcher *dispatcher)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_IMAGE_CACHE;
RedWorkerMessageResetImageCache payload;
write_message(dispatcher->channel, &message);
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
&payload);
}
static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
@ -480,11 +514,11 @@ static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
static void red_dispatcher_reset_cursor(RedDispatcher *dispatcher)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_CURSOR;
RedWorkerMessageResetCursor payload;
write_message(dispatcher->channel, &message);
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_RESET_CURSOR,
&payload);
}
static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
@ -492,29 +526,38 @@ static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
red_dispatcher_reset_cursor((RedDispatcher*)qxl_worker);
}
static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id,
static void red_dispatcher_destroy_surface_wait_sync(RedDispatcher *dispatcher,
uint32_t surface_id)
{
RedWorkerMessageDestroySurfaceWait payload;
payload.surface_id = surface_id;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
&payload);
}
static void red_dispatcher_destroy_surface_wait_async(RedDispatcher *dispatcher,
uint32_t surface_id,
uint64_t cookie)
{
RedWorkerMessageDestroySurfaceWaitAsync payload;
RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC;
payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
payload.surface_id = surface_id;
dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
}
static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher,
uint32_t surface_id,
int async, uint64_t cookie)
{
RedWorkerMessage message;
AsyncCommand *cmd = NULL;
if (async ) {
message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC;
cmd = async_command_alloc(dispatcher, message, cookie);
if (async) {
red_dispatcher_destroy_surface_wait_async(dispatcher, surface_id, cookie);
} else {
message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
red_dispatcher_destroy_surface_wait_sync(dispatcher, surface_id);
}
write_message(dispatcher->channel, &message);
if (async) {
send_data(dispatcher->channel, &cmd, sizeof(cmd));
}
send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
if (async) {
return;
}
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
}
static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
@ -524,9 +567,11 @@ static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surf
static void red_dispatcher_reset_memslots(RedDispatcher *dispatcher)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_MEMSLOTS;
RedWorkerMessageResetMemslots payload;
write_message(dispatcher->channel, &message);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_RESET_MEMSLOTS,
&payload);
}
static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
@ -536,11 +581,15 @@ static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
static void red_dispatcher_wakeup(RedDispatcher *dispatcher)
{
if (!test_bit(RED_WORKER_PENDING_WAKEUP, dispatcher->pending)) {
RedWorkerMessage message = RED_WORKER_MESSAGE_WAKEUP;
set_bit(RED_WORKER_PENDING_WAKEUP, &dispatcher->pending);
write_message(dispatcher->channel, &message);
RedWorkerMessageWakeup payload;
if (test_bit(RED_WORKER_PENDING_WAKEUP, dispatcher->pending)) {
return;
}
set_bit(RED_WORKER_PENDING_WAKEUP, &dispatcher->pending);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_WAKEUP,
&payload);
}
static void qxl_worker_wakeup(QXLWorker *qxl_worker)
@ -550,11 +599,15 @@ static void qxl_worker_wakeup(QXLWorker *qxl_worker)
static void red_dispatcher_oom(RedDispatcher *dispatcher)
{
if (!test_bit(RED_WORKER_PENDING_OOM, dispatcher->pending)) {
RedWorkerMessage message = RED_WORKER_MESSAGE_OOM;
set_bit(RED_WORKER_PENDING_OOM, &dispatcher->pending);
write_message(dispatcher->channel, &message);
RedWorkerMessageOom payload;
if (test_bit(RED_WORKER_PENDING_OOM, dispatcher->pending)) {
return;
}
set_bit(RED_WORKER_PENDING_OOM, &dispatcher->pending);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_OOM,
&payload);
}
static void qxl_worker_oom(QXLWorker *qxl_worker)
@ -564,9 +617,11 @@ static void qxl_worker_oom(QXLWorker *qxl_worker)
static void red_dispatcher_start(RedDispatcher *dispatcher)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_START;
RedWorkerMessageStart payload;
write_message(dispatcher->channel, &message);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_START,
&payload);
}
static void qxl_worker_start(QXLWorker *qxl_worker)
@ -576,20 +631,20 @@ static void qxl_worker_start(QXLWorker *qxl_worker)
static void red_dispatcher_flush_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie)
{
RedWorkerMessageFlushSurfacesAsync payload;
RedWorkerMessage message = RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC;
AsyncCommand *cmd = async_command_alloc(dispatcher, message, cookie);
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &cmd, sizeof(cmd));
payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
}
static void red_dispatcher_stop(RedDispatcher *dispatcher)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_STOP;
RedWorkerMessageStop payload;
write_message(dispatcher->channel, &message);
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_STOP,
&payload);
}
static void qxl_worker_stop(QXLWorker *qxl_worker)
@ -601,14 +656,14 @@ static void red_dispatcher_loadvm_commands(RedDispatcher *dispatcher,
struct QXLCommandExt *ext,
uint32_t count)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_LOADVM_COMMANDS;
RedWorkerMessageLoadvmCommands payload;
red_printf("");
write_message(dispatcher->channel, &message);
send_data(dispatcher->channel, &count, sizeof(uint32_t));
send_data(dispatcher->channel, ext, sizeof(QXLCommandExt) * count);
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
payload.count = count;
payload.ext = ext;
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_LOADVM_COMMANDS,
&payload);
}
static void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
@ -640,37 +695,44 @@ static inline int calc_compression_level(void)
void red_dispatcher_on_ic_change(void)
{
RedWorkerMessageSetCompression payload;
int compression_level = calc_compression_level();
RedDispatcher *now = dispatchers;
while (now) {
RedWorkerMessage message = RED_WORKER_MESSAGE_SET_COMPRESSION;
now->qxl->st->qif->set_compression_level(now->qxl, compression_level);
write_message(now->channel, &message);
send_data(now->channel, &image_compression, sizeof(spice_image_compression_t));
payload.image_compression = image_compression;
dispatcher_send_message(&now->dispatcher,
RED_WORKER_MESSAGE_SET_COMPRESSION,
&payload);
now = now->next;
}
}
void red_dispatcher_on_sv_change(void)
{
RedWorkerMessageSetStreamingVideo payload;
int compression_level = calc_compression_level();
RedDispatcher *now = dispatchers;
while (now) {
RedWorkerMessage message = RED_WORKER_MESSAGE_SET_STREAMING_VIDEO;
now->qxl->st->qif->set_compression_level(now->qxl, compression_level);
write_message(now->channel, &message);
send_data(now->channel, &streaming_video, sizeof(uint32_t));
payload.streaming_video = streaming_video;
dispatcher_send_message(&now->dispatcher,
RED_WORKER_MESSAGE_SET_STREAMING_VIDEO,
&payload);
now = now->next;
}
}
void red_dispatcher_set_mouse_mode(uint32_t mode)
{
RedWorkerMessageSetMouseMode payload;
RedDispatcher *now = dispatchers;
while (now) {
RedWorkerMessage message = RED_WORKER_MESSAGE_SET_MOUSE_MODE;
write_message(now->channel, &message);
send_data(now->channel, &mode, sizeof(uint32_t));
payload.mode = mode;
dispatcher_send_message(&now->dispatcher,
RED_WORKER_MESSAGE_SET_MOUSE_MODE,
&payload);
now = now->next;
}
}
@ -873,34 +935,31 @@ void red_dispatcher_async_complete(struct RedDispatcher *dispatcher,
static RedChannel *red_dispatcher_display_channel_create(RedDispatcher *dispatcher)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_DISPLAY_CHANNEL_CREATE;
RedWorkerMessageDisplayChannelCreate payload;
RedChannel *display_channel;
write_message(dispatcher->channel, &message);
receive_data(dispatcher->channel, &display_channel, sizeof(RedChannel *));
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_DISPLAY_CHANNEL_CREATE,
&payload);
receive_data(dispatcher->dispatcher.send_fd, &display_channel, sizeof(RedChannel *));
return display_channel;
}
static RedChannel *red_dispatcher_cursor_channel_create(RedDispatcher *dispatcher)
{
RedWorkerMessage message = RED_WORKER_MESSAGE_CURSOR_CHANNEL_CREATE;
RedWorkerMessageCursorChannelCreate payload;
RedChannel *cursor_channel;
write_message(dispatcher->channel, &message);
receive_data(dispatcher->channel, &cursor_channel, sizeof(RedChannel *));
read_message(dispatcher->channel, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
dispatcher_send_message(&dispatcher->dispatcher,
RED_WORKER_MESSAGE_CURSOR_CHANNEL_CREATE,
&payload);
receive_data(dispatcher->dispatcher.send_fd, &cursor_channel, sizeof(RedChannel *));
return cursor_channel;
}
RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
{
RedDispatcher *dispatcher;
int channels[2];
RedDispatcher *red_dispatcher;
RedWorkerMessage message;
WorkerInitData init_data;
QXLDevInitInfo init_info;
@ -917,45 +976,41 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
gl_canvas_init();
#endif // USE_OPENGL
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, channels) == -1) {
red_error("socketpair failed %s", strerror(errno));
}
dispatcher = spice_new0(RedDispatcher, 1);
dispatcher->channel = channels[0];
ring_init(&dispatcher->async_commands);
DBG_ASYNC("dispatcher->async_commands.next %p", dispatcher->async_commands.next);
init_data.qxl = dispatcher->qxl = qxl;
red_dispatcher = spice_new0(RedDispatcher, 1);
ring_init(&red_dispatcher->async_commands);
DBG_ASYNC("red_dispatcher->async_commands.next %p", red_dispatcher->async_commands.next);
dispatcher_init(&red_dispatcher->dispatcher, RED_WORKER_MESSAGE_COUNT, NULL);
init_data.qxl = red_dispatcher->qxl = qxl;
init_data.id = qxl->id;
init_data.channel = channels[1];
init_data.pending = &dispatcher->pending;
init_data.red_dispatcher = red_dispatcher;
init_data.pending = &red_dispatcher->pending;
init_data.num_renderers = num_renderers;
memcpy(init_data.renderers, renderers, sizeof(init_data.renderers));
pthread_mutex_init(&dispatcher->async_lock, NULL);
pthread_mutex_init(&red_dispatcher->async_lock, NULL);
init_data.image_compression = image_compression;
init_data.jpeg_state = jpeg_state;
init_data.zlib_glz_state = zlib_glz_state;
init_data.streaming_video = streaming_video;
dispatcher->base.major_version = SPICE_INTERFACE_QXL_MAJOR;
dispatcher->base.minor_version = SPICE_INTERFACE_QXL_MINOR;
dispatcher->base.wakeup = qxl_worker_wakeup;
dispatcher->base.oom = qxl_worker_oom;
dispatcher->base.start = qxl_worker_start;
dispatcher->base.stop = qxl_worker_stop;
dispatcher->base.update_area = qxl_worker_update_area;
dispatcher->base.add_memslot = qxl_worker_add_memslot;
dispatcher->base.del_memslot = qxl_worker_del_memslot;
dispatcher->base.reset_memslots = qxl_worker_reset_memslots;
dispatcher->base.destroy_surfaces = qxl_worker_destroy_surfaces;
dispatcher->base.create_primary_surface = qxl_worker_create_primary_surface;
dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary_surface;
red_dispatcher->base.major_version = SPICE_INTERFACE_QXL_MAJOR;
red_dispatcher->base.minor_version = SPICE_INTERFACE_QXL_MINOR;
red_dispatcher->base.wakeup = qxl_worker_wakeup;
red_dispatcher->base.oom = qxl_worker_oom;
red_dispatcher->base.start = qxl_worker_start;
red_dispatcher->base.stop = qxl_worker_stop;
red_dispatcher->base.update_area = qxl_worker_update_area;
red_dispatcher->base.add_memslot = qxl_worker_add_memslot;
red_dispatcher->base.del_memslot = qxl_worker_del_memslot;
red_dispatcher->base.reset_memslots = qxl_worker_reset_memslots;
red_dispatcher->base.destroy_surfaces = qxl_worker_destroy_surfaces;
red_dispatcher->base.create_primary_surface = qxl_worker_create_primary_surface;
red_dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary_surface;
dispatcher->base.reset_image_cache = qxl_worker_reset_image_cache;
dispatcher->base.reset_cursor = qxl_worker_reset_cursor;
dispatcher->base.destroy_surface_wait = qxl_worker_destroy_surface_wait;
dispatcher->base.loadvm_commands = qxl_worker_loadvm_commands;
red_dispatcher->base.reset_image_cache = qxl_worker_reset_image_cache;
red_dispatcher->base.reset_cursor = qxl_worker_reset_cursor;
red_dispatcher->base.destroy_surface_wait = qxl_worker_destroy_surface_wait;
red_dispatcher->base.loadvm_commands = qxl_worker_loadvm_commands;
qxl->st->qif->get_init_info(qxl, &init_info);
@ -965,7 +1020,6 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
init_data.num_memslots_groups = init_info.num_memslots_groups;
init_data.internal_groupslot_id = init_info.internal_groupslot_id;
init_data.n_surfaces = init_info.n_surfaces;
init_data.dispatcher = dispatcher;
num_active_workers = 1;
@ -974,40 +1028,51 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
sigdelset(&thread_sig_mask, SIGFPE);
sigdelset(&thread_sig_mask, SIGSEGV);
pthread_sigmask(SIG_SETMASK, &thread_sig_mask, &curr_sig_mask);
if ((r = pthread_create(&dispatcher->worker_thread, NULL, red_worker_main, &init_data))) {
if ((r = pthread_create(&red_dispatcher->worker_thread, NULL, red_worker_main, &init_data))) {
red_error("create thread failed %d", r);
}
pthread_sigmask(SIG_SETMASK, &curr_sig_mask, NULL);
read_message(dispatcher->channel, &message);
read_message(red_dispatcher->dispatcher.send_fd, &message);
ASSERT(message == RED_WORKER_MESSAGE_READY);
display_channel = red_dispatcher_display_channel_create(dispatcher);
display_channel = red_dispatcher_display_channel_create(red_dispatcher);
if (display_channel) {
client_cbs.connect = red_dispatcher_set_display_peer;
client_cbs.disconnect = red_dispatcher_disconnect_display_peer;
client_cbs.migrate = red_dispatcher_display_migrate;
red_channel_register_client_cbs(display_channel, &client_cbs);
red_channel_set_data(display_channel, dispatcher);
red_channel_set_data(display_channel, red_dispatcher);
reds_register_channel(display_channel);
}
cursor_channel = red_dispatcher_cursor_channel_create(dispatcher);
cursor_channel = red_dispatcher_cursor_channel_create(red_dispatcher);
if (cursor_channel) {
client_cbs.connect = red_dispatcher_set_cursor_peer;
client_cbs.disconnect = red_dispatcher_disconnect_cursor_peer;
client_cbs.migrate = red_dispatcher_cursor_migrate;
red_channel_register_client_cbs(cursor_channel, &client_cbs);
red_channel_set_data(cursor_channel, dispatcher);
red_channel_set_data(cursor_channel, red_dispatcher);
reds_register_channel(cursor_channel);
}
qxl->st->qif->attache_worker(qxl, &dispatcher->base);
qxl->st->qif->attache_worker(qxl, &red_dispatcher->base);
qxl->st->qif->set_compression_level(qxl, calc_compression_level());
dispatcher->next = dispatchers;
dispatchers = dispatcher;
return dispatcher;
red_dispatcher->next = dispatchers;
dispatchers = red_dispatcher;
return red_dispatcher;
}
struct Dispatcher *red_dispatcher_get_dispatcher(RedDispatcher *red_dispatcher)
{
return &red_dispatcher->dispatcher;
}
void red_dispatcher_set_dispatcher_opaque(struct RedDispatcher *red_dispatcher,
void *opaque)
{
dispatcher_set_opaque(&red_dispatcher->dispatcher, opaque);
}

View File

@ -32,5 +32,154 @@ int red_dispatcher_add_renderer(const char *name);
uint32_t red_dispatcher_qxl_ram_size(void);
int red_dispatcher_qxl_count(void);
void red_dispatcher_async_complete(struct RedDispatcher *, AsyncCommand *);
struct Dispatcher *red_dispatcher_get_dispatcher(struct RedDispatcher *);
typedef struct RedWorkerMessageDisplayConnect {
RedClient * client;
RedsStream * stream;
int migration;
} RedWorkerMessageDisplayConnect;
typedef struct RedWorkerMessageDisplayDisconnect {
RedChannelClient *rcc;
} RedWorkerMessageDisplayDisconnect;
typedef struct RedWorkerMessageDisplayMigrate {
RedChannelClient *rcc;
} RedWorkerMessageDisplayMigrate;
typedef struct RedWorkerMessageCursorConnect {
RedClient *client;
RedsStream *stream;
int migration;
} RedWorkerMessageCursorConnect;
typedef struct RedWorkerMessageCursorDisconnect {
RedChannelClient *rcc;
} RedWorkerMessageCursorDisconnect;
typedef struct RedWorkerMessageCursorMigrate {
RedChannelClient *rcc;
} RedWorkerMessageCursorMigrate;
typedef struct RedWorkerMessageUpdate {
uint32_t surface_id;
QXLRect * qxl_area;
QXLRect * qxl_dirty_rects;
uint32_t num_dirty_rects;
uint32_t clear_dirty_region;
} RedWorkerMessageUpdate;
typedef struct RedWorkerMessageAsync {
AsyncCommand *cmd;
} RedWorkerMessageAsync;
typedef struct RedWorkerMessageUpdateAsync {
RedWorkerMessageAsync base;
uint32_t surface_id;
QXLRect qxl_area;
uint32_t clear_dirty_region;
} RedWorkerMessageUpdateAsync;
typedef struct RedWorkerMessageAddMemslot {
QXLDevMemSlot mem_slot;
} RedWorkerMessageAddMemslot;
typedef struct RedWorkerMessageAddMemslotAsync {
RedWorkerMessageAsync base;
QXLDevMemSlot mem_slot;
} RedWorkerMessageAddMemslotAsync;
typedef struct RedWorkerMessageDelMemslot {
uint32_t slot_group_id;
uint32_t slot_id;
} RedWorkerMessageDelMemslot;
typedef struct RedWorkerMessageDestroySurfaces {
} RedWorkerMessageDestroySurfaces;
typedef struct RedWorkerMessageDestroySurfacesAsync {
RedWorkerMessageAsync base;
} RedWorkerMessageDestroySurfacesAsync;
typedef struct RedWorkerMessageDestroyPrimarySurface {
uint32_t surface_id;
} RedWorkerMessageDestroyPrimarySurface;
typedef struct RedWorkerMessageDestroyPrimarySurfaceAsync {
RedWorkerMessageAsync base;
uint32_t surface_id;
} RedWorkerMessageDestroyPrimarySurfaceAsync;
typedef struct RedWorkerMessageCreatePrimarySurfaceAsync {
RedWorkerMessageAsync base;
uint32_t surface_id;
QXLDevSurfaceCreate surface;
} RedWorkerMessageCreatePrimarySurfaceAsync;
typedef struct RedWorkerMessageCreatePrimarySurface {
uint32_t surface_id;
QXLDevSurfaceCreate surface;
} RedWorkerMessageCreatePrimarySurface;
typedef struct RedWorkerMessageResetImageCache {
} RedWorkerMessageResetImageCache;
typedef struct RedWorkerMessageResetCursor {
} RedWorkerMessageResetCursor;
typedef struct RedWorkerMessageWakeup {
} RedWorkerMessageWakeup;
typedef struct RedWorkerMessageOom {
} RedWorkerMessageOom;
typedef struct RedWorkerMessageStart {
} RedWorkerMessageStart;
typedef struct RedWorkerMessageFlushSurfacesAsync {
RedWorkerMessageAsync base;
} RedWorkerMessageFlushSurfacesAsync;
typedef struct RedWorkerMessageStop {
} RedWorkerMessageStop;
/* this command is sync, so it's ok to pass a pointer */
typedef struct RedWorkerMessageLoadvmCommands {
uint32_t count;
QXLCommandExt *ext;
} RedWorkerMessageLoadvmCommands;
typedef struct RedWorkerMessageSetCompression {
spice_image_compression_t image_compression;
} RedWorkerMessageSetCompression;
typedef struct RedWorkerMessageSetStreamingVideo {
uint32_t streaming_video;
} RedWorkerMessageSetStreamingVideo;
typedef struct RedWorkerMessageSetMouseMode {
uint32_t mode;
} RedWorkerMessageSetMouseMode;
typedef struct RedWorkerMessageDisplayChannelCreate {
} RedWorkerMessageDisplayChannelCreate;
typedef struct RedWorkerMessageCursorChannelCreate {
} RedWorkerMessageCursorChannelCreate;
typedef struct RedWorkerMessageDestroySurfaceWait {
uint32_t surface_id;
} RedWorkerMessageDestroySurfaceWait;
typedef struct RedWorkerMessageDestroySurfaceWaitAsync {
RedWorkerMessageAsync base;
uint32_t surface_id;
} RedWorkerMessageDestroySurfaceWaitAsync;
typedef struct RedWorkerMessageResetMemslots {
} RedWorkerMessageResetMemslots;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -84,6 +84,8 @@ enum {
RED_WORKER_MESSAGE_DISPLAY_CHANNEL_CREATE,
RED_WORKER_MESSAGE_CURSOR_CHANNEL_CREATE,
RED_WORKER_MESSAGE_COUNT // LAST
};
typedef uint32_t RedWorkerMessage;
@ -102,7 +104,6 @@ typedef struct RedDispatcher RedDispatcher;
typedef struct WorkerInitData {
struct QXLInstance *qxl;
int id;
int channel;
uint32_t *pending;
uint32_t num_renderers;
uint32_t renderers[RED_MAX_RENDERERS];
@ -116,7 +117,7 @@ typedef struct WorkerInitData {
uint8_t memslot_id_bits;
uint8_t internal_groupslot_id;
uint32_t n_surfaces;
RedDispatcher *dispatcher;
RedDispatcher *red_dispatcher;
} WorkerInitData;
void *red_worker_main(void *arg);