* sysdeps/mach/hurd/fork.c (LOSE): Put `goto lose' in dead code
[jlayton/glibc.git] / rt / aio_notify.c
1 /* Notify initiator of AIO request.
2    Copyright (C) 1997,98,99,2000,01 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C 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    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <errno.h>
22 #include <pthread.h>
23 #include <stdlib.h>
24 #include "aio_misc.h"
25
26
27 static void *
28 notify_func_wrapper (void *arg)
29 {
30   struct sigevent *sigev = arg;
31   sigev->sigev_notify_function (sigev->sigev_value);
32   return NULL;
33 }
34
35
36 int
37 internal_function
38 __aio_notify_only (struct sigevent *sigev, pid_t caller_pid)
39 {
40   int result = 0;
41
42   /* Send the signal to notify about finished processing of the request.  */
43   if (sigev->sigev_notify == SIGEV_THREAD)
44     {
45       /* We have to start a thread.  */
46       pthread_t tid;
47       pthread_attr_t attr, *pattr;
48
49       pattr = (pthread_attr_t *) sigev->sigev_notify_attributes;
50       if (pattr == NULL)
51         {
52           pthread_attr_init (&attr);
53           pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
54           pattr = &attr;
55         }
56
57       if (pthread_create (&tid, pattr, notify_func_wrapper, sigev) < 0)
58         result = -1;
59     }
60   else if (sigev->sigev_notify == SIGEV_SIGNAL)
61     {
62       /* We have to send a signal.  */
63 #if _POSIX_REALTIME_SIGNALS
64       /* Note that the standard gives us the option of using a plain
65          non-queuing signal here when SA_SIGINFO is not set for the signal.  */
66       if (__aio_sigqueue (sigev->sigev_signo, sigev->sigev_value, caller_pid)
67           < 0)
68         result = -1;
69 #else
70       /* There are no queued signals on this system at all.  */
71       result = raise (sigev->sigev_signo);
72 #endif
73     }
74
75   return result;
76 }
77
78
79 void
80 internal_function
81 __aio_notify (struct requestlist *req)
82 {
83   struct waitlist *waitlist;
84   struct aiocb *aiocbp = &req->aiocbp->aiocb;
85
86   if (__aio_notify_only (&aiocbp->aio_sigevent, req->caller_pid) != 0)
87     {
88       /* XXX What shall we do if already an error is set by
89          read/write/fsync?  */
90       aiocbp->__error_code = errno;
91       aiocbp->__return_value = -1;
92     }
93
94   /* Now also notify possibly waiting threads.  */
95   waitlist = req->waiting;
96   while (waitlist != NULL)
97     {
98       struct waitlist *next = waitlist->next;
99
100       /* Decrement the counter.  This is used in both cases.  */
101       --*waitlist->counterp;
102
103       if (waitlist->sigevp == NULL)
104         pthread_cond_signal (waitlist->cond);
105       else
106         /* This is part of a asynchronous `lio_listio' operation.  If
107            this request is the last one, send the signal.  */
108         if (*waitlist->counterp == 0)
109           {
110             __aio_notify_only (waitlist->sigevp, waitlist->caller_pid);
111             /* This is tricky.  See lio_listio.c for the reason why
112                this works.  */
113             free ((void *) waitlist->counterp);
114           }
115
116       waitlist = next;
117     }
118 }