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