Merge branch 'master' into windows
[ardour.git] / libs / pbd / msvc / msvc_poll.cc
1 /*
2     Copyright (C) 2009 John Emmas
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef COMPILER_MSVC
21
22 //#include <glib/gtimer.h>
23 #include "pbd/msvc_pbd.h"
24
25 #ifndef _DWORD_DEFINED
26 #define _DWORD_DEFINED
27 typedef unsigned long DWORD;
28 #endif  // !_DWORD_DEFINED
29
30 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
31  *                                                                               *
32  * Note that this entire strategy failed to work, at least for pipes. It turned  *
33  * out that Windows 'tell()' always returns 0 when used on a pipe. This strategy *
34  * is now deprecated, having been replaced by a new pipe-like object, which I've *
35  * called 'PBD::pipex'. This polling functionality is included here mostly so    *
36  * that Ardour will build and launch under Windows. However, any module that     *
37  * relies on polling a pipe will eventually need to use the new pipex object.    *
38  * This code will allow it to compile and link successfully, although it won't   *
39  * poll successfully at run time. Having said that, these functions might well   *
40  * work for ports and/or other machanisms that get represented by a file handle. *
41  *                                                                               *
42  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
43
44 int poll_input (struct pollfd *fds, nfds_t nfds, int& elapsed_time, int timeout)
45 {
46 DWORD dwOldTickCount,
47       dwNewTickCount = GetTickCount();
48 bool  input = false,
49       error = false;
50 int   ret = 0;
51
52         if (NULL != fds)
53         {
54                 nfds_t loop;
55                 short ev_mask = (POLLOUT|POLLWRNORM|POLLWRBAND);
56
57                 errno = NO_ERROR;
58
59                 do
60                 {
61                         dwOldTickCount = dwNewTickCount;
62
63                         for (loop=0; loop<nfds; loop++)
64                                 fds[loop].revents = 0;
65
66                         for (loop=0; (loop<nfds && !error); loop++)
67                         {
68                                 if (!(fds[loop].events & ev_mask))
69                                 {
70                                         long pos = _tell(fds[loop].fd);
71
72                                         if (0 > pos)
73                                         {
74                                                 // An error occured ('errno' should have been set by '_tell()')
75                                                 ret = (-1);
76                                                 fds[loop].revents = POLLERR;
77                                                 if (fds[loop].events & POLLRDNORM)
78                                                         fds[loop].revents |= POLLRDNORM;
79                                                 if (fds[loop].events & POLLRDBAND)
80                                                         fds[loop].revents |= POLLRDBAND;
81                                                 if (fds[loop].events & POLLPRI)
82                                                         fds[loop].revents |= POLLPRI;
83
84                                                 // Do we want to abort on error?
85                                                 if (fds[loop].events & POLLERR)
86                                                         error = true;
87                                         }
88                                         else if (pos > 0)
89                                         {
90                                                 // Input characters were found for this fd
91                                                 ret += 1;
92                                                 if (fds[loop].events & POLLRDNORM)
93                                                         fds[loop].revents |= POLLRDNORM;
94                                                 if (fds[loop].events & POLLRDBAND)
95                                                         fds[loop].revents |= POLLRDBAND;
96                                                 if (fds[loop].events & POLLPRI)
97                                                         fds[loop].revents |= POLLPRI;
98
99                                                 // Do we want to abort on input?
100                                                 if ((fds[loop].events & POLLIN)     ||
101                                                     (fds[loop].events & POLLPRI)    ||
102                                                     (fds[loop].events & POLLRDNORM) ||
103                                                     (fds[loop].events & POLLRDBAND))
104                                                         input = true;
105                                         }
106                                 }
107                         }
108
109                         if (input)
110                                 break;
111
112                         dwNewTickCount = GetTickCount();
113                         elapsed_time += (dwNewTickCount-dwOldTickCount);
114                         // Note that the above will wrap round if the user leaves
115                         // his computer powered up for more than about 50 days!
116
117                         // Sleep briefly because GetTickCount() only has an accuracy of 10mS
118                         Sleep(10); // For some reason 'g_usleep()' craps over everything here. Different 'C' runtimes???
119
120                 } while ((!error) && ((timeout == (-1)) || (elapsed_time < timeout)));
121         }
122         else
123         {
124                 errno = ERROR_BAD_ARGUMENTS;
125                 ret = (-1);
126         }
127
128         return (ret);
129 }
130
131 int poll_output (struct pollfd *fds, nfds_t nfds, int& elapsed_time, int timeout)
132 {
133 int ret = 0; // This functionality is not yet implemented
134
135         if (NULL != fds)
136         {
137                 // Just flag whichever pollfd was specified for writing
138                 short ev_mask = (POLLOUT|POLLWRNORM|POLLWRBAND);
139
140                 errno = NO_ERROR;
141                 elapsed_time = 0;
142
143                 for (nfds_t loop=0; loop<nfds; loop++)
144                 {
145                         if (fds[loop].events & ev_mask)
146                         {
147                                 fds[loop].revents = POLLNVAL;
148                                 errno = ERROR_INVALID_ACCESS;
149                                 ret = (-1);
150                         }
151                 }
152         }
153         else
154         {
155                 errno = ERROR_BAD_ARGUMENTS;
156                 ret = (-1);
157         }
158
159         return (ret);
160 }
161
162 //***************************************************************
163 //
164 //      poll()
165 //
166 // Emulates POSIX poll() using Win32 _tell().
167 //
168 //      Returns:
169 //
170 //    On Success: A positive integer indicating the total number
171 //                of file descriptors that were available for
172 //                writing or had data available for reading.
173 //    On Failure: -1 (the actual error is saved in 'errno').
174 //
175 PBD_API int PBD_APICALLTYPE
176 poll (struct pollfd *fds, nfds_t nfds, int timeout)
177 {
178 int elapsed_time = 0;
179 int ret = (-1);
180
181         // Note that this functionality is not fully implemented.
182         // At the time of writing, Ardour seems only to poll on
183         // read pipes. Therefore return an error if any write
184         // pipe seems to have been specified or if too many file
185         // descriptors were passed.
186         short ev_mask = (POLLOUT|POLLWRNORM|POLLWRBAND);
187
188         if ((nfds > OPEN_MAX) || (nfds > NPOLLFILE))
189         {
190                 errno = ERROR_TOO_MANY_OPEN_FILES;
191         }
192         else
193         {
194                 ret = 0;
195
196                 for (nfds_t loop=0; loop<nfds; loop++)
197                 {
198                         if (fds[loop].events & ev_mask)
199                         {
200                                 ret = poll_output(fds, nfds, elapsed_time, timeout);
201                                 break;
202                         }
203                 }
204
205                 if (0 == ret)
206                 {
207                         // Poll for input
208                         ret = poll_input(fds, nfds, elapsed_time, timeout);
209                 }
210         }
211
212         return (ret);
213 }
214
215 #endif  //COMPILER_MSVC