b99896fc978a8edc0a9310037cd14711a0501536
[enigma2.git] / lib / base / filepush.cpp
1 #include <config.h>
2 #include <lib/base/filepush.h>
3 #include <lib/base/eerror.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <sys/ioctl.h>
7
8 #define PVR_COMMIT 1
9
10 eFilePushThread::eFilePushThread(): m_messagepump(eApp, 0)
11 {
12         m_stop = 0;
13         m_sg = 0;
14         flush();
15         enablePVRCommit(0);
16         CONNECT(m_messagepump.recv_msg, eFilePushThread::recvEvent);
17 }
18
19 static void signal_handler(int x)
20 {
21 }
22
23 void eFilePushThread::thread()
24 {
25         off_t dest_pos = 0;
26         size_t bytes_read = 0;
27         
28         off_t current_span_offset;
29         size_t current_span_remaining = 0;
30         
31         int already_empty = 0;
32         eDebug("FILEPUSH THREAD START");
33                 // this is a race. FIXME.
34         
35                 /* we set the signal to not restart syscalls, so we can detect our signal. */
36         struct sigaction act;
37         act.sa_handler = signal_handler; // no, SIG_IGN doesn't do it. we want to receive the -EINTR
38         act.sa_flags = 0;
39         sigaction(SIGUSR1, &act, 0);
40         
41         dest_pos = lseek(m_fd_dest, 0, SEEK_CUR);
42                 /* m_stop must be evaluated after each syscall. */
43         while (!m_stop)
44         {
45                         /* first try flushing the bufptr */
46                 if (m_buf_start != m_buf_end)
47                 {
48                                 // TODO: take care of boundaries.
49                         int w = write(m_fd_dest, m_buffer + m_buf_start, m_buf_end - m_buf_start);
50 //                      eDebug("wrote %d bytes", w);
51                         if (w <= 0)
52                         {
53                                 if (errno == -EINTR)
54                                         continue;
55                                 eDebug("eFilePushThread *write error* (%m) - not yet handled");
56                                 // ... we would stop the thread
57                         }
58
59                                 /* this should flush all written pages to disk. */
60                         posix_fadvise(m_fd_dest, dest_pos, w, POSIX_FADV_DONTNEED);
61
62                         dest_pos += w;
63 //                      printf("FILEPUSH: wrote %d bytes\n", w);
64                         m_buf_start += w;
65                         continue;
66                 }
67
68                         /* now fill our buffer. */
69                         
70                 if (m_sg && !current_span_remaining)
71                 {
72                         m_sg->getNextSourceSpan(bytes_read, current_span_offset, current_span_remaining);
73                         bytes_read = 0;
74                 }
75                 
76                 size_t maxread = sizeof(m_buffer);
77                 
78                         /* if we have a source span, don't read past the end */
79                 if (m_sg && maxread < current_span_remaining)
80                         maxread = current_span_remaining;
81
82                 m_buf_start = 0;
83                 m_buf_end = 0;
84                 
85                 if (maxread)
86                         m_buf_end = read(m_fd_source, m_buffer, maxread);
87
88                 bytes_read += m_buf_end;
89
90                 if (m_buf_end < 0)
91                 {
92                         m_buf_end = 0;
93                         if (errno == EINTR)
94                                 continue;
95                         eDebug("eFilePushThread *read error* - not yet handled");
96                 }
97                 if (m_buf_end == 0)
98                 {
99                                 /* on EOF, try COMMITting once. */
100                         if (m_send_pvr_commit && !already_empty)
101                         {
102                                 eDebug("sending PVR commit");
103                                 already_empty = 1;
104                                 if (::ioctl(m_fd_dest, PVR_COMMIT) == EINTR)
105                                         continue;
106                                 eDebug("commit done");
107                                                 /* well check again */
108                                 continue;
109                         }
110                         sendEvent(evtEOF);
111 #if 0
112                         eDebug("FILEPUSH: end-of-file! (currently unhandled)");
113                         if (!lseek(m_fd_source, 0, SEEK_SET))
114                         {
115                                 eDebug("(looping)");
116                                 continue;
117                         }
118 #endif
119                         break;
120                 } else
121                         already_empty = 0;
122 //              printf("FILEPUSH: read %d bytes\n", m_buf_end);
123         }
124         
125         eDebug("FILEPUSH THREAD STOP");
126 }
127
128 void eFilePushThread::start(int fd_source, int fd_dest)
129 {
130         m_fd_source = fd_source;
131         m_fd_dest = fd_dest;
132         resume();
133 }
134
135 void eFilePushThread::stop()
136 {
137         if (!thread_running()) /* FIXME: races */
138                 return;
139         m_stop = 1;
140         sendSignal(SIGUSR1);
141         kill();
142 }
143
144 void eFilePushThread::pause()
145 {
146         stop();
147 }
148
149 void eFilePushThread::seek(int whence, off_t where)
150 {
151         ::lseek(m_fd_source, where, whence);
152 }
153
154 void eFilePushThread::resume()
155 {
156         m_stop = 0;
157         run();
158 }
159
160 void eFilePushThread::flush()
161 {
162         m_buf_start = m_buf_end = 0;
163 }
164
165 void eFilePushThread::enablePVRCommit(int s)
166 {
167         m_send_pvr_commit = s;
168 }
169
170 void eFilePushThread::sendEvent(int evt)
171 {
172         m_messagepump.send(evt);
173 }
174
175 void eFilePushThread::recvEvent(const int &evt)
176 {
177         m_event(evt);
178 }