- got rid of include/async.h
[wine] / server / fd.c
1 /*
2  * Server-side file descriptor management
3  *
4  * Copyright (C) 2000, 2003 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #ifdef HAVE_SYS_POLL_H
34 #include <sys/poll.h>
35 #endif
36 #ifdef HAVE_STDINT_H
37 #include <stdint.h>
38 #endif
39 #include <sys/stat.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43
44 #include "object.h"
45 #include "file.h"
46 #include "handle.h"
47 #include "process.h"
48 #include "request.h"
49
50 #include "winbase.h"
51 #include "winreg.h"
52 #include "winternl.h"
53
54 #if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE)
55 # include <sys/epoll.h>
56 # define USE_EPOLL
57 #elif defined(linux) && defined(__i386__) && defined(HAVE_STDINT_H)
58 # define USE_EPOLL
59 # define EPOLLIN POLLIN
60 # define EPOLLOUT POLLOUT
61 # define EPOLLERR POLLERR
62 # define EPOLLHUP POLLHUP
63 # define EPOLL_CTL_ADD 1
64 # define EPOLL_CTL_DEL 2
65 # define EPOLL_CTL_MOD 3
66
67 typedef union epoll_data
68 {
69   void *ptr;
70   int fd;
71   uint32_t u32;
72   uint64_t u64;
73 } epoll_data_t;
74
75 struct epoll_event
76 {
77   uint32_t events;
78   epoll_data_t data;
79 };
80
81 #define SYSCALL_RET(ret) do { \
82         if (ret < 0) { errno = -ret; ret = -1; } \
83         return ret; \
84     } while(0)
85
86 static inline int epoll_create( int size )
87 {
88     int ret;
89     __asm__( "pushl %%ebx; movl %2,%%ebx; int $0x80; popl %%ebx"
90              : "=a" (ret) : "0" (254 /*NR_epoll_create*/), "r" (size) );
91     SYSCALL_RET(ret);
92 }
93
94 static inline int epoll_ctl( int epfd, int op, int fd, const struct epoll_event *event )
95 {
96     int ret;
97     __asm__( "pushl %%ebx; movl %2,%%ebx; int $0x80; popl %%ebx"
98              : "=a" (ret)
99              : "0" (255 /*NR_epoll_ctl*/), "r" (epfd), "c" (op), "d" (fd), "S" (event), "m" (*event) );
100     SYSCALL_RET(ret);
101 }
102
103 static inline int epoll_wait( int epfd, struct epoll_event *events, int maxevents, int timeout )
104 {
105     int ret;
106     __asm__( "pushl %%ebx; movl %2,%%ebx; int $0x80; popl %%ebx"
107              : "=a" (ret)
108              : "0" (256 /*NR_epoll_wait*/), "r" (epfd), "c" (events), "d" (maxevents), "S" (timeout)
109              : "memory" );
110     SYSCALL_RET(ret);
111 }
112 #undef SYSCALL_RET
113
114 #endif /* linux && __i386__ && HAVE_STDINT_H */
115
116
117 /* Because of the stupid Posix locking semantics, we need to keep
118  * track of all file descriptors referencing a given file, and not
119  * close a single one until all the locks are gone (sigh).
120  */
121
122 /* file descriptor object */
123
124 /* closed_fd is used to keep track of the unix fd belonging to a closed fd object */
125 struct closed_fd
126 {
127     struct list entry;       /* entry in inode closed list */
128     int         fd;          /* the unix file descriptor */
129     char        unlink[1];   /* name to unlink on close (if any) */
130 };
131
132 struct fd
133 {
134     struct object        obj;         /* object header */
135     const struct fd_ops *fd_ops;      /* file descriptor operations */
136     struct inode        *inode;       /* inode that this fd belongs to */
137     struct list          inode_entry; /* entry in inode fd list */
138     struct closed_fd    *closed;      /* structure to store the unix fd at destroy time */
139     struct object       *user;        /* object using this file descriptor */
140     struct list          locks;       /* list of locks on this fd */
141     unsigned int         access;      /* file access (GENERIC_READ/WRITE) */
142     unsigned int         sharing;     /* file sharing mode */
143     int                  unix_fd;     /* unix file descriptor */
144     int                  fs_locks;    /* can we use filesystem locks for this fd? */
145     int                  poll_index;  /* index of fd in poll array */
146 };
147
148 static void fd_dump( struct object *obj, int verbose );
149 static void fd_destroy( struct object *obj );
150
151 static const struct object_ops fd_ops =
152 {
153     sizeof(struct fd),        /* size */
154     fd_dump,                  /* dump */
155     no_add_queue,             /* add_queue */
156     NULL,                     /* remove_queue */
157     NULL,                     /* signaled */
158     NULL,                     /* satisfied */
159     no_get_fd,                /* get_fd */
160     fd_destroy                /* destroy */
161 };
162
163 /* inode object */
164
165 struct inode
166 {
167     struct object       obj;        /* object header */
168     struct list         entry;      /* inode hash list entry */
169     unsigned int        hash;       /* hashing code */
170     dev_t               dev;        /* device number */
171     ino_t               ino;        /* inode number */
172     struct list         open;       /* list of open file descriptors */
173     struct list         locks;      /* list of file locks */
174     struct list         closed;     /* list of file descriptors to close at destroy time */
175 };
176
177 static void inode_dump( struct object *obj, int verbose );
178 static void inode_destroy( struct object *obj );
179
180 static const struct object_ops inode_ops =
181 {
182     sizeof(struct inode),     /* size */
183     inode_dump,               /* dump */
184     no_add_queue,             /* add_queue */
185     NULL,                     /* remove_queue */
186     NULL,                     /* signaled */
187     NULL,                     /* satisfied */
188     no_get_fd,                /* get_fd */
189     inode_destroy             /* destroy */
190 };
191
192 /* file lock object */
193
194 struct file_lock
195 {
196     struct object       obj;         /* object header */
197     struct fd          *fd;          /* fd owning this lock */
198     struct list         fd_entry;    /* entry in list of locks on a given fd */
199     struct list         inode_entry; /* entry in inode list of locks */
200     int                 shared;      /* shared lock? */
201     file_pos_t          start;       /* locked region is interval [start;end) */
202     file_pos_t          end;
203     struct process     *process;     /* process owning this lock */
204     struct list         proc_entry;  /* entry in list of locks owned by the process */
205 };
206
207 static void file_lock_dump( struct object *obj, int verbose );
208 static int file_lock_signaled( struct object *obj, struct thread *thread );
209
210 static const struct object_ops file_lock_ops =
211 {
212     sizeof(struct file_lock),   /* size */
213     file_lock_dump,             /* dump */
214     add_queue,                  /* add_queue */
215     remove_queue,               /* remove_queue */
216     file_lock_signaled,         /* signaled */
217     no_satisfied,               /* satisfied */
218     no_get_fd,                  /* get_fd */
219     no_destroy                  /* destroy */
220 };
221
222
223 #define OFF_T_MAX       (~((file_pos_t)1 << (8*sizeof(off_t)-1)))
224 #define FILE_POS_T_MAX  (~(file_pos_t)0)
225
226 static file_pos_t max_unix_offset = OFF_T_MAX;
227
228 #define DUMP_LONG_LONG(val) do { \
229     if (sizeof(val) > sizeof(unsigned long) && (val) > ~0UL) \
230         fprintf( stderr, "%lx%08lx", (unsigned long)((val) >> 32), (unsigned long)(val) ); \
231     else \
232         fprintf( stderr, "%lx", (unsigned long)(val) ); \
233   } while (0)
234
235
236
237 /****************************************************************/
238 /* timeouts support */
239
240 struct timeout_user
241 {
242     struct list           entry;      /* entry in sorted timeout list */
243     struct timeval        when;       /* timeout expiry (absolute time) */
244     timeout_callback      callback;   /* callback function */
245     void                 *private;    /* callback private data */
246 };
247
248 static struct list timeout_list = LIST_INIT(timeout_list);   /* sorted timeouts list */
249
250 /* add a timeout user */
251 struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
252 {
253     struct timeout_user *user;
254     struct list *ptr;
255
256     if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
257     user->when     = *when;
258     user->callback = func;
259     user->private  = private;
260
261     /* Now insert it in the linked list */
262
263     LIST_FOR_EACH( ptr, &timeout_list )
264     {
265         struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
266         if (!time_before( &timeout->when, when )) break;
267     }
268     list_add_before( ptr, &user->entry );
269     return user;
270 }
271
272 /* remove a timeout user */
273 void remove_timeout_user( struct timeout_user *user )
274 {
275     list_remove( &user->entry );
276     free( user );
277 }
278
279 /* add a timeout in milliseconds to an absolute time */
280 void add_timeout( struct timeval *when, int timeout )
281 {
282     if (timeout)
283     {
284         long sec = timeout / 1000;
285         if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
286         {
287             when->tv_usec -= 1000000;
288             when->tv_sec++;
289         }
290         when->tv_sec += sec;
291     }
292 }
293
294
295 /****************************************************************/
296 /* poll support */
297
298 static struct fd **poll_users;              /* users array */
299 static struct pollfd *pollfd;               /* poll fd array */
300 static int nb_users;                        /* count of array entries actually in use */
301 static int active_users;                    /* current number of active users */
302 static int allocated_users;                 /* count of allocated entries in the array */
303 static struct fd **freelist;                /* list of free entries in the array */
304
305 #ifdef USE_EPOLL
306
307 static int epoll_fd;
308 static struct epoll_event *epoll_events;
309
310 /* set the events that epoll waits for on this fd; helper for set_fd_events */
311 static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
312 {
313     struct epoll_event ev;
314     int ctl;
315
316     if (epoll_fd == -1) return;
317
318     if (events == -1)  /* stop waiting on this fd completely */
319     {
320         if (pollfd[user].fd == -1) return;  /* already removed */
321         ctl = EPOLL_CTL_DEL;
322     }
323     else if (pollfd[user].fd == -1)
324     {
325         if (pollfd[user].events) return;  /* stopped waiting on it, don't restart */
326         ctl = EPOLL_CTL_ADD;
327     }
328     else
329     {
330         if (pollfd[user].events == events) return;  /* nothing to do */
331         ctl = EPOLL_CTL_MOD;
332     }
333
334     ev.events = events;
335     ev.data.u32 = user;
336
337     if (epoll_ctl( epoll_fd, ctl, fd->unix_fd, &ev ) == -1)
338     {
339         if (errno == ENOMEM)  /* not enough memory, give up on epoll */
340         {
341             close( epoll_fd );
342             epoll_fd = -1;
343         }
344         else perror( "epoll_ctl" );  /* should not happen */
345     }
346 }
347
348 #else /* USE_EPOLL */
349
350 static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
351 {
352 }
353
354 #endif /* USE_EPOLL */
355
356
357 /* add a user in the poll array and return its index, or -1 on failure */
358 static int add_poll_user( struct fd *fd )
359 {
360     int ret;
361     if (freelist)
362     {
363         ret = freelist - poll_users;
364         freelist = (struct fd **)poll_users[ret];
365     }
366     else
367     {
368         if (nb_users == allocated_users)
369         {
370             struct fd **newusers;
371             struct pollfd *newpoll;
372             int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
373             if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
374             if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
375             {
376                 if (allocated_users)
377                     poll_users = newusers;
378                 else
379                     free( newusers );
380                 return -1;
381             }
382             poll_users = newusers;
383             pollfd = newpoll;
384 #ifdef USE_EPOLL
385             if (!allocated_users) epoll_fd = epoll_create( new_count );
386             if (epoll_fd != -1)
387             {
388                 struct epoll_event *new_events;
389                 if (!(new_events = realloc( epoll_events, new_count * sizeof(*epoll_events) )))
390                     return -1;
391                 epoll_events = new_events;
392             }
393 #endif
394             allocated_users = new_count;
395         }
396         ret = nb_users++;
397     }
398     pollfd[ret].fd = -1;
399     pollfd[ret].events = 0;
400     pollfd[ret].revents = 0;
401     poll_users[ret] = fd;
402     active_users++;
403     return ret;
404 }
405
406 /* remove a user from the poll list */
407 static void remove_poll_user( struct fd *fd, int user )
408 {
409     assert( user >= 0 );
410     assert( poll_users[user] == fd );
411
412 #ifdef USE_EPOLL
413     if (epoll_fd != -1 && pollfd[user].fd != -1)
414     {
415         struct epoll_event dummy;
416         epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd->unix_fd, &dummy );
417     }
418 #endif
419     pollfd[user].fd = -1;
420     pollfd[user].events = 0;
421     pollfd[user].revents = 0;
422     poll_users[user] = (struct fd *)freelist;
423     freelist = &poll_users[user];
424     active_users--;
425 }
426
427 /* process pending timeouts and return the time until the next timeout, in milliseconds */
428 static int get_next_timeout(void)
429 {
430     if (!list_empty( &timeout_list ))
431     {
432         struct list expired_list, *ptr;
433         struct timeval now;
434
435         gettimeofday( &now, NULL );
436
437         /* first remove all expired timers from the list */
438
439         list_init( &expired_list );
440         while ((ptr = list_head( &timeout_list )) != NULL)
441         {
442             struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
443
444             if (!time_before( &now, &timeout->when ))
445             {
446                 list_remove( &timeout->entry );
447                 list_add_tail( &expired_list, &timeout->entry );
448             }
449             else break;
450         }
451
452         /* now call the callback for all the removed timers */
453
454         while ((ptr = list_head( &expired_list )) != NULL)
455         {
456             struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
457             list_remove( &timeout->entry );
458             timeout->callback( timeout->private );
459             free( timeout );
460         }
461
462         if ((ptr = list_head( &timeout_list )) != NULL)
463         {
464             struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
465             int diff = (timeout->when.tv_sec - now.tv_sec) * 1000
466                      + (timeout->when.tv_usec - now.tv_usec) / 1000;
467             if (diff < 0) diff = 0;
468             return diff;
469         }
470     }
471     return -1;  /* no pending timeouts */
472 }
473
474 /* server main poll() loop */
475 void main_loop(void)
476 {
477     int i, ret, timeout;
478
479 #ifdef USE_EPOLL
480     assert( POLLIN == EPOLLIN );
481     assert( POLLOUT == EPOLLOUT );
482     assert( POLLERR == EPOLLERR );
483     assert( POLLHUP == EPOLLHUP );
484
485     if (epoll_fd != -1)
486     {
487         while (active_users)
488         {
489             timeout = get_next_timeout();
490
491             if (!active_users) break;  /* last user removed by a timeout */
492             if (epoll_fd == -1) break;  /* an error occurred with epoll */
493
494             ret = epoll_wait( epoll_fd, epoll_events, allocated_users, timeout );
495
496             /* put the events into the pollfd array first, like poll does */
497             for (i = 0; i < ret; i++)
498             {
499                 int user = epoll_events[i].data.u32;
500                 pollfd[user].revents = epoll_events[i].events;
501             }
502
503             /* read events from the pollfd array, as set_fd_events may modify them */
504             for (i = 0; i < ret; i++)
505             {
506                 int user = epoll_events[i].data.u32;
507                 if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents );
508             }
509         }
510     }
511     /* fall through to normal poll loop */
512 #endif  /* USE_EPOLL */
513
514     while (active_users)
515     {
516         timeout = get_next_timeout();
517
518         if (!active_users) break;  /* last user removed by a timeout */
519
520         ret = poll( pollfd, nb_users, timeout );
521         if (ret > 0)
522         {
523             for (i = 0; i < nb_users; i++)
524             {
525                 if (pollfd[i].revents)
526                 {
527                     fd_poll_event( poll_users[i], pollfd[i].revents );
528                     if (!--ret) break;
529                 }
530             }
531         }
532     }
533 }
534
535
536 /****************************************************************/
537 /* inode functions */
538
539 #define HASH_SIZE 37
540
541 static struct list inode_hash[HASH_SIZE];
542
543 /* close all pending file descriptors in the closed list */
544 static void inode_close_pending( struct inode *inode )
545 {
546     struct list *ptr = list_head( &inode->closed );
547
548     while (ptr)
549     {
550         struct closed_fd *fd = LIST_ENTRY( ptr, struct closed_fd, entry );
551         struct list *next = list_next( &inode->closed, ptr );
552
553         if (fd->fd != -1)
554         {
555             close( fd->fd );
556             fd->fd = -1;
557         }
558         if (!fd->unlink)  /* get rid of it unless there's an unlink pending on that file */
559         {
560             list_remove( ptr );
561             free( fd );
562         }
563         ptr = next;
564     }
565 }
566
567
568 static void inode_dump( struct object *obj, int verbose )
569 {
570     struct inode *inode = (struct inode *)obj;
571     fprintf( stderr, "Inode dev=" );
572     DUMP_LONG_LONG( inode->dev );
573     fprintf( stderr, " ino=" );
574     DUMP_LONG_LONG( inode->ino );
575     fprintf( stderr, "\n" );
576 }
577
578 static void inode_destroy( struct object *obj )
579 {
580     struct inode *inode = (struct inode *)obj;
581     struct list *ptr;
582
583     assert( list_empty(&inode->open) );
584     assert( list_empty(&inode->locks) );
585
586     list_remove( &inode->entry );
587
588     while ((ptr = list_head( &inode->closed )))
589     {
590         struct closed_fd *fd = LIST_ENTRY( ptr, struct closed_fd, entry );
591         list_remove( ptr );
592         if (fd->fd != -1) close( fd->fd );
593         if (fd->unlink[0])
594         {
595             /* make sure it is still the same file */
596             struct stat st;
597             if (!stat( fd->unlink, &st ) && st.st_dev == inode->dev && st.st_ino == inode->ino)
598             {
599                 if (S_ISDIR(st.st_mode)) rmdir( fd->unlink );
600                 else unlink( fd->unlink );
601             }
602         }
603         free( fd );
604     }
605 }
606
607 /* retrieve the inode object for a given fd, creating it if needed */
608 static struct inode *get_inode( dev_t dev, ino_t ino )
609 {
610     struct list *ptr;
611     struct inode *inode;
612     unsigned int hash = (dev ^ ino) % HASH_SIZE;
613
614     if (inode_hash[hash].next)
615     {
616         LIST_FOR_EACH( ptr, &inode_hash[hash] )
617         {
618             inode = LIST_ENTRY( ptr, struct inode, entry );
619             if (inode->dev == dev && inode->ino == ino)
620                 return (struct inode *)grab_object( inode );
621         }
622     }
623     else list_init( &inode_hash[hash] );
624
625     /* not found, create it */
626     if ((inode = alloc_object( &inode_ops )))
627     {
628         inode->hash   = hash;
629         inode->dev    = dev;
630         inode->ino    = ino;
631         list_init( &inode->open );
632         list_init( &inode->locks );
633         list_init( &inode->closed );
634         list_add_head( &inode_hash[hash], &inode->entry );
635     }
636     return inode;
637 }
638
639 /* add fd to the indoe list of file descriptors to close */
640 static void inode_add_closed_fd( struct inode *inode, struct closed_fd *fd )
641 {
642     if (!list_empty( &inode->locks ))
643     {
644         list_add_head( &inode->closed, &fd->entry );
645     }
646     else if (fd->unlink[0])  /* close the fd but keep the structure around for unlink */
647     {
648         close( fd->fd );
649         fd->fd = -1;
650         list_add_head( &inode->closed, &fd->entry );
651     }
652     else  /* no locks on this inode and no unlink, get rid of the fd */
653     {
654         close( fd->fd );
655         free( fd );
656     }
657 }
658
659
660 /****************************************************************/
661 /* file lock functions */
662
663 static void file_lock_dump( struct object *obj, int verbose )
664 {
665     struct file_lock *lock = (struct file_lock *)obj;
666     fprintf( stderr, "Lock %s fd=%p proc=%p start=",
667              lock->shared ? "shared" : "excl", lock->fd, lock->process );
668     DUMP_LONG_LONG( lock->start );
669     fprintf( stderr, " end=" );
670     DUMP_LONG_LONG( lock->end );
671     fprintf( stderr, "\n" );
672 }
673
674 static int file_lock_signaled( struct object *obj, struct thread *thread )
675 {
676     struct file_lock *lock = (struct file_lock *)obj;
677     /* lock is signaled if it has lost its owner */
678     return !lock->process;
679 }
680
681 /* set (or remove) a Unix lock if possible for the given range */
682 static int set_unix_lock( struct fd *fd, file_pos_t start, file_pos_t end, int type )
683 {
684     struct flock fl;
685
686     if (!fd->fs_locks) return 1;  /* no fs locks possible for this fd */
687     for (;;)
688     {
689         if (start == end) return 1;  /* can't set zero-byte lock */
690         if (start > max_unix_offset) return 1;  /* ignore it */
691         fl.l_type   = type;
692         fl.l_whence = SEEK_SET;
693         fl.l_start  = start;
694         if (!end || end > max_unix_offset) fl.l_len = 0;
695         else fl.l_len = end - start;
696         if (fcntl( fd->unix_fd, F_SETLK, &fl ) != -1) return 1;
697
698         switch(errno)
699         {
700         case EACCES:
701             /* check whether locks work at all on this file system */
702             if (fcntl( fd->unix_fd, F_GETLK, &fl ) != -1)
703             {
704                 set_error( STATUS_FILE_LOCK_CONFLICT );
705                 return 0;
706             }
707             /* fall through */
708         case EIO:
709         case ENOLCK:
710             /* no locking on this fs, just ignore it */
711             fd->fs_locks = 0;
712             return 1;
713         case EAGAIN:
714             set_error( STATUS_FILE_LOCK_CONFLICT );
715             return 0;
716         case EBADF:
717             /* this can happen if we try to set a write lock on a read-only file */
718             /* we just ignore that error */
719             if (fl.l_type == F_WRLCK) return 1;
720             set_error( STATUS_ACCESS_DENIED );
721             return 0;
722 #ifdef EOVERFLOW
723         case EOVERFLOW:
724 #endif
725         case EINVAL:
726             /* this can happen if off_t is 64-bit but the kernel only supports 32-bit */
727             /* in that case we shrink the limit and retry */
728             if (max_unix_offset > INT_MAX)
729             {
730                 max_unix_offset = INT_MAX;
731                 break;  /* retry */
732             }
733             /* fall through */
734         default:
735             file_set_error();
736             return 0;
737         }
738     }
739 }
740
741 /* check if interval [start;end) overlaps the lock */
742 inline static int lock_overlaps( struct file_lock *lock, file_pos_t start, file_pos_t end )
743 {
744     if (lock->end && start >= lock->end) return 0;
745     if (end && lock->start >= end) return 0;
746     return 1;
747 }
748
749 /* remove Unix locks for all bytes in the specified area that are no longer locked */
750 static void remove_unix_locks( struct fd *fd, file_pos_t start, file_pos_t end )
751 {
752     struct hole
753     {
754         struct hole *next;
755         struct hole *prev;
756         file_pos_t   start;
757         file_pos_t   end;
758     } *first, *cur, *next, *buffer;
759
760     struct list *ptr;
761     int count = 0;
762
763     if (!fd->inode) return;
764     if (!fd->fs_locks) return;
765     if (start == end || start > max_unix_offset) return;
766     if (!end || end > max_unix_offset) end = max_unix_offset + 1;
767
768     /* count the number of locks overlapping the specified area */
769
770     LIST_FOR_EACH( ptr, &fd->inode->locks )
771     {
772         struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, inode_entry );
773         if (lock->start == lock->end) continue;
774         if (lock_overlaps( lock, start, end )) count++;
775     }
776
777     if (!count)  /* no locks at all, we can unlock everything */
778     {
779         set_unix_lock( fd, start, end, F_UNLCK );
780         return;
781     }
782
783     /* allocate space for the list of holes */
784     /* max. number of holes is number of locks + 1 */
785
786     if (!(buffer = malloc( sizeof(*buffer) * (count+1) ))) return;
787     first = buffer;
788     first->next  = NULL;
789     first->prev  = NULL;
790     first->start = start;
791     first->end   = end;
792     next = first + 1;
793
794     /* build a sorted list of unlocked holes in the specified area */
795
796     LIST_FOR_EACH( ptr, &fd->inode->locks )
797     {
798         struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, inode_entry );
799         if (lock->start == lock->end) continue;
800         if (!lock_overlaps( lock, start, end )) continue;
801
802         /* go through all the holes touched by this lock */
803         for (cur = first; cur; cur = cur->next)
804         {
805             if (cur->end <= lock->start) continue; /* hole is before start of lock */
806             if (lock->end && cur->start >= lock->end) break;  /* hole is after end of lock */
807
808             /* now we know that lock is overlapping hole */
809
810             if (cur->start >= lock->start)  /* lock starts before hole, shrink from start */
811             {
812                 cur->start = lock->end;
813                 if (cur->start && cur->start < cur->end) break;  /* done with this lock */
814                 /* now hole is empty, remove it */
815                 if (cur->next) cur->next->prev = cur->prev;
816                 if (cur->prev) cur->prev->next = cur->next;
817                 else if (!(first = cur->next)) goto done;  /* no more holes at all */
818             }
819             else if (!lock->end || cur->end <= lock->end)  /* lock larger than hole, shrink from end */
820             {
821                 cur->end = lock->start;
822                 assert( cur->start < cur->end );
823             }
824             else  /* lock is in the middle of hole, split hole in two */
825             {
826                 next->prev = cur;
827                 next->next = cur->next;
828                 cur->next = next;
829                 next->start = lock->end;
830                 next->end = cur->end;
831                 cur->end = lock->start;
832                 assert( next->start < next->end );
833                 assert( cur->end < next->start );
834                 next++;
835                 break;  /* done with this lock */
836             }
837         }
838     }
839
840     /* clear Unix locks for all the holes */
841
842     for (cur = first; cur; cur = cur->next)
843         set_unix_lock( fd, cur->start, cur->end, F_UNLCK );
844
845  done:
846     free( buffer );
847 }
848
849 /* create a new lock on a fd */
850 static struct file_lock *add_lock( struct fd *fd, int shared, file_pos_t start, file_pos_t end )
851 {
852     struct file_lock *lock;
853
854     if (!fd->inode)  /* not a regular file */
855     {
856         set_error( STATUS_INVALID_HANDLE );
857         return NULL;
858     }
859
860     if (!(lock = alloc_object( &file_lock_ops ))) return NULL;
861     lock->shared  = shared;
862     lock->start   = start;
863     lock->end     = end;
864     lock->fd      = fd;
865     lock->process = current->process;
866
867     /* now try to set a Unix lock */
868     if (!set_unix_lock( lock->fd, lock->start, lock->end, lock->shared ? F_RDLCK : F_WRLCK ))
869     {
870         release_object( lock );
871         return NULL;
872     }
873     list_add_head( &fd->locks, &lock->fd_entry );
874     list_add_head( &fd->inode->locks, &lock->inode_entry );
875     list_add_head( &lock->process->locks, &lock->proc_entry );
876     return lock;
877 }
878
879 /* remove an existing lock */
880 static void remove_lock( struct file_lock *lock, int remove_unix )
881 {
882     struct inode *inode = lock->fd->inode;
883
884     list_remove( &lock->fd_entry );
885     list_remove( &lock->inode_entry );
886     list_remove( &lock->proc_entry );
887     if (remove_unix) remove_unix_locks( lock->fd, lock->start, lock->end );
888     if (list_empty( &inode->locks )) inode_close_pending( inode );
889     lock->process = NULL;
890     wake_up( &lock->obj, 0 );
891     release_object( lock );
892 }
893
894 /* remove all locks owned by a given process */
895 void remove_process_locks( struct process *process )
896 {
897     struct list *ptr;
898
899     while ((ptr = list_head( &process->locks )))
900     {
901         struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, proc_entry );
902         remove_lock( lock, 1 );  /* this removes it from the list */
903     }
904 }
905
906 /* remove all locks on a given fd */
907 static void remove_fd_locks( struct fd *fd )
908 {
909     file_pos_t start = FILE_POS_T_MAX, end = 0;
910     struct list *ptr;
911
912     while ((ptr = list_head( &fd->locks )))
913     {
914         struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, fd_entry );
915         if (lock->start < start) start = lock->start;
916         if (!lock->end || lock->end > end) end = lock->end - 1;
917         remove_lock( lock, 0 );
918     }
919     if (start < end) remove_unix_locks( fd, start, end + 1 );
920 }
921
922 /* add a lock on an fd */
923 /* returns handle to wait on */
924 obj_handle_t lock_fd( struct fd *fd, file_pos_t start, file_pos_t count, int shared, int wait )
925 {
926     struct list *ptr;
927     file_pos_t end = start + count;
928
929     /* don't allow wrapping locks */
930     if (end && end < start)
931     {
932         set_error( STATUS_INVALID_PARAMETER );
933         return 0;
934     }
935
936     /* check if another lock on that file overlaps the area */
937     LIST_FOR_EACH( ptr, &fd->inode->locks )
938     {
939         struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, inode_entry );
940         if (!lock_overlaps( lock, start, end )) continue;
941         if (lock->shared && shared) continue;
942         /* found one */
943         if (!wait)
944         {
945             set_error( STATUS_FILE_LOCK_CONFLICT );
946             return 0;
947         }
948         set_error( STATUS_PENDING );
949         return alloc_handle( current->process, lock, SYNCHRONIZE, 0 );
950     }
951
952     /* not found, add it */
953     if (add_lock( fd, shared, start, end )) return 0;
954     if (get_error() == STATUS_FILE_LOCK_CONFLICT)
955     {
956         /* Unix lock conflict -> tell client to wait and retry */
957         if (wait) set_error( STATUS_PENDING );
958     }
959     return 0;
960 }
961
962 /* remove a lock on an fd */
963 void unlock_fd( struct fd *fd, file_pos_t start, file_pos_t count )
964 {
965     struct list *ptr;
966     file_pos_t end = start + count;
967
968     /* find an existing lock with the exact same parameters */
969     LIST_FOR_EACH( ptr, &fd->locks )
970     {
971         struct file_lock *lock = LIST_ENTRY( ptr, struct file_lock, fd_entry );
972         if ((lock->start == start) && (lock->end == end))
973         {
974             remove_lock( lock, 1 );
975             return;
976         }
977     }
978     set_error( STATUS_FILE_LOCK_CONFLICT );
979 }
980
981
982 /****************************************************************/
983 /* asynchronous operations support */
984
985 struct async
986 {
987     struct fd           *fd;
988     struct thread       *thread;
989     void                *apc;
990     void                *user;
991     void                *sb;
992     struct timeval       when;
993     struct timeout_user *timeout;
994     struct async        *next;
995     struct async       **head;
996 };
997
998 /* cb for timeout on an async request */
999 static void async_callback(void *private)
1000 {
1001     struct async *async = (struct async *)private;
1002
1003     /* fprintf(stderr, "async timeout out %p\n", async); */
1004     async->timeout = NULL;
1005     async_terminate( async, STATUS_TIMEOUT );
1006 }
1007
1008 /* create an async on a given queue of a fd */
1009 struct async *create_async(struct fd *fd, struct thread *thread,
1010                            int timeout, struct async **head, 
1011                            void *io_apc, void *io_user, void* io_sb)
1012 {
1013     struct async *async = mem_alloc( sizeof(struct async) );
1014     struct async **p;
1015
1016     if (!async) return NULL;
1017
1018     async->fd = fd;
1019     async->thread = (struct thread *)grab_object(thread);
1020     async->apc = io_apc;
1021     async->user = io_user;
1022     async->sb = io_sb;
1023     async->head = head;
1024     async->next = NULL;
1025
1026     for (p = head; *p; p = &(*p)->next);
1027     *p = async;
1028
1029     if (timeout)
1030     {
1031         gettimeofday( &async->when, 0 );
1032         add_timeout( &async->when, timeout );
1033         async->timeout = add_timeout_user( &async->when, async_callback, async );
1034     }
1035     else async->timeout = NULL;
1036
1037     return async;
1038 }
1039
1040 /* notifies client thread of new status of its async request */
1041 /* destroys the server side of it */
1042 void async_terminate( struct async *async, int status )
1043 {
1044     struct async** p;
1045
1046     thread_queue_apc( async->thread, NULL, async->apc, APC_ASYNC_IO,
1047                       1, async->user, async->sb, (void *)status );
1048
1049     if (async->timeout) remove_timeout_user( async->timeout );
1050     async->timeout = NULL;
1051
1052     for (p = async->head; *p; p = &(*p)->next)
1053     {
1054         if (*p == async)
1055         {
1056             *p = async->next;
1057             break;
1058         }
1059     }
1060
1061     release_object( async->thread );
1062     free( async );
1063 }
1064
1065 /****************************************************************/
1066 /* file descriptor functions */
1067
1068 static void fd_dump( struct object *obj, int verbose )
1069 {
1070     struct fd *fd = (struct fd *)obj;
1071     fprintf( stderr, "Fd unix_fd=%d user=%p unlink='%s'\n",
1072              fd->unix_fd, fd->user, fd->closed->unlink );
1073 }
1074
1075 static void fd_destroy( struct object *obj )
1076 {
1077     struct fd *fd = (struct fd *)obj;
1078
1079     remove_fd_locks( fd );
1080     list_remove( &fd->inode_entry );
1081     if (fd->poll_index != -1) remove_poll_user( fd, fd->poll_index );
1082     if (fd->inode)
1083     {
1084         inode_add_closed_fd( fd->inode, fd->closed );
1085         release_object( fd->inode );
1086     }
1087     else  /* no inode, close it right away */
1088     {
1089         if (fd->unix_fd != -1) close( fd->unix_fd );
1090     }
1091 }
1092
1093 /* set the events that select waits for on this fd */
1094 void set_fd_events( struct fd *fd, int events )
1095 {
1096     int user = fd->poll_index;
1097     assert( poll_users[user] == fd );
1098
1099     set_fd_epoll_events( fd, user, events );
1100
1101     if (events == -1)  /* stop waiting on this fd completely */
1102     {
1103         pollfd[user].fd = -1;
1104         pollfd[user].events = POLLERR;
1105         pollfd[user].revents = 0;
1106     }
1107     else if (pollfd[user].fd != -1 || !pollfd[user].events)
1108     {
1109         pollfd[user].fd = fd->unix_fd;
1110         pollfd[user].events = events;
1111     }
1112 }
1113
1114 /* allocate an fd object, without setting the unix fd yet */
1115 struct fd *alloc_fd( const struct fd_ops *fd_user_ops, struct object *user )
1116 {
1117     struct fd *fd = alloc_object( &fd_ops );
1118
1119     if (!fd) return NULL;
1120
1121     fd->fd_ops     = fd_user_ops;
1122     fd->user       = user;
1123     fd->inode      = NULL;
1124     fd->closed     = NULL;
1125     fd->access     = 0;
1126     fd->sharing    = 0;
1127     fd->unix_fd    = -1;
1128     fd->fs_locks   = 1;
1129     fd->poll_index = -1;
1130     list_init( &fd->inode_entry );
1131     list_init( &fd->locks );
1132
1133     if ((fd->poll_index = add_poll_user( fd )) == -1)
1134     {
1135         release_object( fd );
1136         return NULL;
1137     }
1138     return fd;
1139 }
1140
1141 /* check if the desired access is possible without violating */
1142 /* the sharing mode of other opens of the same file */
1143 static int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing )
1144 {
1145     unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1146     unsigned int existing_access = 0;
1147     int unlink = 0;
1148     struct list *ptr;
1149
1150     /* if access mode is 0, sharing mode is ignored */
1151     if (!access) sharing = existing_sharing;
1152     fd->access = access;
1153     fd->sharing = sharing;
1154
1155     LIST_FOR_EACH( ptr, &fd->inode->open )
1156     {
1157         struct fd *fd_ptr = LIST_ENTRY( ptr, struct fd, inode_entry );
1158         if (fd_ptr != fd)
1159         {
1160             existing_sharing &= fd_ptr->sharing;
1161             existing_access  |= fd_ptr->access;
1162             if (fd_ptr->closed->unlink[0]) unlink = 1;
1163         }
1164     }
1165
1166     if ((access & GENERIC_READ) && !(existing_sharing & FILE_SHARE_READ)) return 0;
1167     if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) return 0;
1168     if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) return 0;
1169     if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) return 0;
1170     if (fd->closed->unlink[0] && !(existing_sharing & FILE_SHARE_DELETE)) return 0;
1171     if (unlink && !(sharing & FILE_SHARE_DELETE)) return 0;
1172     return 1;
1173 }
1174
1175 /* open() wrapper using a struct fd */
1176 /* the fd must have been created with alloc_fd */
1177 /* on error the fd object is released */
1178 struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode,
1179                     unsigned int access, unsigned int sharing, unsigned int options )
1180 {
1181     struct stat st;
1182     struct closed_fd *closed_fd;
1183     const char *unlink_name = "";
1184
1185     assert( fd->unix_fd == -1 );
1186
1187     if (options & FILE_DELETE_ON_CLOSE) unlink_name = name;
1188     if (!(closed_fd = mem_alloc( sizeof(*closed_fd) + strlen(unlink_name) )))
1189     {
1190         release_object( fd );
1191         return NULL;
1192     }
1193     /* create the directory if needed */
1194     if ((options & FILE_DIRECTORY_FILE) && (flags & O_CREAT))
1195     {
1196         if (mkdir( name, 0777 ) == -1)
1197         {
1198             if (errno != EEXIST || (flags & O_EXCL))
1199             {
1200                 file_set_error();
1201                 release_object( fd );
1202                 free( closed_fd );
1203                 return NULL;
1204             }
1205         }
1206         flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
1207     }
1208     if ((fd->unix_fd = open( name, flags & ~O_TRUNC, *mode )) == -1)
1209     {
1210         file_set_error();
1211         release_object( fd );
1212         free( closed_fd );
1213         return NULL;
1214     }
1215     closed_fd->fd = fd->unix_fd;
1216     closed_fd->unlink[0] = 0;
1217     fstat( fd->unix_fd, &st );
1218     *mode = st.st_mode;
1219
1220     /* only bother with an inode for normal files and directories */
1221     if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
1222     {
1223         struct inode *inode = get_inode( st.st_dev, st.st_ino );
1224
1225         if (!inode)
1226         {
1227             /* we can close the fd because there are no others open on the same file,
1228              * otherwise we wouldn't have failed to allocate a new inode
1229              */
1230             goto error;
1231         }
1232         fd->inode = inode;
1233         fd->closed = closed_fd;
1234         list_add_head( &inode->open, &fd->inode_entry );
1235
1236         /* check directory options */
1237         if ((options & FILE_DIRECTORY_FILE) && !S_ISDIR(st.st_mode))
1238         {
1239             release_object( fd );
1240             set_error( STATUS_NOT_A_DIRECTORY );
1241             return NULL;
1242         }
1243         if ((options & FILE_NON_DIRECTORY_FILE) && S_ISDIR(st.st_mode))
1244         {
1245             release_object( fd );
1246             set_error( STATUS_FILE_IS_A_DIRECTORY );
1247             return NULL;
1248         }
1249         if (!check_sharing( fd, access, sharing ))
1250         {
1251             release_object( fd );
1252             set_error( STATUS_SHARING_VIOLATION );
1253             return NULL;
1254         }
1255         strcpy( closed_fd->unlink, unlink_name );
1256         if (flags & O_TRUNC) ftruncate( fd->unix_fd, 0 );
1257     }
1258     else  /* special file */
1259     {
1260         if (options & FILE_DIRECTORY_FILE)
1261         {
1262             set_error( STATUS_NOT_A_DIRECTORY );
1263             goto error;
1264         }
1265         if (unlink_name[0])  /* we can't unlink special files */
1266         {
1267             set_error( STATUS_INVALID_PARAMETER );
1268             goto error;
1269         }
1270         free( closed_fd );
1271     }
1272     return fd;
1273
1274 error:
1275     release_object( fd );
1276     free( closed_fd );
1277     return NULL;
1278 }
1279
1280 /* create an fd for an anonymous file */
1281 /* if the function fails the unix fd is closed */
1282 struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user )
1283 {
1284     struct fd *fd = alloc_fd( fd_user_ops, user );
1285
1286     if (fd)
1287     {
1288         fd->unix_fd = unix_fd;
1289         return fd;
1290     }
1291     close( unix_fd );
1292     return NULL;
1293 }
1294
1295 /* retrieve the object that is using an fd */
1296 void *get_fd_user( struct fd *fd )
1297 {
1298     return fd->user;
1299 }
1300
1301 /* retrieve the unix fd for an object */
1302 int get_unix_fd( struct fd *fd )
1303 {
1304     return fd->unix_fd;
1305 }
1306
1307 /* check if two file descriptors point to the same file */
1308 int is_same_file_fd( struct fd *fd1, struct fd *fd2 )
1309 {
1310     return fd1->inode == fd2->inode;
1311 }
1312
1313 /* callback for event happening in the main poll() loop */
1314 void fd_poll_event( struct fd *fd, int event )
1315 {
1316     return fd->fd_ops->poll_event( fd, event );
1317 }
1318
1319 /* check if events are pending and if yes return which one(s) */
1320 int check_fd_events( struct fd *fd, int events )
1321 {
1322     struct pollfd pfd;
1323
1324     pfd.fd     = fd->unix_fd;
1325     pfd.events = events;
1326     if (poll( &pfd, 1, 0 ) <= 0) return 0;
1327     return pfd.revents;
1328 }
1329
1330 /* default add_queue() routine for objects that poll() on an fd */
1331 int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry )
1332 {
1333     struct fd *fd = get_obj_fd( obj );
1334
1335     if (!fd) return 0;
1336     if (!obj->head)  /* first on the queue */
1337         set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) );
1338     add_queue( obj, entry );
1339     release_object( fd );
1340     return 1;
1341 }
1342
1343 /* default remove_queue() routine for objects that poll() on an fd */
1344 void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry )
1345 {
1346     struct fd *fd = get_obj_fd( obj );
1347
1348     grab_object( obj );
1349     remove_queue( obj, entry );
1350     if (!obj->head)  /* last on the queue is gone */
1351         set_fd_events( fd, 0 );
1352     release_object( obj );
1353     release_object( fd );
1354 }
1355
1356 /* default signaled() routine for objects that poll() on an fd */
1357 int default_fd_signaled( struct object *obj, struct thread *thread )
1358 {
1359     struct fd *fd = get_obj_fd( obj );
1360     int events = fd->fd_ops->get_poll_events( fd );
1361     int ret = check_fd_events( fd, events ) != 0;
1362
1363     if (ret)
1364         set_fd_events( fd, 0 ); /* stop waiting on select() if we are signaled */
1365     else if (obj->head)
1366         set_fd_events( fd, events ); /* restart waiting on poll() if we are no longer signaled */
1367
1368     release_object( fd );
1369     return ret;
1370 }
1371
1372 /* default handler for poll() events */
1373 void default_poll_event( struct fd *fd, int event )
1374 {
1375     /* an error occurred, stop polling this fd to avoid busy-looping */
1376     if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
1377     wake_up( fd->user, 0 );
1378 }
1379
1380 /* default flush() routine */
1381 int no_flush( struct fd *fd, struct event **event )
1382 {
1383     set_error( STATUS_OBJECT_TYPE_MISMATCH );
1384     return 0;
1385 }
1386
1387 /* default get_file_info() routine */
1388 int no_get_file_info( struct fd *fd )
1389 {
1390     set_error( STATUS_OBJECT_TYPE_MISMATCH );
1391     return 0;
1392 }
1393
1394 /* default queue_async() routine */
1395 void no_queue_async( struct fd *fd, void* apc, void* user, void* io_sb, 
1396                      int type, int count)
1397 {
1398     set_error( STATUS_OBJECT_TYPE_MISMATCH );
1399 }
1400
1401 /* default cancel_async() routine */
1402 void no_cancel_async( struct fd *fd )
1403 {
1404     set_error( STATUS_OBJECT_TYPE_MISMATCH );
1405 }
1406
1407 /* same as get_handle_obj but retrieve the struct fd associated to the object */
1408 static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handle,
1409                                      unsigned int access )
1410 {
1411     struct fd *fd = NULL;
1412     struct object *obj;
1413
1414     if ((obj = get_handle_obj( process, handle, access, NULL )))
1415     {
1416         fd = get_obj_fd( obj );
1417         release_object( obj );
1418     }
1419     return fd;
1420 }
1421
1422 /* flush a file buffers */
1423 DECL_HANDLER(flush_file)
1424 {
1425     struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
1426     struct event * event = NULL;
1427
1428     if (fd)
1429     {
1430         fd->fd_ops->flush( fd, &event );
1431         if ( event )
1432         {
1433             reply->event = alloc_handle( current->process, event, SYNCHRONIZE, 0 );
1434         }
1435         release_object( fd );
1436     }
1437 }
1438
1439 /* get a Unix fd to access a file */
1440 DECL_HANDLER(get_handle_fd)
1441 {
1442     struct fd *fd;
1443
1444     reply->fd = -1;
1445
1446     if ((fd = get_handle_fd_obj( current->process, req->handle, req->access )))
1447     {
1448         int unix_fd = get_handle_unix_fd( current->process, req->handle, req->access );
1449         if (unix_fd != -1) reply->fd = unix_fd;
1450         else if (!get_error())
1451         {
1452             assert( fd->unix_fd != -1 );
1453             send_client_fd( current->process, fd->unix_fd, req->handle );
1454         }
1455         reply->flags = fd->fd_ops->get_file_info( fd );
1456         release_object( fd );
1457     }
1458 }
1459
1460 /* create / reschedule an async I/O */
1461 DECL_HANDLER(register_async)
1462 {
1463     struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
1464
1465     /*
1466      * The queue_async method must do the following:
1467      *
1468      * 1. Get the async_queue for the request of given type.
1469      * 2. Create a new asynchronous request for the selected queue
1470      * 3. Carry out any operations necessary to adjust the object's poll events
1471      *    Usually: set_elect_events (obj, obj->ops->get_poll_events()).
1472      * 4. When the async request is triggered, then send back (with a proper APC)
1473      *    the trigger (STATUS_ALERTED) to the thread that posted the request. 
1474      *    async_destroy() is to be called: it will both notify the sender about
1475      *    the trigger and destroy the request by itself
1476      * See also the implementations in file.c, serial.c, and sock.c.
1477      */
1478
1479     if (fd)
1480     {
1481         fd->fd_ops->queue_async( fd, req->io_apc, req->io_user, req->io_sb, 
1482                                  req->type, req->count );
1483         release_object( fd );
1484     }
1485 }
1486
1487 /* cancels all async I/O */
1488 DECL_HANDLER(cancel_async)
1489 {
1490     struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
1491     if (fd)
1492     {
1493         /* Note: we don't kill the queued APC_ASYNC_IO on this thread because
1494          * NtCancelIoFile() will force the pending APC to be run. Since, 
1495          * Windows only guarantees that the current thread will have no async 
1496          * operation on the current fd when NtCancelIoFile returns, this shall
1497          * do the work.
1498          */
1499         fd->fd_ops->cancel_async( fd );
1500         release_object( fd );
1501     }        
1502 }