/* Copyright (c) 1993, 2015, Oracle and/or its affiliates. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. */ #include #include #include #include #include #include #ifdef SERVER_DGA #include #else #include #include #include #endif /* SERVER_DGA */ #include "dga_incls.h" #include "pix_grab.h" #define NDIGITS 8 #define MINSHMEMSIZE (8*1024) #define MAXSHMEMSIZE (0x00040000) #define MAXSHPXMEMSIZE (0x01000000) #define SHPX_MAX_CLIENTS 64 #define SHPX_MAX_PIXMAPS 341 /* Some structure definition for internal bookkeeping * NOTE: there is only one locking window created per device for * the use of all pixmaps on that device */ typedef struct dga_pixlist { Dga_token p_token; /* Token associated with pix */ int num_clientp; struct dga_pixmap *dga_clientplist; /*List of client ptrs in pix */ struct dga_pixlist *next_plist; /* Next link in the dga list */ } *Dga_pixlist; static struct dga_pixlist *dga_plist = NULL; #ifdef SERVER_DGA extern SHPX_CLIENT_ENTRY shpx_client_directory[]; extern int Dga_shpx_client_count; #else static SHPX_CLIENT_ENTRY shpx_client_directory[SHPX_MAX_CLIENTS]; static int Dga_shpx_client_count = 0; #endif /* SERVER_DGA */ static u_long pagesize; extern int _dga_winlockat(u_long cookie, int **lockp, int **unlockp); extern int _dga_winlockdt(int *lockp, int *unlockp); extern void *_dga_is_X_pixmap(Pixmap pix, Display **dpyp); /****************************************** * * dga_pix_grab: * * create shared memory file for pixmap information * map to lock page * * arguments: * * Dga_token token; INPUT * magic cookie supplied by the server * * returns a user virtual address for a dga_window structure. * returns NULL if anything goes awry. * *****************************************/ Dga_pixmap dga_pix_grab(token, pix) Dga_token token; Pixmap pix; { SHARED_PIXMAP_INFO *infop; _Dga_pixmap clientp ; Display *dpy; int c_fd, i, entry_found; u_int port; size_t size; SHPX_DIRECTORY *shpx_dir; char c_fn[256]; char *dpystr; static char path[256]; char host[MAXHOSTNAMELEN]; Dga_lockp lockp, unlockp; /* Remember to account for multiple clients grabbing the same pixmap * later */ /* First determine if this is a X pixmap - if so, get * the dpy and pixid */ if (!_dga_is_X_pixmap(pix, &dpy)) { #ifdef DEBUG (void) fprintf(stderr, "dga_pix_grab: Unsupported pixmap type\n"); #endif return (PIX_FAILED); } if (!dga_plist) { /* This is the first time through this code so get the * retained path */ if (!XDgaGetRetainedPath(dpy, pix, path)) { #ifdef DEBUG (void) fprintf(stderr, "dga_pix_grab: XDgaGetRetainedPath failed\n"); #endif return (PIX_FAILED); } } #ifndef SERVER_DGA /* Now get the port number for this display */ dpystr = DisplayString(dpy); if (dpystr[0] == ':') (void) sscanf(dpystr, ":%u", &port); else (void) sscanf(dpystr, "%[^:]:%u", host, &port); if (Dga_shpx_client_count == 0) { /* Now start by initializing all the per client structs - * all 64 of them - if thie is the first time you * are grabbing a pixmap */ for (i = 0; i < SHPX_MAX_CLIENTS; i++) { shpx_client_directory[i].cid = 0; shpx_client_directory[i].shpx_directory = NULL; shpx_client_directory[i].fd = 0; shpx_client_directory[i].size = 0; shpx_client_directory[i].npix = 0; } } else #endif /* SERVER_DGA */ { /* If it is not the first time, see if this client has grabbed * a pixmap before and therefore done all the set up. * Search through the client structures for matching token */ i = 0; while ((i < SHPX_MAX_CLIENTS) && (shpx_client_directory[i].cid != token)) { i++; } if ((i == SHPX_MAX_CLIENTS) && (Dga_shpx_client_count == SHPX_MAX_CLIENTS)) { return(0); } } if ((Dga_shpx_client_count > 0) && (i < SHPX_MAX_CLIENTS)) { /* We found a match and the pixmap already has been grabbed before */ shpx_dir = shpx_client_directory[i].shpx_directory; shpx_client_directory[i].npix++; } #ifndef SERVER_DGA else { /* This client has Never grabbed before set up the direct * structure etc. * Open the shared file using server command line * -sharedretainedpath variable for file path if it is * set, else use /tmp. This is because these files can * be very big and there usually isn't much space in /tmp. */ c_fn[0] = 0; if ((path) && (strlen(path) > 0)) strcpy(c_fn, path); else strcpy(c_fn, "/tmp"); strcat(c_fn, PIX_FILE); size = strlen(c_fn); sprintf(c_fn+size,"%01x.%08x", port, token); #ifdef SYSV pagesize = sysconf(_SC_PAGESIZE); #else pagesize = getpagesize(); #endif i = 0; while ((i < SHPX_MAX_CLIENTS) && (shpx_client_directory[i].cid != 0)) i++; if (i >= SHPX_MAX_CLIENTS) return(0); if ((c_fd = open(c_fn,O_RDWR ,0666)) < 0) return(0); /* map the shpx directory for this client and map at 4 megabytes */ shpx_dir = (SHPX_DIRECTORY *)mmap(0, MAXSHPXMEMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, c_fd, (off_t)0); if (shpx_dir == (SHPX_DIRECTORY *)-1) { close(c_fd); return(0); } Dga_shpx_client_count++; shpx_client_directory[i].cid = token; /* BMAC - correct?? */ shpx_client_directory[i].shpx_directory = shpx_dir; shpx_client_directory[i].fd = c_fd; /* no longer need to save it */ shpx_client_directory[i].size = shpx_dir[0].shpx_entry_0.s_size; shpx_client_directory[i].npix = 1; } #endif /* SERVER_DGA */ /* The first 2 entries on the file have special meaning. */ i = 2; entry_found = 0; while ((i < SHPX_MAX_PIXMAPS) && (!entry_found)) { if (shpx_dir[i].shpx_entry.xid == pix) entry_found = 1; else i++; } if (!entry_found) { #ifndef SERVER_DGA close(c_fd); #endif /* SERVER_DGA */ return(0); } infop = (SHARED_PIXMAP_INFO *) (((u_char *)shpx_dir) + shpx_dir[i].shpx_entry.offset); if ((infop->magic != PXMPMAGIC) || (infop->version > PXMPVERS)) { #ifndef SERVER_DGA close(c_fd); #endif /* SERVER_DGA */ return(0); } if (infop->obsolete) { #ifndef SERVER_DGA close(c_fd); #endif /* SERVER_DGA */ return(0); } /* BMAC - Find out about the rache code - what should I do there? */ /* Now fill out the Dga_pixmap structure */ if( (clientp = (_Dga_pixmap) malloc(sizeof(struct dga_pixmap))) == NULL ) return NULL ; clientp->drawable_type = DGA_DRAW_PIXMAP; clientp->p_lockcnt = 0; clientp->obsolete = 0; clientp->p_modif = NULL; clientp->p_infop = (void *)infop ; clientp->c_chngcnt[0] = 0; #ifdef MT clientp->shadow_chngcnt[0] = 0; #endif /* This is the new location added for locking performance * For windows it pts to the second member in the c_wm_chngcnt * array but here I think that it just pts to the previous field * since for pixmaps the array ctr is -1 always */ clientp->p_chngcnt_2nd = clientp->c_chngcnt +1; clientp->s_chngcnt_p = &(infop->s_modified); clientp->c_dirchngcnt = shpx_dir[1].shpx_entry_1.s_dir_seq; clientp->s_dirchngcnt_p = &(shpx_dir[1].shpx_entry_1.s_dir_seq); clientp->c_devinfocnt = 0; clientp->s_devinfocnt_p = &(infop->s_devinfoseq); clientp->c_cachecnt = 0; clientp->s_cachecnt_p = &(infop->s_cacheseq); clientp->c_cached = 0; clientp->s_cached_p = &(infop->cached); clientp->p_dir_index = i; clientp->p_shpx_dir = (void *)shpx_dir; /*CHECK ME */ #ifdef MT if (dgaThreaded) { clientp->p_unlock_func = dgai_unlock; } else { clientp->p_unlock_func = NULL; } #else clientp->p_lock_func = NULL; clientp->p_unlock_func = NULL; #endif clientp->p_update_func = dgai_pix_update; clientp->p_shpx_client = NULL; clientp->p_token = token; clientp->c_size = infop->s_size; clientp->c_pixels = (u_char *)(infop + 1); clientp->depth = infop->depth; clientp->linebytes = infop->linebytes; clientp->p_next = NULL; clientp->p_infofd = NULL; clientp->pix_flags = PIX_NOTICE_CLIPCHG; clientp->p_dpy = 0; clientp->p_id = NULL; clientp->p_client = NULL; clientp->changeMask = NULL; clientp->siteChgReason = NULL; clientp->siteNotifyFunc = NULL; clientp->siteNotifyClientData = NULL; #ifdef SERVER_DGA clientp->p_lockp = infop->p_lockp; clientp->p_unlockp = infop->p_unlockp; #else lockp = NULL; /* init to NULL for check below */ unlockp = NULL; /* Check to see if there are already a lockp and unlockp * for this device--if not create 'em */ if (dga_plist) { lockp = dga_plist->dga_clientplist->p_lockp; unlockp = dga_plist->dga_clientplist->p_unlockp; } if (!lockp) { /* only get new lock pages if necessary */ if( _dga_winlockat(infop->p_cookie, &lockp, &unlockp) != 0 ) { munmap((caddr_t)infop, MAXSHPXMEMSIZE); /* REMIND Daryl: What else do we need to clean up? */ free(clientp) ; return(NULL); } } clientp->p_lockp = lockp; clientp->p_unlockp = unlockp; #endif /* SERVER_DGA */ /* add to linked list of grabbed pixmaps - for internal bookkeeping */ if (!dga_plist) { if ((dga_plist = (Dga_pixlist) malloc(sizeof(struct dga_pixlist))) == NULL ) return NULL ; dga_plist->p_token = token; dga_plist->num_clientp = 1; dga_plist->dga_clientplist = clientp; dga_plist->next_plist = NULL; } else { struct dga_pixlist *new_plist; if ((new_plist = (Dga_pixlist) malloc(sizeof(struct dga_pixlist))) == NULL ) return NULL; new_plist->p_token = token; new_plist->num_clientp = 1; new_plist->dga_clientplist = clientp; new_plist->next_plist = dga_plist; dga_plist = new_plist; } #ifdef MT if (dgaThreaded) { clientp->mutexp = &dgaGlobalPixmapMutex; } else { clientp->mutexp = NULL; } #endif return ((Dga_pixmap) clientp); } void dga_pix_ungrab(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; Dga_pixlist prev_pixlist = NULL; Dga_pixlist pixlist = dga_plist; u_int i; /* Find pixmap in dga_plist */ while (pixlist) { if (pixlist->dga_clientplist == clientp) { #ifndef SERVER_DGA i = 0; while ((i < SHPX_MAX_CLIENTS) && (shpx_client_directory[i].cid != pixlist->p_token)) { i++; } if (i >= SHPX_MAX_CLIENTS) { return; } shpx_client_directory[i].npix--; if (!shpx_client_directory[i].npix) { munmap((caddr_t)shpx_client_directory[i].shpx_directory, MAXSHPXMEMSIZE); close(shpx_client_directory[i].fd); shpx_client_directory[i].cid = 0; shpx_client_directory[i].shpx_directory = NULL; shpx_client_directory[i].fd = 0; shpx_client_directory[i].size = 0; } #endif /* SERVER_DGA */ if (prev_pixlist) prev_pixlist->next_plist = pixlist->next_plist; else dga_plist = pixlist->next_plist; #ifndef SERVER_DGA if (!dga_plist) { _dga_winlockdt(clientp->p_lockp, clientp->p_unlockp); } #endif /* SERVER_DGA */ free(pixlist); free(clientp); if(--Dga_shpx_client_count < 0) Dga_shpx_client_count = 0; return; } else { prev_pixlist = pixlist; pixlist = pixlist->next_plist; } } } #ifdef COMMENT /* TODO: Daryl what is this routine supposed to be used for??? */ int dga_pix_sync(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; /* this checks to see if the shared pixmap info * area has changed and if so reinits the data */ /* This routine seems to requoire that the handle have 1. if the pixmap is cached or not 2. what type the pixmap is = like retained one?? 3. something called sh_rache_scr0, sh_rache_scr1; 4. something called sh_Scr_Virt[]; virtual screen table */ } #endif int dga_pix_cachechg(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; if (clientp->c_cachecnt != *(clientp->s_cachecnt_p)) { /* Something changed */ clientp->c_cachecnt = *(clientp->s_cachecnt_p); return 1; } else /* Nothing has changed */ return 0; } int dga_pix_cached(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; if (clientp->c_cached != *(clientp->s_cached_p)) { /* Something changed */ clientp->c_cached = *(clientp->s_cached_p); return 1; } else /* Nothing has changed */ return 0; } char * dga_pix_devname(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; /* CHECK THIS ! */ return ((char *) PIX_INFOP(clientp)->scr_name); } void * dga_pix_pixels(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; return ((void*)clientp->c_pixels); } int dga_pix_linebytes(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; return (clientp->linebytes); } u_char dga_pix_depth(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; return (clientp->depth); } void * dga_pix_devinfo(clientpi) Dga_pixmap clientpi; { _Dga_pixmap clientp = (struct dga_pixmap *)clientpi; return (((char *)clientp->p_infop) + PIX_INFOP(clientp)->device_offset); }