mirror of
https://github.com/brl/mutter.git
synced 2024-12-26 21:02:14 +00:00
0201fcfc6c
2006-10-01 Elijah Newren <newren gmail com> * src/*.[ch]: Stick an emacs comment directive at the beginning of all the code files so that people using emacs will be more likely to get coding style correct in their patches. We still need a similar vi directive. #358866
498 lines
12 KiB
C
498 lines
12 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/*
|
|
* Copyright (C) 2002 Havoc Pennington
|
|
*
|
|
* 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.
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
|
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of The Open Group shall not be
|
|
* used in advertising or otherwise to promote the sale, use or other dealings
|
|
* in this Software without prior written authorization from The Open Group.
|
|
*/
|
|
|
|
#include "async-getprop.h"
|
|
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <assert.h>
|
|
|
|
#ifndef TRUE
|
|
#define TRUE 1
|
|
#endif
|
|
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#endif
|
|
|
|
#ifndef NULL
|
|
#define NULL ((void*) 0)
|
|
#endif
|
|
|
|
#ifdef HAVE_BACKTRACE
|
|
#include <execinfo.h>
|
|
static void
|
|
print_backtrace (void)
|
|
{
|
|
void *bt[500];
|
|
int bt_size;
|
|
int i;
|
|
char **syms;
|
|
|
|
bt_size = backtrace (bt, 500);
|
|
|
|
syms = backtrace_symbols (bt, bt_size);
|
|
|
|
i = 0;
|
|
while (i < bt_size)
|
|
{
|
|
fprintf (stderr, " %s\n", syms[i]);
|
|
++i;
|
|
}
|
|
|
|
free (syms);
|
|
}
|
|
#else
|
|
static void
|
|
print_backtrace (void)
|
|
{
|
|
fprintf (stderr, "Not compiled with backtrace support\n");
|
|
}
|
|
#endif
|
|
|
|
static int error_trap_depth = 0;
|
|
|
|
static int
|
|
x_error_handler (Display *xdisplay,
|
|
XErrorEvent *error)
|
|
{
|
|
char buf[64];
|
|
|
|
XGetErrorText (xdisplay, error->error_code, buf, 63);
|
|
|
|
if (error_trap_depth == 0)
|
|
{
|
|
print_backtrace ();
|
|
|
|
fprintf (stderr, "Unexpected X error: %s serial %ld error_code %d request_code %d minor_code %d)\n",
|
|
buf,
|
|
error->serial,
|
|
error->error_code,
|
|
error->request_code,
|
|
error->minor_code);
|
|
|
|
exit (1);
|
|
}
|
|
|
|
return 1; /* return value is meaningless */
|
|
}
|
|
|
|
static void
|
|
error_trap_push (Display *xdisplay)
|
|
{
|
|
++error_trap_depth;
|
|
}
|
|
|
|
static void
|
|
error_trap_pop (Display *xdisplay)
|
|
{
|
|
if (error_trap_depth == 0)
|
|
{
|
|
fprintf (stderr, "Error trap underflow!\n");
|
|
exit (1);
|
|
}
|
|
|
|
XSync (xdisplay, False); /* get all errors out of the queue */
|
|
--error_trap_depth;
|
|
}
|
|
|
|
static char*
|
|
my_strdup (const char *str)
|
|
{
|
|
char *s;
|
|
|
|
s = malloc (strlen (str) + 1);
|
|
if (s == NULL)
|
|
{
|
|
fprintf (stderr, "malloc failed\n");
|
|
exit (1);
|
|
}
|
|
strcpy (s, str);
|
|
|
|
return s;
|
|
}
|
|
|
|
static char*
|
|
atom_name (Display *display,
|
|
Atom atom)
|
|
{
|
|
if (atom == None)
|
|
{
|
|
return my_strdup ("None");
|
|
}
|
|
else
|
|
{
|
|
char *xname;
|
|
char *ret;
|
|
|
|
error_trap_push (display);
|
|
xname = XGetAtomName (display, atom);
|
|
error_trap_pop (display);
|
|
if (xname == NULL)
|
|
return my_strdup ("[unknown atom]");
|
|
|
|
ret = my_strdup (xname);
|
|
XFree (xname);
|
|
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
#define ELAPSED(start_time, current_time) \
|
|
(((((double)current_time.tv_sec - start_time.tv_sec) * 1000000 + \
|
|
(current_time.tv_usec - start_time.tv_usec))) / 1000.0)
|
|
|
|
static struct timeval program_start_time;
|
|
|
|
static Bool
|
|
try_get_reply (Display *xdisplay,
|
|
AgGetPropertyTask *task)
|
|
{
|
|
if (ag_task_have_reply (task))
|
|
{
|
|
int result;
|
|
Atom actual_type;
|
|
int actual_format;
|
|
unsigned long n_items;
|
|
unsigned long bytes_after;
|
|
char *data;
|
|
char *name;
|
|
struct timeval current_time;
|
|
|
|
gettimeofday (¤t_time, NULL);
|
|
|
|
printf (" %gms (we have a reply for property %ld)\n",
|
|
ELAPSED (program_start_time, current_time),
|
|
ag_task_get_property (task));
|
|
|
|
data = NULL;
|
|
|
|
name = atom_name (xdisplay,
|
|
ag_task_get_property (task));
|
|
printf (" %s on 0x%lx:\n", name,
|
|
ag_task_get_window (task));
|
|
free (name);
|
|
|
|
result = ag_task_get_reply_and_free (task,
|
|
&actual_type,
|
|
&actual_format,
|
|
&n_items,
|
|
&bytes_after,
|
|
&data);
|
|
task = NULL;
|
|
|
|
if (result != Success)
|
|
{
|
|
fprintf (stderr, " error code %d getting reply\n", result);
|
|
}
|
|
else
|
|
{
|
|
name = atom_name (xdisplay, actual_type);
|
|
printf (" actual_type = %s\n", name);
|
|
free (name);
|
|
|
|
printf (" actual_format = %d\n", actual_format);
|
|
|
|
printf (" n_items = %lu\n", n_items);
|
|
printf (" bytes_after = %lu\n", bytes_after);
|
|
|
|
printf (" data = \"%s\"\n", data ? (char*) data : "NULL");
|
|
}
|
|
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
static void run_speed_comparison (Display *xdisplay,
|
|
Window window);
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
Display *xdisplay;
|
|
int i;
|
|
int n_left;
|
|
int n_props;
|
|
Window window;
|
|
const char *window_str;
|
|
char *end;
|
|
Atom *props;
|
|
struct timeval current_time;
|
|
|
|
if (argc < 2)
|
|
{
|
|
fprintf (stderr, "specify window ID\n");
|
|
return 1;
|
|
}
|
|
|
|
window_str = argv[1];
|
|
|
|
end = NULL;
|
|
window = strtoul (window_str, &end, 0);
|
|
if (end == NULL || *end != '\0')
|
|
{
|
|
fprintf (stderr, "\"%s\" does not parse as a window ID\n", window_str);
|
|
return 1;
|
|
}
|
|
|
|
xdisplay = XOpenDisplay (NULL);
|
|
if (xdisplay == NULL)
|
|
{
|
|
fprintf (stderr, "Could not open display\n");
|
|
return 1;
|
|
}
|
|
|
|
if (getenv ("METACITY_SYNC") != NULL)
|
|
XSynchronize (xdisplay, True);
|
|
|
|
XSetErrorHandler (x_error_handler);
|
|
|
|
n_props = 0;
|
|
props = XListProperties (xdisplay, window, &n_props);
|
|
if (n_props == 0 || props == NULL)
|
|
{
|
|
fprintf (stderr, "Window has no properties\n");
|
|
return 1;
|
|
}
|
|
|
|
gettimeofday (&program_start_time, NULL);
|
|
|
|
i = 0;
|
|
while (i < n_props)
|
|
{
|
|
gettimeofday (¤t_time, NULL);
|
|
printf (" %gms (sending request for property %ld)\n",
|
|
ELAPSED (program_start_time, current_time),
|
|
props[i]);
|
|
if (ag_task_create (xdisplay,
|
|
window, props[i],
|
|
0, 0xffffffff,
|
|
False,
|
|
AnyPropertyType) == NULL)
|
|
{
|
|
fprintf (stderr, "Failed to send request\n");
|
|
return 1;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
XFree (props);
|
|
props = NULL;
|
|
|
|
n_left = n_props;
|
|
|
|
while (TRUE)
|
|
{
|
|
XEvent xevent;
|
|
int connection;
|
|
fd_set set;
|
|
AgGetPropertyTask *task;
|
|
|
|
/* Mop up event queue */
|
|
while (XPending (xdisplay) > 0)
|
|
{
|
|
XNextEvent (xdisplay, &xevent);
|
|
gettimeofday (¤t_time, NULL);
|
|
printf (" %gms (processing event type %d)\n",
|
|
ELAPSED (program_start_time, current_time),
|
|
xevent.xany.type);
|
|
}
|
|
|
|
while ((task = ag_get_next_completed_task (xdisplay)))
|
|
{
|
|
try_get_reply (xdisplay, task);
|
|
n_left -= 1;
|
|
}
|
|
|
|
if (n_left == 0)
|
|
{
|
|
printf ("All %d replies received.\n", n_props);
|
|
break;
|
|
}
|
|
|
|
/* Wake up if we may have a reply */
|
|
connection = ConnectionNumber (xdisplay);
|
|
|
|
FD_ZERO (&set);
|
|
FD_SET (connection, &set);
|
|
|
|
gettimeofday (¤t_time, NULL);
|
|
printf (" %gms (blocking for data %d left)\n",
|
|
ELAPSED (program_start_time, current_time), n_left);
|
|
select (connection + 1, &set, NULL, NULL, NULL);
|
|
}
|
|
|
|
run_speed_comparison (xdisplay, window);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* This function doesn't have all the printf's
|
|
* and other noise, it just compares async to sync
|
|
*/
|
|
static void
|
|
run_speed_comparison (Display *xdisplay,
|
|
Window window)
|
|
{
|
|
int i;
|
|
int n_props;
|
|
struct timeval start, end;
|
|
int n_left;
|
|
|
|
/* We just use atom values (0 to n_props) % 200, many are probably
|
|
* BadAtom, that's fine, but the %200 keeps most of them valid. The
|
|
* async case is about twice as advantageous when using valid atoms
|
|
* (or the issue may be that it's more advantageous when the
|
|
* properties are present and data is transmitted).
|
|
*/
|
|
n_props = 4000;
|
|
printf ("Timing with %d property requests\n", n_props);
|
|
|
|
gettimeofday (&start, NULL);
|
|
|
|
i = 0;
|
|
while (i < n_props)
|
|
{
|
|
if (ag_task_create (xdisplay,
|
|
window, (Atom) i % 200,
|
|
0, 0xffffffff,
|
|
False,
|
|
AnyPropertyType) == NULL)
|
|
{
|
|
fprintf (stderr, "Failed to send request\n");
|
|
exit (1);
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
n_left = n_props;
|
|
|
|
while (TRUE)
|
|
{
|
|
int connection;
|
|
fd_set set;
|
|
XEvent xevent;
|
|
AgGetPropertyTask *task;
|
|
|
|
/* Mop up event queue */
|
|
while (XPending (xdisplay) > 0)
|
|
XNextEvent (xdisplay, &xevent);
|
|
|
|
while ((task = ag_get_next_completed_task (xdisplay)))
|
|
{
|
|
int result;
|
|
Atom actual_type;
|
|
int actual_format;
|
|
unsigned long n_items;
|
|
unsigned long bytes_after;
|
|
char *data;
|
|
|
|
assert (ag_task_have_reply (task));
|
|
|
|
data = NULL;
|
|
result = ag_task_get_reply_and_free (task,
|
|
&actual_type,
|
|
&actual_format,
|
|
&n_items,
|
|
&bytes_after,
|
|
&data);
|
|
|
|
if (data)
|
|
XFree (data);
|
|
|
|
n_left -= 1;
|
|
}
|
|
|
|
if (n_left == 0)
|
|
break;
|
|
|
|
/* Wake up if we may have a reply */
|
|
connection = ConnectionNumber (xdisplay);
|
|
|
|
FD_ZERO (&set);
|
|
FD_SET (connection, &set);
|
|
|
|
select (connection + 1, &set, NULL, NULL, NULL);
|
|
}
|
|
|
|
gettimeofday (&end, NULL);
|
|
|
|
printf ("Async time: %gms\n",
|
|
ELAPSED (start, end));
|
|
|
|
gettimeofday (&start, NULL);
|
|
|
|
error_trap_push (xdisplay);
|
|
|
|
i = 0;
|
|
while (i < n_props)
|
|
{
|
|
Atom actual_type;
|
|
int actual_format;
|
|
unsigned long n_items;
|
|
unsigned long bytes_after;
|
|
unsigned char *data;
|
|
|
|
data = NULL;
|
|
if (XGetWindowProperty (xdisplay, window,
|
|
(Atom) i % 200,
|
|
0, 0xffffffff,
|
|
False,
|
|
AnyPropertyType,
|
|
&actual_type,
|
|
&actual_format,
|
|
&n_items,
|
|
&bytes_after,
|
|
&data) == Success)
|
|
{
|
|
if (data)
|
|
XFree (data);
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
error_trap_pop (xdisplay);
|
|
|
|
gettimeofday (&end, NULL);
|
|
|
|
printf ("Sync time: %gms\n",
|
|
ELAPSED (start, end));
|
|
}
|