source: trunk/third/xscreensaver/utils/xshm.c @ 20148

Revision 20148, 6.3 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 2001
2 *  by Jamie Zawinski <jwz@jwz.org>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation.  No representations are made about the suitability of this
9 * software for any purpose.  It is provided "as is" without express or
10 * implied warranty.
11 */
12
13/* The MIT-SHM (Shared Memory) extension is pretty tricky to use.
14   This file contains the common boiler-plate for creating a shared
15   XImage structure, and for making sure that the shared memory segments
16   get allocated and shut down cleanly.
17
18   This code currently deals only with shared XImages, not with shared Pixmaps.
19   It also doesn't use "completion events", but so far that doesn't seem to
20   be a problem (and I'm not entirely clear on when they would actually be
21   needed, anyway.)
22
23   If you don't have man pages for this extension, see
24   http://www.physik.uni-regensburg.de/~scs22156/sofie-0.2/mit-shm.html
25   or in the R6 sources as "xc/doc/specs/Xext/mit-shm.ms", for example,
26   ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/mit-shm.ms
27
28   (This document seems not to ever remain available on the web in one place
29   for very long; you can search for it by the title, "MIT-SHM -- The MIT
30   Shared Memory Extension".)
31
32   To monitor the system's shared memory segments, run "ipcs -m".
33  */
34
35#include "utils.h"
36
37#ifdef HAVE_XSHM_EXTENSION      /* whole file */
38
39/* #define DEBUG */
40
41#include <errno.h>              /* for perror() */
42#include <X11/Xutil.h>          /* for XDestroyImage() */
43
44#include "xshm.h"
45#include "resources.h"          /* for get_string_resource() */
46
47#ifdef DEBUG
48# include <X11/Xmu/Error.h>
49#endif
50
51extern char *progname;
52
53
54/* The documentation for the XSHM extension implies that if the server
55   supports XSHM but is not the local machine, the XShm calls will return
56   False; but this turns out not to be the case.  Instead, the server
57   throws a BadAccess error.  So, we need to catch X errors around all
58   of our XSHM calls, sigh.
59 */
60
61static Bool shm_got_x_error = False;
62XErrorHandler old_handler = 0;
63static int
64shm_ehandler (Display *dpy, XErrorEvent *error)
65{
66  shm_got_x_error = True;
67
68#ifdef DEBUG
69  fprintf (stderr, "\n%s: ignoring X error from XSHM:\n", progname);
70  XmuPrintDefaultErrorMessage (dpy, error, stderr);
71  fprintf (stderr, "\n");
72#endif
73
74  return 0;
75}
76
77
78#define CATCH_X_ERROR(DPY) do {                         \
79  XSync((DPY), False);                                  \
80  shm_got_x_error = False;                              \
81  if (old_handler != shm_ehandler)                      \
82    old_handler = XSetErrorHandler (shm_ehandler);      \
83} while(0)
84
85#define UNCATCH_X_ERROR(DPY) do {                       \
86  XSync((DPY), False);                                  \
87  if (old_handler)                                      \
88    XSetErrorHandler (old_handler);                     \
89    old_handler = 0;                                    \
90} while(0)
91
92
93XImage *
94create_xshm_image (Display *dpy, Visual *visual,
95                   unsigned int depth,
96                   int format, char *data,
97                   XShmSegmentInfo *shm_info,
98                   unsigned int width, unsigned int height)
99{
100  Status status;
101  XImage *image = 0;
102  if (!get_boolean_resource("useSHM", "Boolean"))
103    return 0;
104
105  if (!XShmQueryExtension (dpy))
106    return 0;
107
108  CATCH_X_ERROR(dpy);
109  image = XShmCreateImage(dpy, visual, depth,
110                          format, data, shm_info, width, height);
111  UNCATCH_X_ERROR(dpy);
112  if (shm_got_x_error)
113    return 0;
114
115#ifdef DEBUG
116  fprintf(stderr, "\n%s: XShmCreateImage(... %d, %d)\n", progname,
117          width, height);
118#endif
119
120  shm_info->shmid = shmget(IPC_PRIVATE,
121                           image->bytes_per_line * image->height,
122                           IPC_CREAT | 0777);
123#ifdef DEBUG
124  fprintf(stderr, "%s: shmget(IPC_PRIVATE, %d, IPC_CREAT | 0777) ==> %d\n",
125          progname, image->bytes_per_line * image->height, shm_info->shmid);
126#endif
127
128  if (shm_info->shmid == -1)
129    {
130      char buf[1024];
131      sprintf (buf, "%s: shmget failed", progname);
132      perror(buf);
133      XDestroyImage (image);
134      image = 0;
135      XSync(dpy, False);
136    }
137  else
138    {
139      shm_info->readOnly = False;
140      image->data = shm_info->shmaddr = shmat(shm_info->shmid, 0, 0);
141
142#ifdef DEBUG
143      fprintf(stderr, "%s: shmat(%d, 0, 0) ==> %d\n", progname,
144              shm_info->shmid, (int) image->data);
145#endif
146
147      CATCH_X_ERROR(dpy);
148      status = XShmAttach(dpy, shm_info);
149      UNCATCH_X_ERROR(dpy);
150      if (shm_got_x_error)
151        status = False;
152
153      if (!status)
154        {
155          fprintf (stderr, "%s: XShmAttach failed!\n", progname);
156          XDestroyImage (image);
157          XSync(dpy, False);
158          shmdt (shm_info->shmaddr);
159          image = 0;
160        }
161#ifdef DEBUG
162      else
163        fprintf(stderr, "%s: XShmAttach(dpy, shm_info) ==> True\n", progname);
164#endif
165
166      XSync(dpy, False);
167
168      /* Delete the shared segment right now; the segment won't actually
169         go away until both the client and server have deleted it.  The
170         server will delete it as soon as the client disconnects, so we
171         should delete our side early in case of abnormal termination.
172         (And note that, in the context of xscreensaver, abnormal
173         termination is the rule rather than the exception, so this would
174         leak like a sieve if we didn't do this...)
175
176         #### Are we leaking anyway?  Perhaps because of the window of
177         opportunity between here and the XShmAttach call above, during
178         which we might be killed?  Do we need to establish a signal
179         handler for this case?
180       */
181      shmctl (shm_info->shmid, IPC_RMID, 0);
182
183#ifdef DEBUG
184      fprintf(stderr, "%s: shmctl(%d, IPC_RMID, 0)\n\n", progname,
185              shm_info->shmid);
186#endif
187    }
188
189  return image;
190}
191
192
193void
194destroy_xshm_image (Display *dpy, XImage *image, XShmSegmentInfo *shm_info)
195{
196  Status status;
197
198  CATCH_X_ERROR(dpy);
199  status = XShmDetach (dpy, shm_info);
200  UNCATCH_X_ERROR(dpy);
201  if (shm_got_x_error)
202    status = False;
203  if (!status)
204    fprintf (stderr, "%s: XShmDetach failed!\n", progname);
205#ifdef DEBUG
206  else
207    fprintf (stderr, "%s: XShmDetach(dpy, shm_info) ==> True\n", progname);
208#endif
209
210  XDestroyImage (image);
211  XSync(dpy, False);
212
213  status = shmdt (shm_info->shmaddr);
214
215  if (status != 0)
216    {
217      char buf[1024];
218      sprintf (buf, "%s: shmdt(0x%lx) failed", progname,
219               (unsigned long) shm_info->shmaddr);
220      perror(buf);
221    }
222#ifdef DEBUG
223  else
224    fprintf (stderr, "%s: shmdt(shm_info->shmaddr) ==> 0\n", progname);
225#endif
226
227  XSync(dpy, False);
228}
229
230
231#endif /* HAVE_XSHM_EXTENSION */
Note: See TracBrowser for help on using the repository browser.