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