os2Stubs.c revision 61b2299d
1/* 2 * (c) Copyright 1996 by Sebastien Marineau and Holger Veit 3 * <marineau@genie.uottawa.ca> 4 * <Holger.Veit@gmd.de> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * HOLGER VEIT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 21 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * Except as contained in this notice, the name of Sebastien Marineau or Holger Veit 25 * shall not be used in advertising or otherwise to promote the sale, use or other 26 * dealings in this Software without prior written authorization from Holger Veit or 27 * Sebastien Marineau. 28 * 29 */ 30 31/* $XFree86: xc/lib/X11/os2Stubs.c,v 3.0 1996/05/13 06:37:17 dawes Exp $ */ 32 33/* A few OS/2 functions needed in the X11 lib. Mainly, the file path redirection 34 * functions and the "optimized" select() for the clients */ 35 36#define I_NEED_OS2_H 37#ifdef HAVE_CONFIG_H 38#include <config.h> 39#endif 40#include <X11/Xpoll.h> 41#include <stdio.h> 42#include <sys/errno.h> 43#define INCL_DOSSEMAPHORES 44#define INCL_DOSNPIPES 45#define INCL_DOSMISC 46#define INCL_DOSMODULEMGR 47#undef BOOL 48#undef BYTE 49#include <os2.h> 50#include <sys/select.h> 51#include <sys/time.h> 52 53char *__XOS2RedirRoot(char *fname) 54{ 55 /* This adds a further redirection by allowing the ProjectRoot 56 * to be prepended by the content of the envvar X11ROOT. 57 * This is for the purpose to move the whole X11 stuff to a different 58 * disk drive. 59 * The feature was added despite various environment variables 60 * because not all file opens respect them. 61 */ 62 static char redirname[300]; /* enough for long filenames */ 63 char *root; 64 65 /* if name does not start with /, assume it is not root-based */ 66 if (fname==0 || !(fname[0]=='/' || fname[0]=='\\')) 67 return fname; 68 69 root = (char*)getenv("X11ROOT"); 70 if (root==0 || 71 (fname[1]==':' && isalpha(fname[0])) || 72 (strlen(fname)+strlen(root)+2) > 300) 73 return fname; 74 sprintf(redirname,"%s%s",root,fname); 75 return redirname; 76} 77 78char *__XOS2RedirRoot1(char *format, char *arg1, char *arg2, char *arg3) 79{ 80 /* this first constructs a name from a format and up to three 81 * components, then adds a path 82 */ 83 char buf[300]; 84 sprintf(buf,format,arg1,arg2,arg3); 85 return __XOS2RedirRoot(buf); 86} 87 88/* This below implements select() for the calls in this file. It has been */ 89/* somewhat optimized for improved performance, but assumes a few */ 90/* things so it cannot be used as a general select. If both pipes and */ 91/* sockets are present, this may call the emx select */ 92 93 94HEV hPipeSem; 95HMODULE hmod_so32dll; 96static int (*os2_tcp_select)(int*,int,int,int,long); 97ULONG os2_get_sys_millis(); 98extern int _files[]; 99 100#define MAX_TCP 256 101/* These lifted from sys/emx.h. Change if that changes there! */ 102#define F_SOCKET 0x10000000 103#define F_PIPE 0x20000000 104 105struct select_data 106{ 107 fd_set read_copy; 108 fd_set write_copy; 109 BOOL have_read; 110 BOOL have_write; 111 int tcp_select_mask[MAX_TCP]; 112 int tcp_emx_handles[MAX_TCP]; 113 int tcp_select_copy[MAX_TCP]; 114 int socket_nread; 115 int socket_nwrite; 116 int socket_ntotal; 117 int pipe_ntotal; 118 int pipe_have_write; 119 int max_fds; 120}; 121 122int os2ClientSelect(int nfds, fd_set *readfds, fd_set *writefds, 123 fd_set *exceptfds, struct timeval *timeout) 124{ 125static BOOL FirstTime=TRUE; 126static haveTCPIP=TRUE; 127ULONG timeout_ms; 128ULONG postCount, start_millis,now_millis; 129char faildata[16]; 130struct select_data sd; 131BOOL any_ready; 132int np,ns, i,ready_handles,n; 133APIRET rc; 134 135sd.have_read=FALSE; sd.have_write=FALSE; 136sd.socket_nread=0; sd.socket_nwrite=0; sd.socket_ntotal=0; 137sd.max_fds=31; ready_handles=0; any_ready=FALSE; 138sd.pipe_ntotal=0; sd.pipe_have_write=FALSE; 139 140if(FirstTime){ 141 /* First load the so32dll.dll module and get a pointer to the SELECT fn */ 142 143 if((rc=DosLoadModule(faildata,sizeof(faildata),"SO32DLL",&hmod_so32dll))!=0){ 144 fprintf(stderr, "Could not load module so32dll.dll, rc = %d. Error note %s\n",rc,faildata); 145 haveTCPIP=FALSE; 146 } 147 if((rc = DosQueryProcAddr(hmod_so32dll, 0, "SELECT", (PPFN)&os2_tcp_select))!=0){ 148 fprintf(stderr, "Could not query address of SELECT, rc = %d.\n",rc); 149 haveTCPIP=FALSE; 150 } 151 /* Call these a first time to set the semaphore */ 152 rc = DosCreateEventSem(NULL, &hPipeSem, DC_SEM_SHARED, FALSE); 153 if(rc) { 154 fprintf(stderr, "Could not create event semaphore, rc=%d\n",rc); 155 return(-1); 156 } 157 rc = DosResetEventSem(hPipeSem, &postCount); 158 FirstTime = FALSE; 159} 160 161/* Set up the time delay structs */ 162 163 if(timeout!=NULL) { 164 timeout_ms=timeout->tv_sec*1000+timeout->tv_usec/1000; 165 } 166 else { timeout_ms=1000000; } /* This should be large enough... */ 167 if(timeout_ms>0) start_millis=os2_get_sys_millis(); 168 169/* Copy the masks */ 170 {FD_ZERO(&sd.read_copy);} 171 {FD_ZERO(&sd.write_copy);} 172 if(readfds!=NULL){ XFD_COPYSET(readfds,&sd.read_copy); sd.have_read=TRUE;} 173 if(writefds!=NULL) {XFD_COPYSET(writefds,&sd.write_copy);sd.have_write=TRUE;} 174 175/* And zero the original masks */ 176 if(sd.have_read){ FD_ZERO(readfds);} 177 if(sd.have_write) {FD_ZERO(writefds);} 178 if(exceptfds != NULL) {FD_ZERO(exceptfds);} 179 180/* Now we parse the fd_sets passed to select and separate pipe/sockets */ 181 n = os2_parse_select(&sd,nfds); 182 if(n == -1) { 183 errno = EBADF; 184 return (-1); 185 } 186 187/* Now we have three cases: either we have sockets, pipes, or both */ 188/* We handle all three cases differently to optimize things */ 189 190/* Case 1: only pipes! */ 191 if((sd.pipe_ntotal >0) && (!sd.socket_ntotal)){ 192 np = os2_check_pipes(&sd,readfds,writefds); 193 if(np > 0){ 194 return (np); 195 } 196 else if (np == -1) { return(-1); } 197 while(!any_ready){ 198 rc = DosWaitEventSem(hPipeSem, timeout_ms); 199 if(rc == 640) { 200 return(0); 201 } 202 if((rc != 0) && (rc != 95)) {errno= EBADF; return(-1);} 203 np = os2_check_pipes(&sd,readfds,writefds); 204 if (np > 0){ 205 return(np); 206 } 207 else if (np < 0){ return(-1); } 208 } 209 } 210 211/* Case 2: only sockets. Just let the os/2 tcp select do the work */ 212 if((sd.socket_ntotal > 0) && (!sd.pipe_ntotal)){ 213 ns = os2_check_sockets(&sd, readfds, writefds, timeout_ms); 214 return (ns); 215 } 216 217/* Case 3: combination of both */ 218 if((sd.socket_ntotal > 0) && (sd.pipe_ntotal)){ 219 np = os2_check_pipes(&sd,readfds,writefds); 220 if(np > 0){ 221 any_ready=TRUE; 222 ready_handles += np; 223 } 224 else if (np == -1) { return(-1); } 225 226 ns = os2_check_sockets(&sd,readfds,writefds, 0); 227 if(ns>0){ 228 ready_handles+=ns; 229 any_ready = TRUE; 230 } 231 else if (ns == -1) {return(-1);} 232 233 while (!any_ready && timeout_ms){ 234 235 rc = DosWaitEventSem(hPipeSem, 10L); 236 if(rc == 0){ 237 np = os2_check_pipes(&sd,readfds,writefds); 238 if(np > 0){ 239 ready_handles+=np; 240 any_ready = TRUE; 241 } 242 else if (np == -1) { 243 return(-1); } 244 } 245 246 ns = os2_check_sockets(&sd,readfds,writefds,exceptfds, 0); 247 if(ns>0){ 248 ready_handles+=ns; 249 any_ready = TRUE; 250 } 251 else if (ns == -1) {return(-1);} 252 253 if (i%8 == 0) { 254 now_millis = os2_get_sys_millis(); 255 if((now_millis-start_millis) > timeout_ms) timeout_ms = 0; 256 } 257 i++; 258 } 259 } 260 261return(ready_handles); 262} 263 264 265ULONG os2_get_sys_millis() 266{ 267 APIRET rc; 268 ULONG milli; 269 270 rc = DosQuerySysInfo(14, 14, &milli, sizeof(milli)); 271 if(rc) { 272 fprintf(stderr,"Bad return code querying the millisecond counter! rc=%d\n",rc); 273 return(0); 274 } 275 return(milli); 276} 277 278int os2_parse_select(sd,nfds) 279struct select_data *sd; 280int nfds; 281{ 282 int i; 283 APIRET rc; 284/* First we determine up to which descriptor we need to check. */ 285/* No need to check up to 256 if we don't have to (and usually we dont...)*/ 286/* Note: stuff here is hardcoded for fd_sets which are int[8] as in EMX!!! */ 287 288 if(nfds > sd->max_fds){ 289 for(i=0;i<((FD_SETSIZE+31)/32);i++){ 290 if(sd->read_copy.fds_bits[i] || 291 sd->write_copy.fds_bits[i]) 292 sd->max_fds=(i*32) +32; 293 } 294 } 295 else { sd->max_fds = nfds; } 296/* Check if result is greater than specified in select() call */ 297 if(sd->max_fds > nfds) sd->max_fds = nfds; 298 299 if (sd->have_read) 300 { 301 for (i = 0; i < sd->max_fds; ++i) { 302 if (FD_ISSET (i, &sd->read_copy)){ 303 if(_files[i] & F_SOCKET) 304 { 305 sd->tcp_select_mask[sd->socket_ntotal]=_getsockhandle(i); 306 sd->tcp_emx_handles[sd->socket_ntotal]=i; 307 sd->socket_ntotal++; sd->socket_nread++; 308 } 309 else if (_files[i] & F_PIPE) 310 { 311 sd -> pipe_ntotal++; 312 rc = DosSetNPipeSem((HPIPE)i, (HSEM) hPipeSem, i); 313 if(rc) { fprintf(stderr,"Error SETNPIPE rc = %d\n",rc); return -1;} 314 } 315 } 316 } 317 } 318 319 if (sd->have_write) 320 { 321 for (i = 0; i < sd->max_fds; ++i) { 322 if (FD_ISSET (i, &sd->write_copy)){ 323 if(_files[i] & F_SOCKET) 324 { 325 sd->tcp_select_mask[sd->socket_ntotal]=_getsockhandle(i); 326 sd->tcp_emx_handles[sd->socket_ntotal]=i; 327 sd->socket_ntotal++; sd->socket_nwrite++; 328 } 329 else if (_files[i] & F_PIPE) 330 { 331 sd -> pipe_ntotal++; 332 rc = DosSetNPipeSem((HPIPE)i, (HSEM) hPipeSem, i); 333 if(rc) { fprintf(stderr,"Error SETNPIPE rc = %d\n",rc); return -1;} 334 sd -> pipe_have_write=TRUE; 335 } 336 } 337 } 338 } 339 340 341return(sd->socket_ntotal); 342} 343 344 345int os2_check_sockets(sd,readfds,writefds) 346struct select_data *sd; 347fd_set *readfds,*writefds; 348{ 349 int e,i; 350 int j,n; 351 memcpy(sd->tcp_select_copy,sd->tcp_select_mask, 352 sd->socket_ntotal*sizeof(int)); 353 354 e = os2_tcp_select(sd->tcp_select_copy,sd->socket_nread, 355 sd->socket_nwrite, 0, 0); 356 357 if(e == 0) return(e); 358/* We have something ready? */ 359 if(e>0){ 360 j = 0; n = 0; 361 for (i = 0; i < sd->socket_nread; ++i, ++j) 362 if (sd->tcp_select_copy[j] != -1) 363 { 364 FD_SET (sd->tcp_emx_handles[j], readfds); 365 n ++; 366 } 367 for (i = 0; i < sd->socket_nwrite; ++i, ++j) 368 if (sd->tcp_select_copy[j] != -1) 369 { 370 FD_SET (sd->tcp_emx_handles[j], writefds); 371 n ++; 372 } 373 errno = 0; 374 375 return n; 376 } 377 if(e<0){ 378 /*Error -- TODO */ 379 fprintf(stderr,"Error in server select! e=%d\n",e); 380 errno = EBADF; 381 return (-1); 382 } 383 } 384 385/* Check to see if anything is ready on pipes */ 386 387int os2_check_pipes(sd,readfds,writefds) 388struct select_data *sd; 389fd_set *readfds,*writefds; 390{ 391int i,e; 392ULONG ulPostCount; 393PIPESEMSTATE pipeSemState[128]; 394APIRET rc; 395 e = 0; 396 rc = DosResetEventSem(hPipeSem,&ulPostCount); 397 rc = DosQueryNPipeSemState((HSEM) hPipeSem, (PPIPESEMSTATE)&pipeSemState, 398 sizeof(pipeSemState)); 399 if(rc) fprintf(stderr,"SELECT: rc from QueryNPipeSem: %d\n",rc); 400 i=0; 401 while (pipeSemState[i].fStatus != 0) { 402 /*fprintf(stderr,"SELECT: sem entry, stat=%d, flag=%d, key=%d,avail=%d\n", 403 pipeSemState[i].fStatus,pipeSemState[i].fFlag,pipeSemState[i].usKey, 404 pipeSemState[i].usAvail); */ 405 if((pipeSemState[i].fStatus == 1) && 406 (FD_ISSET(pipeSemState[i].usKey,&sd->read_copy))){ 407 FD_SET(pipeSemState[i].usKey,readfds); 408 e++; 409 } 410 else if((pipeSemState[i].fStatus == 2) && 411 (FD_ISSET(pipeSemState[i].usKey,&sd->write_copy))){ 412 FD_SET(pipeSemState[i].usKey,writefds); 413 e++; 414 } 415 else if( (pipeSemState[i].fStatus == 3) && 416 ( (FD_ISSET(pipeSemState[i].usKey,&sd->read_copy)) || 417 (FD_ISSET(pipeSemState[i].usKey,&sd->write_copy)) )){ 418 errno = EBADF; 419 return (-1); 420 } 421 i++; 422 } /* endwhile */ 423 /*fprintf(stderr,"Done listing pipe sem entries, total %d entries, total ready entries %d\n",i,e);*/ 424errno = 0; 425return(e); 426} 427 428 429 430