1 // thread.c
2 //
3 /****************************************************************************
4    liblscp - LinuxSampler Control Protocol API
5    Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved.
6 
7    This library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11 
12    This library 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 GNU
15    Lesser General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License along
18    with this program; if not, write to the Free Software Foundation, Inc.,
19    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 
21 *****************************************************************************/
22 
23 #include "lscp/thread.h"
24 
25 
26 //-------------------------------------------------------------------------
27 // Threads.
28 
29 struct _lscp_thread_t {
30 #if defined(WIN32)
31 	HANDLE              hThread;
32 	DWORD               dwThreadID;
33 #else
34 	pthread_t           pthread;
35 #endif
36 	lscp_thread_proc_t  pfnProc;
37 	void               *pvData;
38 	int                 iDetach;
39 };
40 
41 
42 #if defined(WIN32)
_lscp_thread_start(LPVOID pvThread)43 static DWORD WINAPI _lscp_thread_start ( LPVOID pvThread )
44 #else
45 static void *_lscp_thread_start ( void *pvThread )
46 #endif
47 {
48 	lscp_thread_t *pThread = (lscp_thread_t *) pvThread;
49 	if (pThread) {
50 	//  fprintf(stderr, "_lscp_thread_start: pThread=%p started.\n", pThread);
51 		pThread->pfnProc(pThread->pvData);
52 	//  fprintf(stderr, "_lscp_thread_start: pThread=%p terminated.\n", pThread);
53 		if (pThread->iDetach)
54 			free(pThread);
55 	}
56 #if defined(WIN32)
57 	return 0;
58 #else
59 	return NULL;
60 #endif
61 }
62 
lscp_thread_create(lscp_thread_proc_t pfnProc,void * pvData,int iDetach)63 lscp_thread_t *lscp_thread_create ( lscp_thread_proc_t pfnProc, void *pvData, int iDetach )
64 {
65 	lscp_thread_t *pThread;
66 #if !defined(WIN32)
67 	pthread_attr_t attr;
68 #endif
69 
70 	if (pfnProc == NULL) {
71 		fprintf(stderr, "lcsp_thread_create: Invalid thread function.\n");
72 		return NULL;
73 	}
74 
75 	pThread = (lscp_thread_t *) malloc(sizeof(lscp_thread_t));
76 	if (pThread == NULL) {
77 		fprintf(stderr, "lcsp_thread_create: Out of memory.\n");
78 		return NULL;
79 	}
80 	memset(pThread, 0, sizeof(lscp_thread_t));
81 
82 	pThread->pvData  = pvData;
83 	pThread->pfnProc = pfnProc;
84 	pThread->iDetach = iDetach;
85 
86 //  fprintf(stderr, "lscp_thread_create: pThread=%p.\n", pThread);
87 
88 #if defined(WIN32)
89 	pThread->hThread = CreateThread(NULL, 0, _lscp_thread_start, (LPVOID) pThread, 0, &(pThread->dwThreadID));
90 	if (pThread->hThread == NULL) {
91 		fprintf(stderr, "lcsp_thread_create: Failed to create thread.\n");
92 		free(pThread);
93 		return NULL;
94 	}
95 #else
96 	pthread_attr_init(&attr);
97 	if (iDetach)
98 		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
99 	if (pthread_create(&pThread->pthread, &attr, _lscp_thread_start, pThread)) {
100 		fprintf(stderr, "lcsp_thread_create: Failed to create thread.\n");
101 		free(pThread);
102 		return NULL;
103 	}
104 #endif
105 
106 return pThread;
107 }
108 
109 
lscp_thread_join(lscp_thread_t * pThread)110 lscp_status_t lscp_thread_join( lscp_thread_t *pThread )
111 {
112 	lscp_status_t ret = LSCP_FAILED;
113 
114 	if (pThread == NULL)
115 		return ret;
116 
117 //  fprintf(stderr, "lscp_thread_join: pThread=%p.\n", pThread);
118 
119 #if defined(WIN32)
120 	if (pThread->hThread && WaitForSingleObject(pThread->hThread, INFINITE) == WAIT_OBJECT_0) {
121 		pThread->hThread = NULL;
122 		ret = LSCP_OK;
123 	}
124 #else
125 	if (pThread->pthread && pthread_join(pThread->pthread, NULL) == 0) {
126 		pThread->pthread = 0;
127 		ret = LSCP_OK;
128 	}
129 #endif
130 
131 	return ret;
132 }
133 
134 
lscp_thread_cancel(lscp_thread_t * pThread)135 lscp_status_t lscp_thread_cancel ( lscp_thread_t *pThread )
136 {
137 	lscp_status_t ret = LSCP_FAILED;
138 
139 	if (pThread == NULL)
140 		return ret;
141 
142 //  fprintf(stderr, "lscp_thread_cancel: pThread=%p.\n", pThread);
143 
144 #if defined(WIN32)
145 	if (pThread->hThread) { // Should we TerminateThread(pThread->hThread, 0) ?
146 	/*  pThread->hThread = NULL; */
147 		ret = LSCP_OK;
148 	}
149 #else
150 	if (pThread->pthread && pthread_cancel(pThread->pthread) == 0) {
151 		pThread->pthread = 0;
152 		ret = LSCP_OK;
153 	}
154 #endif
155 
156 	return ret;
157 }
158 
159 
lscp_thread_destroy(lscp_thread_t * pThread)160 lscp_status_t lscp_thread_destroy ( lscp_thread_t *pThread )
161 {
162 	lscp_status_t ret = lscp_thread_cancel(pThread);
163 
164 	if (ret == LSCP_OK)
165 		ret = lscp_thread_join(pThread);
166 
167 //  fprintf(stderr, "lscp_thread_destroy: pThread=%p.\n", pThread);
168 
169 	if (ret == LSCP_OK)
170 		free(pThread);
171 
172 	return ret;
173 }
174 
175 
176 // end of thread.c
177