1 /* Support for thread stuff.
2  *
3  * JC & KM 9/5/94
4  * Modified:
5  * 28/11/94 JC
6  *	- return(0) missing from tidy_thread_info()
7  * 4/8/99 RP JC
8  *	- reorganised for POSIX
9  * 28/3/11
10  * 	- moved to vips_ namespace
11  */
12 
13 /*
14 
15     This file is part of VIPS.
16 
17     VIPS is free software; you can redistribute it and/or modify
18     it under the terms of the GNU Lesser General Public License as published by
19     the Free Software Foundation; either version 2 of the License, or
20     (at your option) any later version.
21 
22     This program is distributed in the hope that it will be useful,
23     but WITHOUT ANY WARRANTY; without even the implied warranty of
24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25     GNU Lesser General Public License for more details.
26 
27     You should have received a copy of the GNU Lesser General Public License
28     along with this program; if not, write to the Free Software
29     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30     02110-1301  USA
31 
32  */
33 
34 /*
35 
36     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
37 
38  */
39 
40 /*
41 #define DEBUG_IO
42  */
43 
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif /*HAVE_CONFIG_H*/
47 #include <vips/intl.h>
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <signal.h>
52 #include <errno.h>
53 
54 #include <vips/vips.h>
55 #include <vips/thread.h>
56 
57 void
vips_semaphore_init(VipsSemaphore * s,int v,char * name)58 vips_semaphore_init( VipsSemaphore *s, int v, char *name )
59 {
60 	s->v = v;
61 	s->name = name;
62 	s->mutex = vips_g_mutex_new();
63 	s->cond = vips_g_cond_new();
64 }
65 
66 void
vips_semaphore_destroy(VipsSemaphore * s)67 vips_semaphore_destroy( VipsSemaphore *s )
68 {
69 	VIPS_FREEF( vips_g_mutex_free, s->mutex );
70 	VIPS_FREEF( vips_g_cond_free, s->cond );
71 }
72 
73 /* Add n to the semaphore and signal any threads that are blocked waiting
74  * a change.
75  */
76 int
vips_semaphore_upn(VipsSemaphore * s,int n)77 vips_semaphore_upn( VipsSemaphore *s, int n )
78 {
79 	int value_after_op;
80 
81 	g_mutex_lock( s->mutex );
82 	s->v += n;
83 	value_after_op = s->v;
84 
85 	/* If we are only incrementing by one, we only need to wake a single
86 	 * thread. If we are incrementing by a lot, we must wake all threads.
87 	 */
88 	if( n == 1 )
89 		g_cond_signal( s->cond );
90 	else
91 		g_cond_broadcast( s->cond );
92 	g_mutex_unlock( s->mutex );
93 
94 #ifdef DEBUG_IO
95 	printf( "vips_semaphore_upn(\"%s\",%d) = %d\n",
96 		s->name, n, value_after_op );
97 	if( value_after_op > 1 )
98 		vips_error( "vips_semaphore_upn", "up over 1!" );
99 #endif /*DEBUG_IO*/
100 
101 	return( value_after_op );
102 }
103 
104 /* Increment the semaphore.
105  */
106 int
vips_semaphore_up(VipsSemaphore * s)107 vips_semaphore_up( VipsSemaphore *s )
108 {
109 	return( vips_semaphore_upn( s, 1 ) );
110 }
111 
112 /* Wait for sem>n, then subtract n.
113  */
114 int
vips_semaphore_downn(VipsSemaphore * s,int n)115 vips_semaphore_downn( VipsSemaphore *s, int n )
116 {
117 	int value_after_op;
118 
119 	VIPS_GATE_START( "vips_semaphore_downn: wait" );
120 
121 	g_mutex_lock( s->mutex );
122 
123 	while( s->v < n )
124 		g_cond_wait( s->cond, s->mutex );
125 	s->v -= n;
126 	value_after_op = s->v;
127 
128 	g_mutex_unlock( s->mutex );
129 
130 #ifdef DEBUG_IO
131 	printf( "vips_semaphore_downn(\"%s\",%d): %d\n",
132 		s->name, n, value_after_op );
133 #endif /*DEBUG_IO*/
134 
135 	VIPS_GATE_STOP( "vips_semaphore_downn: wait" );
136 
137 	return( value_after_op );
138 }
139 
140 /* Wait for sem > 0, then decrement.
141  */
142 int
vips_semaphore_down(VipsSemaphore * s)143 vips_semaphore_down( VipsSemaphore *s )
144 {
145 	return( vips_semaphore_downn( s, 1 ) );
146 }
147