da261b83dbf70126670b6e41907c310fd04f9575
[asterisk/asterisk.git] / include / asterisk / lock.h
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*
20  * General Asterisk channel definitions.
21  */
22
23 #ifndef _ASTERISK_LOCK_H
24 #define _ASTERISK_LOCK_H
25
26 #include <pthread.h>
27 #include <netdb.h>
28 #include <time.h>
29 #include <sys/param.h>
30
31 #include "asterisk/logger.h"
32
33 #define AST_PTHREADT_NULL (pthread_t) -1
34 #define AST_PTHREADT_STOP (pthread_t) -2
35
36 #ifdef __APPLE__
37 /* Provide the Linux initializers for MacOS X */
38 #define PTHREAD_MUTEX_RECURSIVE_NP                                      PTHREAD_MUTEX_RECURSIVE
39 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP           { 0x4d555458, \
40                                                                                                            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
41                                                                                                                  0x20 } }
42 #endif
43
44 #ifdef BSD
45 #ifdef __GNUC__
46 #define AST_MUTEX_INIT_W_CONSTRUCTORS
47 #else
48 #define AST_MUTEX_INIT_ON_FIRST_USE
49 #endif
50 #endif /* BSD */
51
52 /* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes
53    and will not run without them. */
54 #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
55 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
56 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
57 #else
58 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_MUTEX_INITIALIZER
59 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE
60 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
61
62 #ifdef SOLARIS
63 #define AST_MUTEX_INIT_W_CONSTRUCTORS
64 #endif
65
66 #ifdef DEBUG_THREADS
67
68 #define __ast_mutex_logger(...) { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); }
69
70 #ifdef THREAD_CRASH
71 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
72 #endif
73
74 #include <errno.h>
75 #include <string.h>
76 #include <stdio.h>
77 #include <unistd.h>
78
79 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, NULL, 0, 0, NULL, 0 }
80
81 struct ast_mutex_info {
82         pthread_mutex_t mutex;
83         const char *file;
84         int lineno;
85         int reentrancy;
86         const char *func;
87         pthread_t thread;
88 };
89
90 typedef struct ast_mutex_info ast_mutex_t;
91
92 static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
93                                                 const char *mutex_name, ast_mutex_t *t,
94                                                 pthread_mutexattr_t *attr) 
95 {
96 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
97         int canlog = strcmp(filename, "logger.c");
98
99         if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
100                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
101                                    filename, lineno, func, mutex_name);
102                 __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
103                                    t->file, t->lineno, t->func, mutex_name);
104 #ifdef THREAD_CRASH
105                 DO_THREAD_CRASH;
106 #endif
107                 return 0;
108         }
109 #endif
110
111         t->file = filename;
112         t->lineno = lineno;
113         t->func = func;
114         t->thread  = 0;
115         t->reentrancy = 0;
116
117         return pthread_mutex_init(&t->mutex, attr);
118 }
119
120 static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
121                                            const char *mutex_name, ast_mutex_t *t)
122 {
123         static pthread_mutexattr_t  attr;
124
125         pthread_mutexattr_init(&attr);
126         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
127
128         return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
129 }
130
131 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
132                                                 const char *mutex_name, ast_mutex_t *t)
133 {
134         int res;
135         int canlog = strcmp(filename, "logger.c");
136
137 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
138         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
139                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
140                                    filename, lineno, func, mutex_name);
141         }
142 #endif
143
144         res = pthread_mutex_trylock(&t->mutex);
145         switch (res) {
146         case 0:
147                 pthread_mutex_unlock(&t->mutex);
148                 break;
149         case EINVAL:
150                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
151                                   filename, lineno, func, mutex_name);
152                 break;
153         case EBUSY:
154                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
155                                    filename, lineno, func, mutex_name);
156                 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
157                                    t->file, t->lineno, t->func, mutex_name);
158                 break;
159         }
160
161         if ((res = pthread_mutex_destroy(&t->mutex)))
162                 __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
163                                    filename, lineno, func, strerror(res));
164 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
165         else
166                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
167 #endif
168         t->file = filename;
169         t->lineno = lineno;
170         t->func = func;
171
172         return res;
173 }
174
175 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
176 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
177  constrictors/destructors to create/destroy mutexes.  */
178 #define __AST_MUTEX_DEFINE(scope,mutex) \
179         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
180 static void  __attribute__ ((constructor)) init_##mutex(void) \
181 { \
182         ast_mutex_init(&mutex); \
183 } \
184 static void  __attribute__ ((destructor)) fini_##mutex(void) \
185 { \
186         ast_mutex_destroy(&mutex); \
187 }
188 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
189 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
190  first use.  The performance impact on FreeBSD should be small since
191  the pthreads library does this itself to initialize errror checking
192  (defaulty type) mutexes.  If nither is defined, the pthreads librariy
193  does the initialization itself on first use. */ 
194 #define __AST_MUTEX_DEFINE(scope,mutex) \
195         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
196 #else /* AST_MUTEX_INIT_W_CONSTRUCTORS */
197 /* By default, use static initialization of mutexes.*/ 
198 #define __AST_MUTEX_DEFINE(scope,mutex) \
199         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
200 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
201
202 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
203                                            const char* mutex_name, ast_mutex_t *t)
204 {
205         int res;
206         int canlog = strcmp(filename, "logger.c");
207
208 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
209         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
210 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
211                 ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
212                                  filename, lineno, func, mutex_name);
213 #endif
214                 ast_mutex_init(t);
215         }
216 #endif /* defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
217
218 #ifdef DETECT_DEADLOCKS
219         {
220                 time_t seconds = time(NULL);
221                 time_t current;
222                 do {
223                         res = pthread_mutex_trylock(&t->mutex);
224                         if (res == EBUSY) {
225                                 current = time(NULL);
226                                 if ((current - seconds) && (!((current - seconds) % 5))) {
227                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
228                                                            filename, lineno, func, (int)(current - seconds), mutex_name);
229                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
230                                                            t->file, t->lineno, t->func, mutex_name);
231                                 }
232                                 usleep(200);
233                         }
234                 } while (res == EBUSY);
235         }
236 #else
237         res = pthread_mutex_lock(&t->mutex);
238 #endif /* DETECT_DEADLOCKS */
239
240         if (!res) {
241                 t->reentrancy++;
242                 t->file = filename;
243                 t->lineno = lineno;
244                 t->func = func;
245                 t->thread = pthread_self();
246         } else {
247                 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
248                                    filename, lineno, func, strerror(errno));
249 #ifdef THREAD_CRASH
250                 DO_THREAD_CRASH;
251 #endif
252         }
253
254         return res;
255 }
256
257 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
258                                               const char* mutex_name, ast_mutex_t *t)
259 {
260         int res;
261
262 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
263         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
264 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
265                 int canlog = strcmp(filename, "logger.c");
266
267                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
268                                    filename, lineno, func, mutex_name);
269 #endif
270                 ast_mutex_init(t);
271         }
272 #endif /* defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
273
274         if (!(res = pthread_mutex_trylock(&t->mutex))) {
275                 t->reentrancy++;
276                 t->file = filename;
277                 t->lineno = lineno;
278                 t->func = func;
279                 t->thread = pthread_self();
280         }
281
282         return res;
283 }
284
285 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
286                                              const char *mutex_name, ast_mutex_t *t)
287 {
288         int res;
289         int canlog = strcmp(filename, "logger.c");
290
291 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
292         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
293                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
294                                    filename, lineno, func, mutex_name);
295         }
296 #endif
297
298         if (t->thread != pthread_self()) {
299                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
300                                    filename, lineno, func, mutex_name);
301                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
302                                    t->file, t->lineno, t->func, mutex_name);
303 #ifdef THREAD_CRASH
304                 DO_THREAD_CRASH;
305 #endif
306         }
307
308         if (--t->reentrancy < 0) {
309                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
310                                    filename, lineno, func, mutex_name);
311                 t->reentrancy = 0;
312         }
313
314         if (!t->reentrancy) {
315                 t->file = NULL;
316                 t->lineno = 0;
317                 t->func = NULL;
318                 t->thread = 0;
319         }
320
321         if ((res = pthread_mutex_unlock(&t->mutex))) {
322                 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
323                                    filename, lineno, func, strerror(res));
324 #ifdef THREAD_CRASH
325                 DO_THREAD_CRASH;
326 #endif
327         }
328
329         return res;
330 }
331
332 static inline int __ast_pthread_cond_wait(const char *filename, int lineno, const char *func,
333                                           pthread_cond_t *cond, const char *mutex_name, ast_mutex_t *t)
334 {
335         int res;
336         int canlog = strcmp(filename, "logger.c");
337
338 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
339         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
340                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
341                                    filename, lineno, func, mutex_name);
342         }
343 #endif
344
345         if (t->thread != pthread_self()) {
346                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
347                                    filename, lineno, func, mutex_name);
348                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
349                                    t->file, t->lineno, t->func, mutex_name);
350 #ifdef THREAD_CRASH
351                 DO_THREAD_CRASH;
352 #endif
353         }
354
355         if (--t->reentrancy < 0) {
356                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
357                                    filename, lineno, func, mutex_name);
358                 t->reentrancy = 0;
359         }
360
361         if (!t->reentrancy) {
362                 t->file = NULL;
363                 t->lineno = 0;
364                 t->func = NULL;
365                 t->thread = 0;
366         }
367
368         if ((res = pthread_cond_wait(cond, &t->mutex))) {
369                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
370                                    filename, lineno, func, strerror(res));
371 #ifdef THREAD_CRASH
372                 DO_THREAD_CRASH;
373 #endif
374         } else {
375                 t->reentrancy++;
376                 t->file = filename;
377                 t->lineno = lineno;
378                 t->func = func;
379                 t->thread = pthread_self();
380         }
381
382         return res;
383 }
384
385 static inline int __ast_pthread_cond_timedwait(const char *filename, int lineno, const char *func,
386                                                pthread_cond_t *cond, const struct timespec *abstime,
387                                                const char *mutex_name, ast_mutex_t *t)
388 {
389         int res;
390         int canlog = strcmp(filename, "logger.c");
391
392 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
393         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
394                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
395                                    filename, lineno, func, mutex_name);
396         }
397 #endif
398
399         if (t->thread != pthread_self()) {
400                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
401                                    filename, lineno, func, mutex_name);
402                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
403                                    t->file, t->lineno, t->func, mutex_name);
404 #ifdef THREAD_CRASH
405                 DO_THREAD_CRASH;
406 #endif
407         }
408
409         if (--t->reentrancy < 0) {
410                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
411                                    filename, lineno, func, mutex_name);
412                 t->reentrancy = 0;
413         }
414
415         if (!t->reentrancy) {
416                 t->file = NULL;
417                 t->lineno = 0;
418                 t->func = NULL;
419                 t->thread = 0;
420         }
421
422         if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime))) {
423                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
424                                    filename, lineno, func, strerror(res));
425 #ifdef THREAD_CRASH
426                 DO_THREAD_CRASH;
427 #endif
428         } else {
429                 t->reentrancy++;
430                 t->file = filename;
431                 t->lineno = lineno;
432                 t->func = func;
433                 t->thread = pthread_self();
434         }
435
436         return res;
437 }
438
439 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
440 #define ast_pthread_mutex_init(pmutex,attr) __ast_pthread_mutex_init_attr(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex, attr)
441 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
442 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
443 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
444 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
445 #define ast_pthread_cond_wait(cond, a) __ast_pthread_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, #a, a)
446 #define ast_pthread_cond_timedwait(cond, a, t) __ast_pthread_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, t, #a, a)
447
448 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
449 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
450 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
451 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
452 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
453 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
454 #define pthread_cond_wait use_ast_pthread_cond_wait_instead_of_pthread_cond_wait
455 #define pthread_cond_timedwait use_ast_pthread_cond_wait_instead_of_pthread_cond_timedwait
456
457 #else /* !DEBUG_THREADS */
458
459
460 #define AST_MUTEX_INIT_VALUE    PTHREAD_MUTEX_INIT_VALUE
461
462
463 typedef pthread_mutex_t ast_mutex_t;
464
465 static inline int ast_mutex_init(ast_mutex_t *pmutex)
466 {
467         pthread_mutexattr_t attr;
468         pthread_mutexattr_init(&attr);
469         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
470         return pthread_mutex_init(pmutex, &attr);
471 }
472 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
473 #define ast_mutex_unlock(pmutex) pthread_mutex_unlock(pmutex)
474 #define ast_mutex_destroy(pmutex) pthread_mutex_destroy(pmutex)
475
476 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
477 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
478  constrictors/destructors to create/destroy mutexes.  */ 
479 #define __AST_MUTEX_DEFINE(scope,mutex) \
480         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
481 static void  __attribute__ ((constructor)) init_##mutex(void) \
482 { \
483         ast_mutex_init(&mutex); \
484 } \
485 static void  __attribute__ ((destructor)) fini_##mutex(void) \
486 { \
487         ast_mutex_destroy(&mutex); \
488 }
489
490 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
491 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
492
493 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
494 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
495  first use.  The performance impact on FreeBSD should be small since
496  the pthreads library does this itself to initialize errror checking
497  (defaulty type) mutexes.*/ 
498 #define __AST_MUTEX_DEFINE(scope,mutex) \
499         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
500
501 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
502 {
503         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
504                 ast_mutex_init(pmutex);
505         return pthread_mutex_lock(pmutex);
506 }
507 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
508 {
509         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
510                 ast_mutex_init(pmutex);
511         return pthread_mutex_trylock(pmutex);
512 }
513 #else
514 /* By default, use static initialization of mutexes.*/ 
515 #define __AST_MUTEX_DEFINE(scope,mutex) \
516         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
517 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
518 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
519 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
520
521 #define ast_pthread_cond_wait pthread_cond_wait
522 #define ast_pthread_cond_timedwait pthread_cond_timedwait
523
524 #endif /* !DEBUG_THREADS */
525
526 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
527 #define AST_MUTEX_DEFINE_EXPORTED(mutex) __AST_MUTEX_DEFINE(/**/,mutex)
528
529 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
530
531 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
532 #ifndef __linux__
533 #define pthread_create __use_ast_pthread_create_instead__
534 #endif
535
536 #endif /* _ASTERISK_LOCK_H */