1 /*
2 * cdda - CD Digital Audio support
3 *
4 * Copyright (C) 1993-2004 Ti Kan
5 * E-mail: xmcd@amb.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * This file contains code to support CDDA operations with
22 * parallel reader/writer threads implemented using POSIX 1003.1c
23 * threads.
24 */
25 #ifndef lint
26 static char *_pthr_c_ident_ = "@(#)pthr.c 7.54 04/03/17";
27 #endif
28
29 #include "common_d/appenv.h"
30 #include "common_d/util.h"
31 #include "libdi_d/libdi.h"
32 #include "cdda_d/cdda.h"
33 #include "cdda_d/common.h"
34 #include <stdint.h>
35
36
37 #ifdef CDDA_PTHREADS
38
39 #include <sys/param.h>
40 #include "cdda_d/pthr.h"
41
42 /*
43 * Platform-specific configuration for thread scheduling control
44 */
45 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && \
46 (defined(_POSIX_PRIORITY_SCHEDULING) || \
47 defined(PTHREAD_SCHED_MAX_PRIORITY))
48 /* If these are defined in <unistd.h> and <pthread.h> then the
49 * system fully supports POSIX priority scheduling control for
50 * threads.
51 */
52 #define USE_POSIX_THREAD_SCHED
53 #endif
54
55
56 extern appdata_t app_data;
57 extern FILE *errfp;
58 extern cdda_client_t *cdda_clinfo;
59
60 extern cdda_rd_tbl_t cdda_rd_calltbl[];
61 extern cdda_wr_tbl_t cdda_wr_calltbl[];
62
63 /* Semaphore structure */
64 typedef struct {
65 pthread_mutex_t mutex;
66 pthread_cond_t cond;
67 int v;
68 } pthr_sem_t;
69
70 #define PTHR_NSEMS 3 /* Number of semaphores */
71
72 STATIC void *pthr_shmaddr; /* Shared memory pointer */
73 STATIC int skip_hbchk = 0; /* Skip heartbeat checking */
74 STATIC cd_state_t *cd = NULL; /* CD state pointer */
75 STATIC char errbuf[ERR_BUF_SZ]; /* Error message buffer */
76 STATIC pthr_sem_t pthr_sem[PTHR_NSEMS]; /* LOCK, ROOM and DATA */
77 STATIC void (*opipe)(int); /* Saved SIGPIPE handler */
78
79
80 /*
81 * cdda_pthr_highpri
82 * Increase the calling thread's scheduling priority
83 *
84 * Args:
85 * name - thread name string
86 *
87 * Return:
88 * Nothing.
89 */
90 STATIC void
cdda_pthr_highpri(char * name)91 cdda_pthr_highpri(char *name)
92 {
93 #ifdef USE_POSIX_THREAD_SCHED
94 int ret,
95 minpri,
96 maxpri;
97 pthread_t tid;
98 struct sched_param scparm;
99
100 #ifdef HAS_EUID
101 uid_t savuid = geteuid();
102
103 if (util_seteuid(0) < 0 || geteuid() != 0) {
104 DBGPRN(DBG_GEN)(errfp,
105 "cdda_pthr_setpri: Cannot change scheduling: "
106 "Insufficient privilege.\n");
107 (void) util_seteuid(savuid);
108 return;
109 }
110 #endif
111
112 tid = pthread_self();
113
114 /* Set priority to 80% between min and max */
115 #ifdef PTHREAD_SCHED_MAX_PRIORITY
116 minpri = PTHREAD_SCHED_MIN_PRIORITY;
117 maxpri = PTHREAD_SCHED_MAX_PRIORITY;
118 #else
119 minpri = sched_get_priority_min(SCHED_RR);
120 maxpri = sched_get_priority_max(SCHED_RR);
121 #endif
122 if (minpri < 0 || maxpri < 0) {
123 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_highpri: "
124 "Failed getting min/max priority values: "
125 "errno=%d\n", errno);
126 #ifdef HAS_EUID
127 (void) util_seteuid(savuid);
128 #endif
129 return;
130 }
131
132 scparm.sched_priority = ((maxpri - minpri) * 8 / 10) + minpri;
133
134 if ((ret = pthread_setschedparam(tid, SCHED_RR, &scparm)) < 0) {
135 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_highpri: "
136 "pthread_setschedparam failed: "
137 "ret=%d\n", ret);
138 #ifdef HAS_EUID
139 (void) util_seteuid(savuid);
140 #endif
141 return;
142 }
143
144 DBGPRN(DBG_GEN)(errfp,
145 "\n%s running POSIX SCHED_RR scheduling (thread id=%ju)\n"
146 "Priority=%d (range: %d,%d)\n",
147 name, (uintmax_t) tid, scparm.sched_priority, minpri, maxpri);
148
149 #ifdef HAS_EUID
150 (void) util_seteuid(savuid);
151 #endif
152 #endif /* USE_POSIX_THREAD_SCHED */
153 }
154
155
156 /*
157 * cdda_pthr_atfork
158 * Child process handler function for fork(2), registered and called
159 * from pthread_atfork(3), so that the child process can run without
160 * being blocked in mutexes.
161 *
162 * Args:
163 * None.
164 *
165 * Return:
166 * Nothing.
167 */
168 STATIC void
cdda_pthr_atfork(void)169 cdda_pthr_atfork(void)
170 {
171 int i,
172 ret;
173
174 /* Initialize all mutexes to unlocked state */
175 for (i = 0; i < PTHR_NSEMS; i++) {
176 ret = pthread_mutex_init(&pthr_sem[i].mutex, NULL);
177 if (ret != 0) {
178 (void) sprintf(errbuf,
179 "cdda_pthr_atfork: pthread_mutex_init failed "
180 "(sem %d, ret=%d)",
181 i, ret);
182 CDDA_INFO(errbuf);
183 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
184 }
185 }
186 }
187
188
189 /*
190 * cdda_pthr_getsem
191 * Initialize semaphores, making lock available.
192 *
193 * Args:
194 * None.
195 *
196 * Return:
197 * FALSE - failure
198 * TRUE - success
199 */
200 STATIC bool_t
cdda_pthr_getsem(void)201 cdda_pthr_getsem(void)
202 {
203 int i,
204 ret;
205
206 for (i = 0; i < PTHR_NSEMS; i++) {
207 pthr_sem[i].v = 0;
208
209 ret = pthread_mutex_init(&pthr_sem[i].mutex, NULL);
210 if (ret != 0) {
211 (void) sprintf(errbuf,
212 "cdda_pthr_getsem: pthread_mutex_init failed "
213 "(sem %d, ret=%d)",
214 i, ret);
215 CDDA_INFO(errbuf);
216 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
217 return FALSE;
218 }
219
220 ret = pthread_cond_init(&pthr_sem[i].cond, NULL);
221 if (ret != 0) {
222 (void) sprintf(errbuf,
223 "cdda_pthr_getsem: pthread_cond_init failed "
224 "(sem %d, ret=%d)",
225 i, ret);
226 CDDA_INFO(errbuf);
227 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
228 return FALSE;
229 }
230 }
231
232 /* Make lock available */
233 pthr_sem[LOCK].v = 1;
234
235 return TRUE;
236 }
237
238
239 /*
240 * cdda_pthr_getshm
241 * Initialize shared memory. We first work out how much shared
242 * memory we require and fill in a temporary cd_size_t structure
243 * along the way. We then create the shared memory segment and
244 * set the fields of *cd pointing into it.
245 *
246 * Args:
247 * None.
248 *
249 * Return:
250 * FALSE - failure
251 * TRUE - success
252 */
253 STATIC bool_t
cdda_pthr_getshm(void)254 cdda_pthr_getshm(void)
255 {
256 cd_size_t *cd_tmp_size;
257
258 /* Store sizes here temporarily */
259 cd_tmp_size = (cd_size_t *) MEM_ALLOC(
260 "cd_tmp_size", sizeof(cd_size_t)
261 );
262 if (cd_tmp_size == NULL) {
263 CDDA_FATAL(app_data.str_nomemory);
264 return FALSE;
265 }
266
267 (void) memset(cd_tmp_size, 0, sizeof(cd_size_t));
268
269 /* Sizes */
270 cd_tmp_size->str_length = DEF_CDDA_STR_LEN;
271 cd_tmp_size->chunk_blocks = app_data.cdda_readchkblks;
272
273 /* Sizes depend on jitter */
274 if (app_data.cdda_jitter_corr) {
275 cd_tmp_size->olap_blocks = DEF_CDDA_OLAP_BLKS;
276 cd_tmp_size->search_blocks = DEF_CDDA_SRCH_BLKS;
277 }
278 else {
279 cd_tmp_size->olap_blocks = 0;
280 cd_tmp_size->search_blocks = 0;
281 }
282
283 /* Chunk bytes */
284 cd_tmp_size->chunk_bytes = cd_tmp_size->chunk_blocks * CDDA_BLKSZ;
285
286 /* Buffer chunks */
287 cd_tmp_size->buffer_chunks =
288 (FRAME_PER_SEC * DEF_CDDA_BUFFER_SECS) /
289 cd_tmp_size->chunk_blocks;
290 /* Check if we need to round up */
291 if (((FRAME_PER_SEC * DEF_CDDA_BUFFER_SECS) %
292 cd_tmp_size->chunk_blocks) != 0)
293 cd_tmp_size->buffer_chunks++;
294
295 /* Buffer blocks */
296 cd_tmp_size->buffer_blocks =
297 cd_tmp_size->buffer_chunks * cd_tmp_size->chunk_blocks;
298
299 /* Buffer bytes */
300 cd_tmp_size->buffer_bytes =
301 cd_tmp_size->buffer_chunks * cd_tmp_size->chunk_bytes;
302
303 /* Overlap bytes */
304 cd_tmp_size->olap_bytes = cd_tmp_size->olap_blocks * CDDA_BLKSZ;
305
306 /* Search */
307 cd_tmp_size->search_bytes = cd_tmp_size->search_blocks * CDDA_BLKSZ;
308
309 /* How much shared memory do we need? */
310 cd_tmp_size->size =
311 sizeof(cd_size_t) + sizeof(cd_info_t) + sizeof(cd_buffer_t);
312
313 /* Add memory for overlap */
314 cd_tmp_size->size += (cd_tmp_size->search_bytes << 1);
315
316 /* Add memory for data read */
317 cd_tmp_size->size +=
318 cd_tmp_size->chunk_bytes + (cd_tmp_size->olap_bytes << 1);
319
320 /* Add memory for buffer */
321 cd_tmp_size->size += cd_tmp_size->buffer_bytes;
322
323 /* Now create the pthread shared memory: just malloc it */
324 pthr_shmaddr = (byte_t *) MEM_ALLOC("cdda_shm", cd_tmp_size->size);
325 if (pthr_shmaddr == NULL) {
326 (void) sprintf(errbuf, "cdda_pthr_getshm: Out of memory.");
327 CDDA_INFO(errbuf);
328 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
329 MEM_FREE(cd_tmp_size);
330 return FALSE;
331 }
332
333 /* Now set our fields pointing into the shared memory */
334 cd->cds = (cd_size_t *) pthr_shmaddr;
335
336 /* Copy in sizes */
337 (void) memcpy(pthr_shmaddr, cd_tmp_size, sizeof(cd_size_t));
338
339 /* Info */
340 cd->i = (cd_info_t *)(void *)
341 ((byte_t *) pthr_shmaddr + sizeof(cd_size_t));
342
343 /* Buffer */
344 cd->cdb = (cd_buffer_t *)(void *)
345 ((byte_t *) cd->i + sizeof(cd_info_t));
346
347 /* Overlap */
348 cd->cdb->olap = (byte_t *) ((byte_t *) cd->cdb + sizeof(cd_buffer_t));
349
350 /* Data */
351 cd->cdb->data = (byte_t *)
352 ((byte_t *) cd->cdb->olap +
353 (cd->cds->search_bytes << 1));
354
355 /* Buffer */
356 cd->cdb->b = (byte_t *)
357 ((byte_t *) cd->cdb->data +
358 cd->cds->chunk_bytes +
359 (cd->cds->olap_bytes << 1));
360
361 /* Free temporary cd_size_t */
362 MEM_FREE(cd_tmp_size);
363 return TRUE;
364 }
365
366
367 /*
368 * cdda_pthr_initshm
369 * Initialize fields of the cd_state_t structure. The cd_size_t structure
370 * has already been done in cdda_pthr_getshm(). The buffer we initialize
371 * prior to playing.
372 *
373 * Args:
374 * s - Pointer to the curstat_t structure.
375 *
376 * Return:
377 * Nothing.
378 */
379 STATIC void
cdda_pthr_initshm(curstat_t * s)380 cdda_pthr_initshm(curstat_t *s)
381 {
382 /* General state */
383 cd->i->state = CDSTAT_COMPLETED;
384 cd->i->chroute = app_data.ch_route;
385 cd->i->att = s->cdda_att;
386 cd->i->outport = (int) app_data.outport;
387 cd->i->vol_taper = app_data.vol_taper;
388 cd->i->vol = 0;
389 cd->i->vol_left = 100;
390 cd->i->vol_right = 100;
391 cd->i->jitter = (int) app_data.cdda_jitter_corr;
392 cd->i->frm_played = 0;
393 cd->i->trk_idx = 0;
394 cd->i->trk_len = 0;
395 cd->i->debug = app_data.debug;
396
397 /* Start and ending LBAs for tracks */
398 cd->i->start_lba = 0;
399 cd->i->end_lba = 0;
400
401 /* Initial frames per second statistic */
402 cd->i->frm_per_sec = 0;
403
404 /* Process ids */
405 cd->i->reader = (thid_t) 0;
406 cd->i->writer = (thid_t) 0;
407
408 /* Reader and writer heartbeats */
409 cd->i->reader_hb = 0;
410 cd->i->writer_hb = 0;
411
412 /* heartbeat timeouts */
413 cd->i->reader_hb_timeout = app_data.hb_timeout;
414 cd->i->writer_hb_timeout = app_data.hb_timeout * DEF_CDDA_BUFFER_SECS;
415 }
416
417
418 /*
419 * cdda_pthr_wdone
420 * Write thread cleanup. This is called when the write thread is
421 * forcibly canceled.
422 *
423 * Args:
424 * p - Unused
425 *
426 * Return:
427 * Nothing.
428 */
429 /*ARGSUSED*/
430 STATIC void
cdda_pthr_wdone(void * p)431 cdda_pthr_wdone(void *p)
432 {
433 void (*wdone)(bool_t);
434
435 wdone = cdda_wr_calltbl[app_data.cdda_wrmethod].writedone;
436
437 /* Call cleanup function */
438 (*wdone)(FALSE);
439 }
440
441
442 /*
443 * cdda_pthr_rdone
444 * Read thread cleanup. This is called when the read thread is
445 * forcibly canceled.
446 *
447 * Args:
448 * p - Unused
449 *
450 * Return:
451 * Nothing.
452 */
453 /*ARGSUSED*/
454 STATIC void
cdda_pthr_rdone(void * p)455 cdda_pthr_rdone(void *p)
456 {
457 void (*rdone)(bool_t);
458
459 rdone = cdda_rd_calltbl[app_data.cdda_rdmethod].readdone;
460
461 /* Call cleanup function */
462 (*rdone)(FALSE);
463 }
464
465
466 /*
467 * cdda_pthr_unblock
468 * Unblock the other threads.
469 *
470 * Args:
471 * p - Unused
472 *
473 * Return:
474 * Nothing.
475 */
476 /*ARGSUSED*/
477 STATIC void
cdda_pthr_unblock(void * p)478 cdda_pthr_unblock(void *p)
479 {
480 int i;
481
482 /*
483 * There was a problem, so we came here. This thread
484 * will no longer be part of the game, it was the only competing
485 * thread for the resources, which it still may have locked, so
486 * unconditionally give them up.
487 */
488 for (i = 0; i < PTHR_NSEMS; i++)
489 cdda_pthr_postsem(0, i);
490 }
491
492
493 /*
494 * cdda_pthr_writer
495 * Writer thread function
496 *
497 * Args:
498 * arg - Pointer to the curstat_t structure.
499 *
500 * Return:
501 * Always returns NULL.
502 */
503 STATIC void *
cdda_pthr_writer(void * arg)504 cdda_pthr_writer(void *arg)
505 {
506 curstat_t *s = (curstat_t *) arg;
507 int ret;
508 bool_t status,
509 (*wfunc)(curstat_t *);
510 void (*wdone)(bool_t);
511 #ifndef __VMS
512 sigset_t sigs;
513 #endif
514
515 /* Store writer thread id */
516 cd->i->writer = (thid_t) pthread_self();
517
518 DBGPRN(DBG_GEN)(errfp, "\nStarted writer thread id=%ju\n",
519 (uintmax_t) cd->i->writer);
520
521 #ifndef __VMS
522 /* Block some signals in this thread */
523 (void) sigemptyset(&sigs);
524 (void) sigaddset(&sigs, SIGPIPE);
525 (void) sigaddset(&sigs, SIGALRM);
526 #ifdef USE_SIGTHREADMASK
527 if ((ret = sigthreadmask(SIG_BLOCK, &sigs, NULL)) != 0) {
528 DBGPRN(DBG_GEN)(errfp, "sigthreadmask failed: "
529 "(writer ret=%d)\n", ret);
530 }
531 #else
532 if ((ret = pthread_sigmask(SIG_BLOCK, &sigs, NULL)) != 0) {
533 DBGPRN(DBG_GEN)(errfp, "pthread_sigmask failed: "
534 "(writer ret=%d)\n", ret);
535 }
536 #endif
537 #endif /* __VMS */
538
539 wfunc = cdda_wr_calltbl[app_data.cdda_wrmethod].writefunc;
540 wdone = cdda_wr_calltbl[app_data.cdda_wrmethod].writedone;
541
542 /* Increase writer thread scheduling priority if specified */
543 if (app_data.cdda_sched & CDDA_WRPRI)
544 cdda_pthr_highpri("Writer thread");
545
546 pthread_cleanup_push(cdda_pthr_wdone, NULL);
547 pthread_cleanup_push(cdda_pthr_unblock, NULL);
548
549 /* Call write function */
550 status = (*wfunc)(s);
551
552 pthread_cleanup_pop(0);
553 pthread_cleanup_pop(0);
554
555 /* Call cleanup function */
556 (*wdone)((bool_t) !status);
557
558 /* End of write thread */
559 pthread_exit((void *)(uintptr_t) (status ? 0 : 1));
560
561 /* Should never get here */
562 return NULL;
563 }
564
565
566 /*
567 * cdda_pthr_reader
568 * Reader thread function
569 *
570 * Args:
571 * arg - Pointer to the di_dev_t structure.
572 *
573 * Return:
574 * Always returns NULL.
575 */
576 STATIC void *
cdda_pthr_reader(void * arg)577 cdda_pthr_reader(void *arg)
578 {
579 di_dev_t *devp = (di_dev_t *) arg;
580 int ret;
581 bool_t status,
582 (*rfunc)(di_dev_t *);
583 void (*rdone)(bool_t);
584 #ifndef __VMS
585 sigset_t sigs;
586 #endif
587
588 /* Store reader thread id */
589 cd->i->reader = (thid_t) pthread_self();
590
591 DBGPRN(DBG_GEN)(errfp, "\nStarted reader thread id=%lu\n",
592 (uintmax_t) cd->i->reader);
593
594 #ifndef __VMS
595 /* Block some signals in this thread */
596 (void) sigemptyset(&sigs);
597 (void) sigaddset(&sigs, SIGPIPE);
598 (void) sigaddset(&sigs, SIGALRM);
599 #ifdef USE_SIGTHREADMASK
600 if ((ret = sigthreadmask(SIG_BLOCK, &sigs, NULL)) != 0) {
601 DBGPRN(DBG_GEN)(errfp, "sigthreadmask failed: "
602 "(reader ret=%d)\n", ret);
603 }
604 #else
605 if ((ret = pthread_sigmask(SIG_BLOCK, &sigs, NULL)) != 0) {
606 DBGPRN(DBG_GEN)(errfp, "pthread_sigmask failed: "
607 "(reader ret=%d)\n", ret);
608 }
609 #endif
610 #endif /* __VMS */
611
612 rfunc = cdda_rd_calltbl[app_data.cdda_rdmethod].readfunc;
613 rdone = cdda_rd_calltbl[app_data.cdda_rdmethod].readdone;
614
615 /* Increase reader thread scheduling priority if specified */
616 if (app_data.cdda_sched & CDDA_RDPRI)
617 cdda_pthr_highpri("Reader thread");
618
619 pthread_cleanup_push(cdda_pthr_rdone, NULL);
620 pthread_cleanup_push(cdda_pthr_unblock, NULL);
621
622 /* Call read function */
623 status = (*rfunc)(devp);
624
625 pthread_cleanup_pop(0);
626 pthread_cleanup_pop(0);
627
628 /* Call cleanup function */
629 (*rdone)((bool_t) !status);
630
631 /* End of read thread */
632 pthread_exit((void *)(uintptr_t) (status ? 0 : 1));
633
634 /* Should never get here */
635 return NULL;
636 }
637
638
639 /*
640 * cdda_pthr_cleanup
641 * Detaches shared memory, removes it and destroys semaphores.
642 *
643 * Args:
644 * None.
645 *
646 * Return:
647 * Nothing.
648 */
649 STATIC void
cdda_pthr_cleanup(void)650 cdda_pthr_cleanup(void)
651 {
652 int i,
653 ret;
654
655 if (cd == NULL)
656 return;
657
658 DBGPRN(DBG_GEN)(errfp, "\ncdda_pthr_cleanup: Cleaning up CDDA.\n");
659
660 /* Deallocate cd_state_t structure */
661 MEM_FREE(cd);
662 cd = NULL;
663
664 /* Deallocate shared memory */
665 if (pthr_shmaddr != NULL) {
666 MEM_FREE(pthr_shmaddr);
667 pthr_shmaddr = NULL;
668 }
669
670 /* Destroy semaphores */
671 for (i = 0; i < PTHR_NSEMS; i++) {
672 if ((ret = pthread_mutex_destroy(&pthr_sem[i].mutex)) != 0) {
673 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_cleanup: "
674 "pthread_mutex_destroy failed "
675 "(sem %d, ret=%d)\n",
676 i, ret);
677 }
678 if ((ret = pthread_cond_destroy(&pthr_sem[i].cond)) != 0) {
679 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_cleanup: "
680 "pthread_cond_destroy failed "
681 "(sem %d, ret=%d)\n",
682 i, ret);
683 }
684 }
685 }
686
687
688 /*
689 * cdda_pthr_init2
690 * Initialize shared memory and semaphores.
691 *
692 * Args:
693 * Pointer to the curstat_t structure.
694 *
695 * Return:
696 * TRUE - success
697 * FALSE - failure
698 */
699 STATIC bool_t
cdda_pthr_init2(curstat_t * s)700 cdda_pthr_init2(curstat_t *s)
701 {
702 /* Allocate memory */
703 cd = (cd_state_t *) MEM_ALLOC("cd_state_t", sizeof(cd_state_t));
704 if (cd == NULL)
705 /* Out of memory */
706 return FALSE;
707
708 (void) memset(cd, 0, sizeof(cd_state_t));
709
710 /* Initialize semaphores */
711 if (!cdda_pthr_getsem()) {
712 cdda_pthr_cleanup();
713 return FALSE;
714 }
715
716 /* Initialize shared memory */
717 if (!cdda_pthr_getshm()) {
718 cdda_pthr_cleanup();
719 return FALSE;
720 }
721
722 /* Initialize fields */
723 cdda_pthr_initshm(s);
724
725 DBGPRN(DBG_GEN)(errfp, "\nPTHREADS: CDDA initted.\n");
726 return TRUE;
727 }
728
729
730 /*
731 * cdda_pthr_capab
732 * Return configured CDDA capabilities
733 *
734 * Args:
735 * None.
736 *
737 * Return:
738 * Bitmask of supported CDDA read and write features
739 */
740 word32_t
cdda_pthr_capab(void)741 cdda_pthr_capab(void)
742 {
743 word32_t (*rinit)(void),
744 (*winit)(void);
745
746 if (app_data.cdda_rdmethod == CDDA_RD_NONE ||
747 app_data.cdda_wrmethod == CDDA_WR_NONE)
748 return 0;
749
750 if (app_data.cdda_rdmethod < CDDA_RD_NONE ||
751 app_data.cdda_rdmethod >= CDDA_RD_METHODS ||
752 app_data.cdda_wrmethod < CDDA_WR_NONE ||
753 app_data.cdda_wrmethod >= CDDA_WR_METHODS) {
754 CDDA_WARNING(app_data.str_cddainit_fail);
755 DBGPRN(DBG_GEN)(errfp, "Warning: %s\n",
756 app_data.str_cddainit_fail);
757 return 0;
758 }
759
760 /* Call readinit and writeinit functions to determine capability */
761 rinit = cdda_rd_calltbl[app_data.cdda_rdmethod].readinit;
762 winit = cdda_wr_calltbl[app_data.cdda_wrmethod].writeinit;
763
764 if (rinit == NULL || winit == NULL) {
765 CDDA_WARNING(app_data.str_cddainit_fail);
766 DBGPRN(DBG_GEN)(errfp, "Warning: %s\n",
767 app_data.str_cddainit_fail);
768 return 0;
769 }
770
771 return ((*rinit)() | (*winit)());
772 }
773
774
775 /*
776 * cdda_pthr_init
777 * Initialize cdda subsystem.
778 *
779 * Args:
780 * s - Pointer to the curstat_t structure.
781 *
782 * Return:
783 * FALSE - failure
784 * TRUE - success
785 */
786 /*ARGSUSED*/
787 bool_t
cdda_pthr_init(curstat_t * s)788 cdda_pthr_init(curstat_t *s)
789 {
790 if (app_data.cdda_rdmethod <= CDDA_RD_NONE ||
791 app_data.cdda_rdmethod >= CDDA_RD_METHODS ||
792 app_data.cdda_wrmethod <= CDDA_WR_NONE ||
793 app_data.cdda_wrmethod >= CDDA_WR_METHODS ||
794 cdda_rd_calltbl[app_data.cdda_rdmethod].readfunc == NULL ||
795 cdda_wr_calltbl[app_data.cdda_wrmethod].writefunc == NULL) {
796 return FALSE;
797 }
798
799 /* Defer the rest of initialization to cdda_pthr_init2 */
800 return TRUE;
801 }
802
803
804 /*
805 * cdda_pthr_halt
806 * Halt cdda subsystem.
807 *
808 * Args:
809 * devp - Read device descriptor
810 * s - Pointer to the curstat_t structure
811 *
812 * Return:
813 * Nothing.
814 */
815 void
cdda_pthr_halt(di_dev_t * devp,curstat_t * s)816 cdda_pthr_halt(di_dev_t *devp, curstat_t *s)
817 {
818 if (cd == NULL)
819 return;
820
821 /* Stop playback, if applicable */
822 (void) cdda_pthr_stop(devp, s);
823
824 /* Clean up IPC */
825 cdda_pthr_cleanup();
826
827 DBGPRN(DBG_GEN)(errfp, "\nPTHREADS: CDDA halted.\n");
828 }
829
830
831 /*
832 * cdda_pthr_play
833 * Start cdda play.
834 *
835 * Args:
836 * devp - Read device descriptor
837 * s - Pointer to the curstat_t structure
838 * start_lba - Start logical block address
839 * end_lba - End logical block address
840 *
841 * Return:
842 * TRUE - success
843 * FALSE - failure
844 */
845 /*ARGSUSED*/
846 bool_t
cdda_pthr_play(di_dev_t * devp,curstat_t * s,sword32_t start_lba,sword32_t end_lba)847 cdda_pthr_play(di_dev_t *devp, curstat_t *s,
848 sword32_t start_lba, sword32_t end_lba)
849 {
850 int ret;
851 pthread_t tid;
852
853 if (cd == NULL && !cdda_pthr_init2(s))
854 return FALSE;
855
856 if (start_lba >= end_lba) {
857 (void) sprintf(errbuf,
858 "cdda_pthr_play: "
859 "Start LBA is greater than or equal to end LBA.");
860 CDDA_INFO(errbuf);
861 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
862 return FALSE;
863 }
864
865 /* If not stopped, stop first */
866 if (cd->i->state != CDSTAT_COMPLETED)
867 (void) cdda_pthr_stop(devp, s);
868
869 /* Set status */
870 cd->i->state = CDSTAT_PLAYING;
871
872 /* Where are we starting */
873 cd->i->start_lba = start_lba;
874 cd->i->end_lba = end_lba;
875
876 /* Not finished reading */
877 cd->i->cdda_done = 0;
878
879 /* Buffer pointers */
880 cd->cdb->occupied = 0;
881 cd->cdb->nextin = 0;
882 cd->cdb->nextout = 0;
883
884 /* Clear message buffer */
885 cd->i->msgbuf[0] = '\0';
886
887 /* Room available */
888 pthr_sem[ROOM].v = 1;
889
890 /* No data available */
891 pthr_sem[DATA].v = 0;
892
893 #ifndef __VMS /* VMS has no real fork, so this does not apply */
894 #if __FreeBSD_version >= 502100 || defined(__DragonFly__)
895 /* Register fork handler */
896 if ((ret = pthread_atfork(NULL, NULL, cdda_pthr_atfork)) != 0) {
897 (void) sprintf(errbuf,
898 "cdda_pthr_play: pthread_atfork failed (ret=%d)",
899 ret);
900 CDDA_INFO(errbuf);
901 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
902 cd->i->state = CDSTAT_COMPLETED;
903 return FALSE;
904 }
905 #endif
906 #endif
907
908 /* Ignore SIGPIPE */
909 opipe = util_signal(SIGPIPE, SIG_IGN);
910
911 /* Start CDDA reader thread */
912 if ((ret = pthread_create(&tid, NULL,
913 cdda_pthr_reader, (void *) devp)) != 0) {
914 (void) sprintf(errbuf,
915 "cdda_pthr_play: pthread_create failed "
916 "(reader ret=%d)",
917 ret);
918 CDDA_INFO(errbuf);
919 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
920 cd->i->state = CDSTAT_COMPLETED;
921 if (cd->i->writer != (thid_t) 0) {
922 cdda_pthr_kill(cd->i->writer, SIGTERM);
923 cd->i->writer = (thid_t) 0;
924 }
925
926 /* Restore saved SIGPIPE handler */
927 (void) util_signal(SIGPIPE, opipe);
928 return FALSE;
929 }
930
931 /* Start CDDA writer thread */
932 if ((ret = pthread_create(&tid, NULL,
933 cdda_pthr_writer, (void *) s)) != 0) {
934 (void) sprintf(errbuf,
935 "cdda_pthr_play: pthread_create failed "
936 "(writer ret=%d)",
937 ret);
938 CDDA_INFO(errbuf);
939 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
940 cd->i->state = CDSTAT_COMPLETED;
941 if (cd->i->reader != (thid_t) 0) {
942 cdda_pthr_kill(cd->i->reader, SIGTERM);
943 cd->i->reader = (thid_t) 0;
944 }
945
946 /* Restore saved SIGPIPE handler */
947 (void) util_signal(SIGPIPE, opipe);
948 return FALSE;
949 }
950
951 return TRUE;
952 }
953
954
955 /*
956 * cdda_pthr_pause_resume
957 * Pause CDDA playback.
958 *
959 * Args:
960 * devp - Read device descriptor
961 * s - Pointer to the curstat_t structure
962 * resume - Whether to resume playback
963 *
964 * Return:
965 * TRUE - success
966 * FALSE - failure
967 */
968 /*ARGSUSED*/
969 bool_t
cdda_pthr_pause_resume(di_dev_t * devp,curstat_t * s,bool_t resume)970 cdda_pthr_pause_resume(di_dev_t *devp, curstat_t *s, bool_t resume)
971 {
972 if (cd == NULL && !cdda_pthr_init2(s))
973 return FALSE;
974
975 if (cd->i->writer != (thid_t) 0) {
976 if (resume)
977 cd->i->state = CDSTAT_PLAYING;
978 else
979 cd->i->state = CDSTAT_PAUSED;
980
981 /* Skip heartbeat checking */
982 skip_hbchk = CDDA_HB_SKIP;
983 }
984 return TRUE;
985 }
986
987
988 /*
989 * cdda_pthr_stop
990 * Stop CDDA playback.
991 *
992 * Args:
993 * devp - Read device descriptor
994 * s - Pointer to the curstat_t structure
995 *
996 * Return:
997 * TRUE - success
998 * FALSE - failure
999 */
1000 /*ARGSUSED*/
1001 bool_t
cdda_pthr_stop(di_dev_t * devp,curstat_t * s)1002 cdda_pthr_stop(di_dev_t *devp, curstat_t *s)
1003 {
1004 void *status;
1005 int ret;
1006 pthread_t tid;
1007
1008 if (cd == NULL && !cdda_pthr_init2(s))
1009 return FALSE;
1010
1011 /* Set status */
1012 cd->i->state = CDSTAT_COMPLETED;
1013
1014 if (cd->i->writer != (thid_t) 0) {
1015 tid = (pthread_t) cd->i->writer;
1016
1017 /* Wait for writer, blocking */
1018 DBGPRN(DBG_GEN)(errfp,
1019 "\ncdda_pthr_stop: Waiting for writer thread id=%ju\n",
1020 (uintmax_t) tid);
1021
1022 if ((ret = pthread_join(tid, &status)) != 0) {
1023 DBGPRN(DBG_GEN)(errfp,
1024 "pthread_join failed (writer ret=%d)\n", ret);
1025 }
1026 else {
1027 ret = (int)(uintptr_t) status;
1028 if (ret == (int)(uintptr_t) PTHREAD_CANCELED) {
1029 DBGPRN(DBG_GEN)(errfp, "Writer canceled\n");
1030 }
1031 else {
1032 DBGPRN(DBG_GEN)(errfp,
1033 "Writer exited, status %d\n", ret);
1034 }
1035
1036 /* Display message, if any */
1037 if (ret != 0 && cd->i->msgbuf[0] != '\0')
1038 CDDA_INFO(cd->i->msgbuf);
1039 }
1040
1041 cd->i->writer = (thid_t) 0;
1042 }
1043
1044 if (cd->i->reader != (thid_t) 0) {
1045 tid = (pthread_t) cd->i->reader;
1046
1047 /* Wait for reader, blocking */
1048 DBGPRN(DBG_GEN)(errfp,
1049 "\ncdda_pthr_stop: Waiting for reader thread id=%ju\n",
1050 (uintptr_t) tid);
1051
1052 if ((ret = pthread_join(tid, &status)) != 0) {
1053 DBGPRN(DBG_GEN)(errfp,
1054 "pthread_join failed (reader ret=%d)\n", ret);
1055 }
1056 else {
1057 ret = (int)(uintptr_t) status;
1058 if (ret == (int)(uintptr_t) PTHREAD_CANCELED) {
1059 DBGPRN(DBG_GEN)(errfp, "Reader canceled\n");
1060 }
1061 else {
1062 DBGPRN(DBG_GEN)(errfp,
1063 "Reader exited, status %d\n", ret);
1064 }
1065
1066 /* Display message, if any */
1067 if (ret != 0 && cd->i->msgbuf[0] != '\0')
1068 CDDA_INFO(cd->i->msgbuf);
1069 }
1070
1071 cd->i->reader = (thid_t) 0;
1072 }
1073
1074 /* Reset states */
1075 cdda_pthr_initshm(s);
1076
1077 /* Restore saved SIGPIPE handler */
1078 (void) util_signal(SIGPIPE, opipe);
1079
1080 return TRUE;
1081 }
1082
1083
1084 /*
1085 * cdda_pthr_vol
1086 * Change volume setting.
1087 *
1088 * Args:
1089 * devp - Read device descriptor
1090 * s - Pointer to the curstat_t structure
1091 * vol - Desired volume level
1092 * query - Whether querying or setting the volume
1093 *
1094 * Return:
1095 * The volume setting, or -1 on failure.
1096 */
1097 /*ARGSUSED*/
1098 int
cdda_pthr_vol(di_dev_t * devp,curstat_t * s,int vol,bool_t query)1099 cdda_pthr_vol(di_dev_t *devp, curstat_t *s, int vol, bool_t query)
1100 {
1101 if (cd == NULL && !cdda_pthr_init2(s))
1102 return -1;
1103
1104 if (query) {
1105 s->level_left = (byte_t) cd->i->vol_left;
1106 s->level_right = (byte_t) cd->i->vol_right;
1107 return (cd->i->vol);
1108 }
1109
1110 cd->i->vol_taper = app_data.vol_taper;
1111 cd->i->vol = vol;
1112 cd->i->vol_left = (int) s->level_left;
1113 cd->i->vol_right = (int) s->level_right;
1114
1115 return (vol);
1116 }
1117
1118
1119 /*
1120 * cdda_pthr_chroute
1121 * Change channel routing setting.
1122 *
1123 * Args:
1124 * devp - Read device descriptor
1125 * s - Pointer to the curstat_t structure
1126 *
1127 * Return:
1128 * TRUE - success
1129 * FALSE - failure
1130 */
1131 /*ARGSUSED*/
1132 bool_t
cdda_pthr_chroute(di_dev_t * devp,curstat_t * s)1133 cdda_pthr_chroute(di_dev_t *devp, curstat_t *s)
1134 {
1135 if (cd != NULL) {
1136 cd->i->chroute = app_data.ch_route;
1137 return TRUE;
1138 }
1139 else
1140 return FALSE;
1141 }
1142
1143
1144 /*
1145 * cdda_pthr_att
1146 * Change CDDA level attentuator setting.
1147 *
1148 * Args:
1149 * s - Pointer to the curstat_t structure
1150 *
1151 * Return:
1152 * Nothing.
1153 */
1154 void
cdda_pthr_att(curstat_t * s)1155 cdda_pthr_att(curstat_t *s)
1156 {
1157 if (cd != NULL)
1158 cd->i->att = (int) s->cdda_att;
1159 }
1160
1161
1162 /*
1163 * cdda_pthr_outport
1164 * Change CDDA output port setting.
1165 *
1166 * Args:
1167 * None.
1168 *
1169 * Return:
1170 * Nothing.
1171 */
1172 void
cdda_pthr_outport(void)1173 cdda_pthr_outport(void)
1174 {
1175 if (cd != NULL)
1176 cd->i->outport = (int) app_data.outport;
1177 }
1178
1179
1180 /*
1181 * cdda_pthr_getstatus
1182 * Get CDDA playback status.
1183 *
1184 * Args:
1185 * devp - Read device descriptor
1186 * s - Pointer to curstat_t structure
1187 * sp - CDDA status return structure
1188 *
1189 * Return:
1190 * TRUE - success
1191 * FALSE - failure
1192 */
1193 /*ARGSUSED*/
1194 bool_t
cdda_pthr_getstatus(di_dev_t * devp,curstat_t * s,cdstat_t * sp)1195 cdda_pthr_getstatus(di_dev_t *devp, curstat_t *s, cdstat_t *sp)
1196 {
1197 int i;
1198 time_t now;
1199 bool_t reader_fail,
1200 writer_fail;
1201 static int hbint = 0,
1202 hbcnt = 0;
1203
1204 if (cd == NULL && !cdda_pthr_init2(s))
1205 return FALSE;
1206
1207 /* Current playback status */
1208 sp->status = cd->i->state;
1209 if (sp->status == CDSTAT_COMPLETED)
1210 (void) cdda_pthr_stop(devp, s);
1211
1212 /* Current playback location */
1213 sp->abs_addr.addr = cd->i->start_lba + cd->i->frm_played;
1214
1215 util_blktomsf(
1216 sp->abs_addr.addr,
1217 &sp->abs_addr.min,
1218 &sp->abs_addr.sec,
1219 &sp->abs_addr.frame,
1220 MSF_OFFSET
1221 );
1222
1223 i = cd->i->trk_idx;
1224 if (sp->abs_addr.addr >= s->trkinfo[i].addr &&
1225 sp->abs_addr.addr < s->trkinfo[i+1].addr) {
1226 sp->track = s->trkinfo[i].trkno;
1227
1228 sp->rel_addr.addr =
1229 sp->abs_addr.addr - s->trkinfo[i].addr;
1230
1231 util_blktomsf(
1232 sp->rel_addr.addr,
1233 &sp->rel_addr.min,
1234 &sp->rel_addr.sec,
1235 &sp->rel_addr.frame,
1236 0
1237 );
1238 }
1239 else for (i = 0; i < (int) s->tot_trks; i++) {
1240 if (sp->abs_addr.addr >= s->trkinfo[i].addr &&
1241 sp->abs_addr.addr < s->trkinfo[i+1].addr) {
1242 sp->track = s->trkinfo[i].trkno;
1243
1244 sp->rel_addr.addr =
1245 sp->abs_addr.addr - s->trkinfo[i].addr;
1246
1247 util_blktomsf(
1248 sp->rel_addr.addr,
1249 &sp->rel_addr.min,
1250 &sp->rel_addr.sec,
1251 &sp->rel_addr.frame,
1252 0
1253 );
1254 break;
1255 }
1256 }
1257
1258 sp->index = 1; /* Index number not supported in this mode */
1259
1260 /* Current volume and balance */
1261 sp->level = (byte_t) cd->i->vol;
1262 sp->level_left = (byte_t) cd->i->vol_left;
1263 sp->level_right = (byte_t) cd->i->vol_right;
1264
1265 sp->tot_frm = cd->i->end_lba - cd->i->start_lba + 1;
1266 sp->frm_played = cd->i->frm_played;
1267 sp->frm_per_sec = cd->i->frm_per_sec;
1268
1269 /* Initialize heartbeat checking interval */
1270 if (hbint == 0)
1271 hbcnt = hbint = (1000 / app_data.stat_interval) + 1;
1272
1273 /* Check reader and writer heartbeats */
1274 if (sp->status == CDSTAT_PLAYING && --hbcnt == 0 &&
1275 cd->i->reader != (thid_t) 0 && cd->i->writer != (thid_t) 0 &&
1276 cd->i->reader_hb != 0 && cd->i->writer_hb != 0) {
1277 hbcnt = hbint;
1278 now = time(NULL);
1279
1280 if (skip_hbchk > 0) {
1281 /* Skip heartbeat checking for a few iterations after
1282 * resuming from pause, to let the reader and writer
1283 * threads to catch up.
1284 */
1285 reader_fail = writer_fail = FALSE;
1286 skip_hbchk--;
1287 }
1288 else {
1289 reader_fail = (bool_t)
1290 ((now - cd->i->reader_hb) > cd->i->reader_hb_timeout);
1291 writer_fail = (bool_t)
1292 ((now - cd->i->writer_hb) > cd->i->writer_hb_timeout);
1293 }
1294
1295 if (reader_fail || writer_fail) {
1296 /* Reader or writer is hung or died */
1297 cdda_pthr_kill(cd->i->reader, SIGTERM);
1298 cdda_pthr_kill(cd->i->writer, SIGTERM);
1299
1300 (void) cdda_pthr_stop(devp, s);
1301
1302 (void) sprintf(errbuf,
1303 "CDDA %s thread failure!",
1304 writer_fail ? "writer" : "reader");
1305 CDDA_INFO(errbuf);
1306 DBGPRN(DBG_GEN)(errfp, "%s\n", errbuf);
1307 }
1308 }
1309
1310 return TRUE;
1311 }
1312
1313
1314 /*
1315 * cdda_pthr_debug
1316 * Debug level change notification function
1317 *
1318 * Args:
1319 * lev - New debug level
1320 *
1321 * Return:
1322 * Nothing.
1323 */
1324 void
cdda_pthr_debug(word32_t lev)1325 cdda_pthr_debug(word32_t lev)
1326 {
1327 if (cd != NULL)
1328 cd->i->debug = lev;
1329 }
1330
1331
1332
1333 /*
1334 * cdda_pthr_info
1335 * Append CDDA read and write method information to supplied string.
1336 *
1337 * Args:
1338 * str - The string to append to.
1339 *
1340 * Return:
1341 * Nothing.
1342 */
1343 void
cdda_pthr_info(char * str)1344 cdda_pthr_info(char *str)
1345 {
1346 void (*rinfo)(char *),
1347 (*winfo)(char *);
1348
1349 (void) strcat(str, "POSIX Threads\n");
1350
1351 (void) strcat(str, " Extract: ");
1352 if (app_data.cdda_rdmethod <= CDDA_RD_NONE ||
1353 app_data.cdda_rdmethod >= CDDA_RD_METHODS) {
1354 (void) strcat(str, "not configured\n");
1355 }
1356 else {
1357 rinfo = cdda_rd_calltbl[app_data.cdda_rdmethod].readinfo;
1358 if (rinfo == NULL)
1359 (void) strcat(str, "not configured\n");
1360 else
1361 (*rinfo)(str);
1362 }
1363
1364 (void) strcat(str, " Playback: ");
1365 if (app_data.cdda_wrmethod <= CDDA_WR_NONE ||
1366 app_data.cdda_wrmethod >= CDDA_WR_METHODS) {
1367 (void) strcat(str, "not configured\n");
1368 }
1369 else {
1370 winfo = cdda_wr_calltbl[app_data.cdda_wrmethod].writeinfo;
1371 if (winfo == NULL)
1372 (void) strcat(str, "not configured\n");
1373 else
1374 (*winfo)(str);
1375 }
1376 }
1377
1378
1379 /*
1380 * cdda_pthr_initipc
1381 * Retrieves shared memory and semaphores. Sets up our pointers
1382 * from cd into shared memory. Used by the reader/writer threads.
1383 *
1384 * Args:
1385 * cd - Pointer to the cd_state_t structure to be filled in
1386 *
1387 * Return:
1388 * The IPC semaphore ID, or -1 if failed.
1389 */
1390 int
cdda_pthr_initipc(cd_state_t * cdp)1391 cdda_pthr_initipc(cd_state_t *cdp)
1392 {
1393 if (pthr_shmaddr == NULL) {
1394 DBGPRN(DBG_GEN)(errfp,
1395 "cdda_pthr_initipc: No shared memory!\n");
1396 return -1;
1397 }
1398
1399 /* Now set our fields pointing into the shared memory */
1400 cdp->cds = (cd_size_t *) pthr_shmaddr;
1401
1402 /* Info */
1403 cdp->i = (cd_info_t *)(void *)
1404 ((byte_t *) pthr_shmaddr + sizeof(cd_size_t));
1405
1406 /* Buffer */
1407 cdp->cdb = (cd_buffer_t *)(void *)
1408 ((byte_t *) cd->i + sizeof(cd_info_t));
1409
1410 /* Overlap */
1411 cdp->cdb->olap = (byte_t *) ((byte_t *) cd->cdb + sizeof(cd_buffer_t));
1412
1413 /* Data */
1414 cdp->cdb->data = (byte_t *)
1415 ((byte_t *) cd->cdb->olap +
1416 (cd->cds->search_bytes << 1));
1417
1418 /* Buffer */
1419 cdp->cdb->b = (byte_t *)
1420 ((byte_t *) cd->cdb->data + cd->cds->chunk_bytes +
1421 (cd->cds->olap_bytes << 1));
1422
1423 return (1);
1424 }
1425
1426
1427 /*
1428 * cdda_pthr_waitsem
1429 * Waits for a semaphore
1430 *
1431 * Args:
1432 * semid - Unused
1433 * num - Semaphore to wait on
1434 *
1435 * Return:
1436 * Nothing.
1437 */
1438 /*ARGSUSED*/
1439 void
cdda_pthr_waitsem(int semid,int num)1440 cdda_pthr_waitsem(int semid, int num)
1441 {
1442 int ret;
1443 pthread_t tid;
1444
1445
1446 tid = pthread_self();
1447
1448 if ((ret = pthread_mutex_lock(&pthr_sem[num].mutex)) != 0) {
1449 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_waitsem: "
1450 "pthread_mutex_lock failed (sem %d ret=%d)\n",
1451 num, ret);
1452 if ((ret = pthread_cancel(tid)) != 0) {
1453 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_waitsem: "
1454 "pthread_cancel failed (ret=%d)\n", ret);
1455 }
1456 return;
1457 }
1458
1459 while (pthr_sem[num].v == 0) {
1460 ret = pthread_cond_wait(&pthr_sem[num].cond,
1461 &pthr_sem[num].mutex);
1462 if (ret != 0) {
1463 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_waitsem: "
1464 "pthread_cond_wait failed (sem %d ret=%d)\n",
1465 num, ret);
1466 if ((ret = pthread_cancel(tid)) != 0) {
1467 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_waitsem: "
1468 "pthread_cancel failed (ret=%d)\n", ret);
1469 }
1470 return;
1471 }
1472 }
1473
1474 pthr_sem[num].v = 0;
1475
1476 if ((ret = pthread_mutex_unlock(&pthr_sem[num].mutex)) != 0) {
1477 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_waitsem: "
1478 "pthread_mutex_unlock failed (sem %d ret=%d)\n",
1479 num, ret);
1480 if ((ret = pthread_cancel(tid)) != 0) {
1481 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_waitsem: "
1482 "pthread_cancel failed (ret=%d)\n", ret);
1483 }
1484 }
1485 }
1486
1487
1488 /*
1489 * cdda_pthr_postsem
1490 * Releases a semaphore
1491 *
1492 * Args:
1493 * semid - Unused
1494 * num - Semaphore to wait on
1495 *
1496 * Return:
1497 * Nothing.
1498 */
1499 /*ARGSUSED*/
1500 void
cdda_pthr_postsem(int semid,int num)1501 cdda_pthr_postsem(int semid, int num)
1502 {
1503 int ret;
1504 pthread_t tid;
1505
1506 tid = pthread_self();
1507
1508 if ((ret = pthread_mutex_lock(&pthr_sem[num].mutex)) != 0) {
1509 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_postsem: "
1510 "pthread_mutex_lock failed (sem %d ret=%d)\n",
1511 num, ret);
1512 if ((ret = pthread_cancel(tid)) != 0) {
1513 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_postsem: "
1514 "pthread_cancel failed (ret=%d)\n", ret);
1515 }
1516 return;
1517 }
1518
1519 pthr_sem[num].v = 1;
1520
1521 if ((ret = pthread_mutex_unlock(&pthr_sem[num].mutex)) != 0) {
1522 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_postsem: "
1523 "pthread_mutex_unlock failed (sem %d ret=%d)\n",
1524 num, ret);
1525 if ((ret = pthread_cancel(tid)) != 0) {
1526 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_postsem: "
1527 "pthread_cancel failed (ret=%d)\n", ret);
1528 }
1529 return;
1530 }
1531
1532 if ((ret = pthread_cond_signal(&pthr_sem[num].cond)) != 0) {
1533 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_postsem: "
1534 "pthread_mutex_unlock failed (sem %d ret=%d)\n",
1535 num, ret);
1536 if ((ret = pthread_cancel(tid)) != 0) {
1537 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_postsem: "
1538 "pthread_cancel failed (ret=%d)\n", ret);
1539 }
1540 }
1541 }
1542
1543
1544 /*
1545 * cdda_pthr_preinit
1546 * Early program startup initializations.
1547 *
1548 * Args:
1549 * None.
1550 *
1551 * Return:
1552 * Nothing.
1553 */
1554 void
cdda_pthr_preinit(void)1555 cdda_pthr_preinit(void)
1556 {
1557 #ifdef NEED_PTHREAD_INIT
1558 pthread_init();
1559 #endif
1560 }
1561
1562
1563 /*
1564 * cdda_pthr_yield
1565 * Let other threads run.
1566 *
1567 * Args:
1568 * None.
1569 *
1570 * Return:
1571 * Nothing.
1572 */
1573 void
cdda_pthr_yield(void)1574 cdda_pthr_yield(void)
1575 {
1576 #ifdef _POSIX_PRIORITY_SCHEDULING
1577 sched_yield();
1578 #endif
1579 util_delayms(100);
1580 }
1581
1582
1583 /*
1584 * cdda_pthr_kill
1585 * Terminate a thread.
1586 *
1587 * Args:
1588 * id - The thread id
1589 * sig - The signal
1590 *
1591 * Return:
1592 * Nothing.
1593 */
1594 void
cdda_pthr_kill(thid_t id,int sig)1595 cdda_pthr_kill(thid_t id, int sig)
1596 {
1597 int ret;
1598
1599 if (sig != SIGTERM) {
1600 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_kill: "
1601 "signal %d not implemented for pthreads\n", sig);
1602 return;
1603 }
1604 if ((ret = pthread_cancel((pthread_t) id)) != 0) {
1605 DBGPRN(DBG_GEN)(errfp, "cdda_pthr_kill: "
1606 "pthread_cancel failed (ret=%d)\n", ret);
1607 }
1608 }
1609
1610
1611 #endif /* CDDA_PTHREADS */
1612
1613