xenocara/app/lbxproxy/di/lbxutil.c
2006-11-26 14:07:37 +00:00

510 lines
13 KiB
C

/* $Xorg: lbxutil.c,v 1.4 2000/08/17 19:53:55 cpqbld Exp $ */
/*
* Copyright 1994 Network Computing Devices, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name Network Computing Devices, Inc. not be
* used in advertising or publicity pertaining to distribution of this
* software without specific, written prior permission.
*
* THIS SOFTWARE IS PROVIDED `AS-IS'. NETWORK COMPUTING DEVICES, INC.,
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
* LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK
* COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
* SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
* OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
* WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/* $XFree86$ */
/*
* utility routines for LBX requests
*/
#include <stdio.h>
#include "misc.h"
#include "assert.h"
#include "lbx.h"
#include "util.h"
#include "tags.h"
#include "resource.h"
#include "wire.h"
#include "swap.h"
#include "colormap.h"
Bool compStats = FALSE; /* report stream compression statistics */
#ifdef DEBUG
extern int lbxDebug;
#endif
extern int lbxMaxMotionEvents;
ReplyStuffPtr
NewReply(client, major, minor, reply_func)
ClientPtr client;
int major;
int minor;
ReplyFunc reply_func;
{
ReplyStuffPtr new,
*end;
new = (ReplyStuffPtr) xalloc(sizeof(ReplyStuffRec));
if (!new)
return new;
new->sequenceNumber = LBXSequenceNumber(client);
new->major = major;
new->minor = minor;
new->reply_func = reply_func;
new->next = NULL;
end = &LBXReplyList(client);
while (*end)
end = &(*end)->next;
*end = new;
return new;
}
void
RemoveReply(client, rp)
ClientPtr client;
ReplyStuffPtr rp;
{
ReplyStuffPtr cur, *prev;
prev = &LBXReplyList(client);
while ((cur = *prev) != rp)
prev = &cur->next;
*prev = cur->next;
if (cur->major == client->server->lbxReq) {
if (CacheTrimNeeded(client->server, client->server->global_cache) &&
!AnyTagBearingReplies(client->server, client->server->global_cache))
CacheTrim(client->server, client->server->global_cache);
if (CacheTrimNeeded(client->server, client->server->prop_cache) &&
!AnyTagBearingReplies(client->server, client->server->prop_cache))
CacheTrim(client->server, client->server->prop_cache);
}
xfree(cur);
}
ReplyStuffPtr
GetMatchingReply(client, seqno, flush_older)
ClientPtr client;
int seqno;
Bool flush_older;
{
ReplyStuffPtr t, old;
seqno &= 0xffff;
for (t = LBXReplyList(client); t; t = t->next) {
if ((t->sequenceNumber & 0xffff) == seqno)
break;
}
#ifdef SEQ_DEBUG
if (t)
fprintf(stderr, "matched reply for seq 0x%x\n", seqno);
else
fprintf(stderr, "no reply for seq 0x%x\n", seqno);
#endif
if (t && flush_older) {
while ((old = LBXReplyList(client)) != t) {
fprintf(stderr,
"unclaimed reply: maj %d min %d seq 0x%x curseq 0x%x\n",
old->major, old->minor, old->sequenceNumber, seqno);
LBXReplyList(client) = old->next;
xfree(old);
}
}
return t;
}
Bool
AnyReplies(client)
ClientPtr client;
{
return (LBXReplyList(client) != NULL);
}
Bool
AnyTagBearingReplies(server, cache)
XServerPtr server;
Cache cache;
{
int i;
int lbxreq;
ReplyStuffPtr t;
Bool found = FALSE;
/* assume this is called while a reply is being processed, so need two */
for (i = 1; i < currentMaxClients; i++)
{
if (!clients[i])
continue;
lbxreq = clients[i]->server->lbxReq;
for (t = LBXReplyList(clients[i]); t; t = t->next) {
if (t->major == lbxreq) {
switch (t->minor) {
case X_LbxGetModifierMapping:
case X_LbxGetKeyboardMapping:
case X_LbxQueryFont:
if (cache == server->global_cache) {
if (found)
return TRUE;
found = TRUE;
}
break;
case X_LbxGetProperty:
if (cache == server->prop_cache) {
if (found)
return TRUE;
found = TRUE;
}
break;
}
}
}
}
return FALSE;
}
/*
* this is used for stashing short-circuited replies for later.
* it currently assumes that all of them will be 32 bytes for the reply
* plus some amount of extra data
*/
Bool
SaveReplyData(client, rep, len, data)
ClientPtr client;
xReply *rep;
int len;
pointer data;
{
ReplyDataPtr new, *end;
new = (ReplyDataPtr) xalloc(sizeof(ReplyDataRec));
if (!new)
return FALSE;
if (len) {
new->data = (pointer) xalloc(len);
if (!new->data) {
xfree(new);
return FALSE;
} else {
memcpy((char *) new->data, (char *) data, len);
}
}
new->reply = *rep;
new->dlen = len;
new->delay_seq_no = LBXSequenceNumber(client);
new->next = NULL;
end = &LBXReplyData(client);
while (*end)
end = &(*end)->next;
*end = new;
#ifdef SEQ_DEBUG
fprintf(stderr, "saving reply seq 0x%x\n", LBXSequenceNumber(client));
#endif
return TRUE;
}
Bool
FlushDelayedReplies(client)
ClientPtr client;
{
ReplyDataPtr *prev, cur;
#ifdef SEQ_DEBUG
fprintf(stderr, "flushing replies seq 0x%x:", LBXLastResponse(client));
#endif
for (prev = &LBXReplyData(client); (cur = *prev); ) {
#ifdef SEQ_DEBUG
fprintf(stderr, " 0x%x", cur->delay_seq_no);
#endif
if ((cur->delay_seq_no & 0xffff) == LBXLastResponse(client) + 1) {
WriteToClient(client, sizeof(xReply), (char *) &cur->reply);
if (cur->dlen)
WriteToClient(client, cur->dlen, (char *) cur->data);
LBXLastResponse(client) = cur->delay_seq_no;
*prev = cur->next;
xfree(cur);
}
else
prev = &cur->next;
}
#ifdef SEQ_DEBUG
fprintf(stderr, "\n");
#endif
return TRUE;
}
void
BumpSequence(client)
ClientPtr client;
{
DBG(DBG_CLIENT, (stderr, "bumping client %d sequence by %d to %d\n",
client->index, LBXSequenceLost(client), LBXSequenceNumber(client)));
ModifySequence(client, LBXSequenceLost(client));
LBXSequenceLost(client) = 0;
}
void
ForceSequenceUpdate(client)
ClientPtr client;
{
if (LBXSequenceLost(client)) {
BumpSequence(client);
}
}
void
LbxFreeTag(server, tag, tagtype)
XServerPtr server;
XID tag;
int tagtype;
{
Cache tag_cache;
switch (tagtype) {
case LbxTagTypeProperty:
tag_cache = server->prop_cache;
break;
case LbxTagTypeFont:
case LbxTagTypeModmap:
case LbxTagTypeKeymap:
case LbxTagTypeConnInfo:
tag_cache = server->global_cache;
break;
default:
fprintf(stderr,
"unknown type in InvalidateTag request: tag 0x%lx type %d\n",
(long)tag, tagtype);
return;
}
TagFreeData(server, tag_cache, tag, TRUE);
}
void
LbxSendTagData(client, tag, tagtype)
ClientPtr client;
XID tag;
int tagtype;
{
TagData td;
unsigned long len;
pointer tdata;
PropertyTagDataPtr ptdp;
if (tagtype == LbxTagTypeProperty && (td = TagGetTag(client->server,
client->server->prop_cache, tag))) {
ptdp = (PropertyTagDataPtr) td->tdata;
tdata = ptdp->data;
len = ptdp->length;
} else {
fprintf(stderr, "invalid SendTagData request: tag 0x%lx type %d\n",
(long)tag, tagtype);
len = 0;
tdata = NULL;
}
SendTagData(client, tag, len, tdata);
}
extern unsigned long stream_out_compressed;
extern unsigned long stream_out_uncompressed;
extern unsigned long stream_out_plain;
extern unsigned long stream_in_compressed;
extern unsigned long stream_in_uncompressed;
extern unsigned long stream_in_plain;
extern unsigned long raw_stream_out;
extern unsigned long raw_stream_in;
void
DumpCompressionStats()
{
if (raw_stream_out && stream_out_plain) {
fprintf(stderr, "Requests: normal = %ld, reencoded = %ld",
(long)raw_stream_out, (long)stream_out_plain);
stream_out_compressed += stream_out_uncompressed;
if (stream_out_compressed)
fprintf(stderr, ", compressed = %ld", (long)stream_out_compressed);
else
stream_out_compressed = stream_out_plain;
fprintf(stderr, "\n %.2f:1 overall reduction ratio\n",
(float)raw_stream_out / (float)stream_out_compressed);
}
if (raw_stream_in && stream_in_plain) {
fprintf(stderr, "Responses: normal = %ld, reencoded = %ld",
(long)raw_stream_in, (long)stream_in_plain);
stream_in_compressed += stream_in_uncompressed;
if (stream_in_compressed)
fprintf(stderr, ", compressed = %ld", (long)stream_in_compressed);
else
stream_in_compressed = stream_in_plain;
fprintf(stderr, "\n %.2f:1 overall reduction ratio\n",
(float)raw_stream_in / (float)stream_in_compressed);
}
}
void
ZeroCompressionStats()
{
stream_out_compressed = 0;
stream_out_uncompressed = 0;
stream_out_plain = 0;
stream_in_compressed = 0;
stream_in_uncompressed = 0;
stream_in_plain = 0;
raw_stream_out = 0;
raw_stream_in = 0;
}
#ifdef LBX_STATS
int intern_good,
intern_miss;
int getatom_good,
getatom_miss;
int luc_good,
luc_miss;
int ac_good,
ac_miss;
int anc_good,
anc_miss;
int getmodmap_tag, /* tag only */
getmodmap_full;
int getkeymap_tag, /* tag only */
getkeymap_full;
int queryfont_tag, /* tag only */
queryfont_full;
int getsetup_tag, /* tag only */
getsetup_full;
int getprop_tag,
getprop_full;
int tag_bytes_unsent; /* approx data kept off wire by tags */
int delta_out_total;
int delta_out_attempts;
int delta_out_hits;
int delta_in_total;
int delta_in_attempts;
int delta_in_hits;
extern int gfx_gc_hit;
extern int gfx_gc_miss;
extern int gfx_draw_hit;
extern int gfx_draw_miss;
extern int gfx_total;
void
DumpOtherStats()
{
fprintf(stderr, "Short-circuit stats\n");
fprintf(stderr, "InternAtom cache hits %d misses %d\n", intern_good, intern_miss);
fprintf(stderr, "GetAtomName cache hits %d misses %d\n", getatom_good, getatom_miss);
fprintf(stderr, "LookupColor cache hits %d misses %d\n", luc_good, luc_miss);
fprintf(stderr, "AllocColor cache hits %d misses %d\n", ac_good, ac_miss);
fprintf(stderr, "AllocNamedColor cache hits %d misses %d\n", anc_good, anc_miss);
fprintf(stderr, "Tag stats\n");
fprintf(stderr, "GetModifierMapping used tag %d, full data %d\n", getmodmap_tag, getmodmap_full);
fprintf(stderr, "GetKeyboardMapping used tag %d, full data %d\n", getkeymap_tag, getkeymap_full);
fprintf(stderr, "QueryFont used tag %d, full data %d\n", queryfont_tag, queryfont_full);
fprintf(stderr, "GetProperty used tag %d, full data %d\n", getprop_tag, getprop_full);
fprintf(stderr, "ConnectionSetup used tag %d, full data %d\n", getsetup_tag, getsetup_full);
fprintf(stderr, "Approx bytes kept off wire by tags %d\n", tag_bytes_unsent);
fprintf(stderr, "Delta Compressor stats\n");
fprintf(stderr, "Sent: total msgs = %d, cacheable = %d, cache hits = %d\n",
delta_out_total, delta_out_attempts, delta_out_hits);
fprintf(stderr, "Received: total = %d, cacheable = %d, cache hits = %d\n",
delta_in_total, delta_in_attempts, delta_in_hits);
fprintf(stderr, "GFX Cache stats\n");
fprintf(stderr, "Reencoded = %d\n", gfx_total);
#define percent(s,t) ((t) ? ((s) * 100) / (t) : 0)
#define ratios(h,m) (h), percent (h, (h)+(m)), (m), percent (m, (h) + (m))
fprintf(stderr, "Draw hit = %d (%d%%) miss = %d (%d%%) GC hit = %d (%d%%) miss = %d (%d%%)\n",
ratios (gfx_draw_hit, gfx_draw_miss),
ratios (gfx_gc_hit, gfx_gc_miss));
#define savings(h,m) (((h) + (m)) * 4) - ((h) + (m) * 5)
fprintf(stderr, "Total bytes saved = %d Draw = %d GC = %d\n",
savings (gfx_gc_hit + gfx_draw_hit, gfx_gc_miss + gfx_draw_miss),
savings (gfx_draw_hit, gfx_draw_miss),
savings (gfx_gc_hit, gfx_gc_miss));
}
void
ZeroOtherStats()
{
intern_good = intern_miss = 0;
getatom_good = getatom_miss = 0;
luc_good = luc_miss = 0;
ac_good = ac_miss = 0;
anc_good = anc_miss = 0;
getmodmap_tag = 0;
getmodmap_full = 0;
getkeymap_tag = 0;
getkeymap_full = 0;
getprop_tag = 0;
getprop_full = 0;
getsetup_tag = 0;
getsetup_full = 0;
delta_out_total = delta_out_attempts = delta_out_hits = 0;
delta_in_total = delta_in_attempts = delta_in_hits = 0;
gfx_gc_hit = 0;
gfx_gc_miss = 0;
gfx_draw_hit = 0;
gfx_draw_miss = 0;
gfx_total = 0;
}
#endif
void
SendInitLBXPackets(server)
XServerPtr server;
{
ZeroCompressionStats();
#ifdef LBX_STATS
ZeroOtherStats();
#endif
AllowMotion(server->serverClient, lbxMaxMotionEvents);
}
void
LbxCleanupSession()
{
if (compStats)
{
DumpCompressionStats();
ZeroCompressionStats();
}
#ifdef LBX_STATS
DumpOtherStats();
ZeroOtherStats();
#endif
}