Cygwin: dsp: Implement select()/poll().

Previously, sound device /dev/dsp did not support select()/poll().
These have been implemented with this patch.

Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
This commit is contained in:
Takashi Yano 2023-09-06 22:03:18 +09:00
parent 7a43763d24
commit 2c06014f12
4 changed files with 187 additions and 1 deletions

View File

@ -1483,3 +1483,41 @@ fhandler_dev_dsp::_fixup_after_exec ()
audio_out_ = NULL;
}
}
bool
fhandler_dev_dsp::_write_ready ()
{
audio_buf_info info;
if (audio_out_)
{
audio_out_->buf_info (&info, audiofreq_, audiobits_, audiochannels_);
return info.bytes > 0;
}
else
return true;
}
bool
fhandler_dev_dsp::_read_ready ()
{
audio_buf_info info;
if (audio_in_)
{
audio_in_->buf_info (&info, audiofreq_, audiobits_, audiochannels_);
return info.bytes > 0;
}
else
return true;
}
bool
fhandler_dev_dsp::write_ready ()
{
return base ()->_write_ready ();
}
bool
fhandler_dev_dsp::read_ready ()
{
return base ()->_read_ready ();
}

View File

@ -2847,6 +2847,9 @@ class fhandler_dev_dsp: public fhandler_base
void close_audio_in ();
void close_audio_out (bool = false);
bool _read_ready();
bool _write_ready();
public:
bool use_archetype () const {return true;}
@ -2866,6 +2869,14 @@ class fhandler_dev_dsp: public fhandler_base
fh->copy_from (this);
return fh;
}
/* select.cc */
select_record *select_read (select_stuff *);
select_record *select_write (select_stuff *);
select_record *select_except (select_stuff *);
bool read_ready();
bool write_ready();
};
class fhandler_virtual : public fhandler_base

View File

@ -87,6 +87,11 @@ struct select_socket_info: public select_info
select_socket_info (): select_info (), num_w4 (0), ser_num (0), w4 (NULL) {}
};
struct select_dsp_info: public select_info
{
select_dsp_info (): select_info () {}
};
class select_stuff
{
public:
@ -112,6 +117,7 @@ public:
select_pipe_info *device_specific_ptys;
select_fifo_info *device_specific_fifo;
select_socket_info *device_specific_socket;
select_dsp_info *device_specific_dsp;
bool test_and_set (int, fd_set *, fd_set *, fd_set *);
int poll (fd_set *, fd_set *, fd_set *);
@ -125,7 +131,8 @@ public:
device_specific_pipe (NULL),
device_specific_ptys (NULL),
device_specific_fifo (NULL),
device_specific_socket (NULL)
device_specific_socket (NULL),
device_specific_dsp (NULL)
{}
};

View File

@ -2255,3 +2255,133 @@ fhandler_timerfd::select_except (select_stuff *stuff)
s->except_ready = false;
return s;
}
static int
peek_dsp (select_record *s, bool from_select)
{
int gotone = 0;
fhandler_dev_dsp *fh = (fhandler_dev_dsp *)(fhandler_base *) s->fh;
if (s->read_selected)
if (s->read_ready || fh->read_ready ())
gotone += s->read_ready = true;
if (s->write_selected)
if (s->write_ready || fh->write_ready ())
gotone += s->write_ready = true;
return gotone;
}
static int start_thread_dsp (select_record *me, select_stuff *stuff);
static DWORD
thread_dsp (void *arg)
{
select_dsp_info *di = (select_dsp_info *) arg;
DWORD sleep_time = 0;
bool looping = true;
while (looping)
{
for (select_record *s = di->start; (s = s->next); )
if (s->startup == start_thread_dsp)
{
if (peek_dsp (s, true))
looping = false;
if (di->stop_thread)
{
select_printf ("stopping");
looping = false;
break;
}
}
if (!looping)
break;
cygwait (sleep_time >> 3);
if (sleep_time < 80)
++sleep_time;
if (di->stop_thread)
break;
}
return 0;
}
static int
start_thread_dsp (select_record *me, select_stuff *stuff)
{
select_dsp_info *di = stuff->device_specific_dsp;
if (di->start)
me->h = *((select_dsp_info *) stuff->device_specific_dsp)->thread;
else
{
di->start = &stuff->start;
di->stop_thread = false;
di->thread = new cygthread (thread_dsp, di, "dspsel");
me->h = *di->thread;
if (!me->h)
return 0;
}
return 1;
}
static void
dsp_cleanup (select_record *aaa, select_stuff *stuff)
{
select_dsp_info *di = (select_dsp_info *) stuff->device_specific_dsp;
if (!di)
return;
if (di->thread)
{
di->stop_thread = true;
di->thread->detach ();
}
delete di;
stuff->device_specific_dsp = NULL;
}
select_record *
fhandler_dev_dsp::select_read (select_stuff *stuff)
{
if (!stuff->device_specific_dsp
&& (stuff->device_specific_dsp = new select_dsp_info) == NULL)
return NULL;
select_record *s = stuff->start.next;
s->startup = start_thread_dsp;
s->peek = peek_dsp;
s->verify = verify_ok;
s->cleanup = dsp_cleanup;
s->read_selected = true;
s->read_ready = false;
return s;
}
select_record *
fhandler_dev_dsp::select_write (select_stuff *stuff)
{
if (!stuff->device_specific_dsp
&& (stuff->device_specific_dsp = new select_dsp_info) == NULL)
return NULL;
select_record *s = stuff->start.next;
s->startup = start_thread_dsp;
s->peek = peek_dsp;
s->verify = verify_ok;
s->cleanup = dsp_cleanup;
s->write_selected = true;
s->write_ready = false;
return s;
}
select_record *
fhandler_dev_dsp::select_except (select_stuff *stuff)
{
if (!stuff->device_specific_dsp
&& (stuff->device_specific_dsp = new select_dsp_info) == NULL)
return NULL;
select_record *s = stuff->start.next;
s->startup = start_thread_dsp;
s->peek = peek_dsp;
s->verify = verify_ok;
s->cleanup = dsp_cleanup;
s->except_selected = true;
s->except_ready = false;
return s;
}