~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/include/k5-thread.h

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2009-05-07 16:16:34 UTC
  • mfrom: (13.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090507161634-xqyk0s9na0le4flj
Tags: 1.7dfsg~beta1-4
When  decrypting the TGS response fails with the subkey, try with the
session key to work around Heimdal bug, Closes: #527353 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * include/k5-thread.h
3
3
 *
4
 
 * Copyright 2004,2005,2006 by the Massachusetts Institute of Technology.
 
4
 * Copyright 2004,2005,2006,2007,2008 by the Massachusetts Institute of Technology.
5
5
 * All Rights Reserved.
6
6
 *
7
7
 * Export of this software from the United States of America may
48
48
   //            finish does nothing
49
49
   //   Windows: partial initializer is an invalid handle,
50
50
   //            finish does the real initialization work
51
 
   //   debug:   partial initializer sets one magic value,
52
 
   //            finish verifies and sets a new magic value for
53
 
   //              lock/unlock to check
54
51
   k5_mutex_t foo_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
55
52
   int k5_mutex_finish_init(k5_mutex_t *);
56
53
   // for dynamic allocation
71
68
 
72
69
   A second function or macro called at various possible "first" entry
73
70
   points which either calls pthread_once on the first function
74
 
   (POSIX), or checks some flag set by the first function (Windows,
75
 
   debug support), and possibly returns an error.  (In the
76
 
   non-threaded case, a simple flag can be used to avoid multiple
77
 
   invocations, and the mutexes don't need run-time initialization
78
 
   anyways.)
 
71
   (POSIX), or checks some flag set by the first function (Windows),
 
72
   and possibly returns an error.  (In the non-threaded case, a simple
 
73
   flag can be used to avoid multiple invocations, and the mutexes
 
74
   don't need run-time initialization anyways.)
79
75
 
80
76
   A third function for library termination calls mutex_destroy on
81
77
   each mutex for the library.  This function would be called
130
126
   The TSD destructor table is global state, protected by a mutex if
131
127
   threads are enabled.
132
128
 
133
 
   Debug support: Not much.  Might check if k5_key_register has been
134
 
   called and abort if not.
135
 
 
136
129
 
137
130
   Any actual external symbols will use the krb5int_ prefix.  The k5_
138
131
   names will be simple macros or inline functions to rename the
143
136
 
144
137
   More to be added, perhaps.  */
145
138
 
146
 
#define DEBUG_THREADS
147
 
#define DEBUG_THREADS_LOC
148
 
#undef DEBUG_THREADS_SLOW /* debugging stuff that'll slow things down? */
149
 
#undef DEBUG_THREADS_STATS
150
 
 
151
139
#include <assert.h>
152
140
 
153
 
/* For tracking locations, of (e.g.) last lock or unlock of mutex.  */
154
 
#ifdef DEBUG_THREADS_LOC
155
 
typedef struct {
156
 
    const char *filename;
157
 
    int lineno;
158
 
} k5_debug_loc;
159
 
#define K5_DEBUG_LOC_INIT       { __FILE__, __LINE__ }
160
 
#if __GNUC__ >= 2
161
 
#define K5_DEBUG_LOC            (__extension__ (k5_debug_loc)K5_DEBUG_LOC_INIT)
162
 
#else
163
 
static inline k5_debug_loc k5_debug_make_loc(const char *file, int line)
164
 
{
165
 
    k5_debug_loc l;
166
 
    l.filename = file;
167
 
    l.lineno = line;
168
 
    return l;
169
 
}
170
 
#define K5_DEBUG_LOC            (k5_debug_make_loc(__FILE__,__LINE__))
171
 
#endif
172
 
#else /* ! DEBUG_THREADS_LOC */
173
 
typedef char k5_debug_loc;
174
 
#define K5_DEBUG_LOC_INIT       0
175
 
#define K5_DEBUG_LOC            0
176
 
#endif
177
 
 
178
 
#define k5_debug_update_loc(L)  ((L) = K5_DEBUG_LOC)
179
 
 
180
 
 
181
 
 
182
 
/* Statistics gathering:
183
 
 
184
 
   Currently incomplete, don't try enabling it.
185
 
 
186
 
   Eventually: Report number of times locked, total and standard
187
 
   deviation of the time the lock was held, total and std dev time
188
 
   spent waiting for the lock.  "Report" will probably mean "write a
189
 
   line to a file if a magic environment variable is set."  */
190
 
 
191
 
#ifdef DEBUG_THREADS_STATS
192
 
 
193
 
#if HAVE_TIME_H && (!defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME))
194
 
# include <time.h>
195
 
#endif
196
 
#if HAVE_SYS_TIME_H
197
 
# include <sys/time.h>
198
 
#endif
199
 
#ifdef HAVE_STDINT_H
200
 
# include <stdint.h>
201
 
#endif
202
 
/* for memset */
203
 
#include <string.h>
204
 
/* for uint64_t */
205
 
#include <inttypes.h>
206
 
typedef uint64_t k5_debug_timediff_t; /* or long double */
207
 
typedef struct timeval k5_debug_time_t;
208
 
static inline k5_debug_timediff_t
209
 
timediff(k5_debug_time_t t2, k5_debug_time_t t1)
210
 
{
211
 
    return (t2.tv_sec - t1.tv_sec) * 1000000 + (t2.tv_usec - t1.tv_usec);
212
 
}
213
 
static inline k5_debug_time_t get_current_time(void)
214
 
{
215
 
    struct timeval tv;
216
 
    if (gettimeofday(&tv,0) < 0) { tv.tv_sec = tv.tv_usec = 0; }
217
 
    return tv;
218
 
}
219
 
struct k5_timediff_stats {
220
 
    k5_debug_timediff_t valmin, valmax, valsum, valsqsum;
221
 
};
222
 
typedef struct {
223
 
    int count;
224
 
    k5_debug_time_t time_acquired, time_created;
225
 
    struct k5_timediff_stats lockwait, lockheld;
226
 
} k5_debug_mutex_stats;
227
 
#define k5_mutex_init_stats(S)                                  \
228
 
        (memset((S), 0, sizeof(k5_debug_mutex_stats)),  \
229
 
         (S)->time_created = get_current_time(),                \
230
 
         0)
231
 
#define k5_mutex_finish_init_stats(S)   (0)
232
 
#define K5_MUTEX_STATS_INIT     { 0, {0}, {0}, {0}, {0} }
233
 
typedef k5_debug_time_t k5_mutex_stats_tmp;
234
 
#define k5_mutex_stats_start()  get_current_time()
235
 
void KRB5_CALLCONV krb5int_mutex_lock_update_stats(k5_debug_mutex_stats *m,
236
 
                                                   k5_mutex_stats_tmp start);
237
 
void KRB5_CALLCONV krb5int_mutex_unlock_update_stats(k5_debug_mutex_stats *m);
238
 
#define k5_mutex_lock_update_stats      krb5int_mutex_lock_update_stats
239
 
#define k5_mutex_unlock_update_stats    krb5int_mutex_unlock_update_stats
240
 
void KRB5_CALLCONV krb5int_mutex_report_stats(/* k5_mutex_t *m */);
241
 
 
242
 
#else
243
 
 
244
 
typedef char k5_debug_mutex_stats;
245
 
#define k5_mutex_init_stats(S)          (*(S) = 's', 0)
246
 
#define k5_mutex_finish_init_stats(S)   (0)
247
 
#define K5_MUTEX_STATS_INIT             's'
248
 
typedef int k5_mutex_stats_tmp;
249
 
#define k5_mutex_stats_start()          (0)
250
 
#ifdef __GNUC__
251
 
static inline void
252
 
k5_mutex_lock_update_stats(k5_debug_mutex_stats *m, k5_mutex_stats_tmp t)
253
 
{
254
 
}
255
 
#else
256
 
# define k5_mutex_lock_update_stats(M,S)        (S)
257
 
#endif
258
 
#define k5_mutex_unlock_update_stats(M) (*(M) = 's')
259
 
 
260
 
/* If statistics tracking isn't enabled, these functions don't actually
261
 
   do anything.  Declare anyways so we can do type checking etc.  */
262
 
void KRB5_CALLCONV krb5int_mutex_lock_update_stats(k5_debug_mutex_stats *m,
263
 
                                                   k5_mutex_stats_tmp start);
264
 
void KRB5_CALLCONV krb5int_mutex_unlock_update_stats(k5_debug_mutex_stats *m);
265
 
void KRB5_CALLCONV krb5int_mutex_report_stats(/* k5_mutex_t *m */);
266
 
 
267
 
#define krb5int_mutex_report_stats(M)   ((M)->stats = 'd')
268
 
 
269
 
#endif
270
 
 
271
 
 
 
141
 
 
142
/* The mutex structure we use, k5_mutex_t, is defined to some
 
143
   OS-specific bits.  The use of multiple layers of typedefs are an
 
144
   artifact resulting from debugging code we once used, implemented as
 
145
   wrappers around the OS mutex scheme.
 
146
 
 
147
   The OS specific bits, in k5_os_mutex, break down into three primary
 
148
   implementations, POSIX threads, Windows threads, and no thread
 
149
   support.  However, the POSIX thread version is further subdivided:
 
150
   In one case, we can determine at run time whether the thread
 
151
   library is linked into the application, and use it only if it is
 
152
   present; in the other case, we cannot, and the thread library must
 
153
   be linked in always, but can be used unconditionally.  In the
 
154
   former case, the k5_os_mutex structure needs to hold both the POSIX
 
155
   and the non-threaded versions.
 
156
 
 
157
   The various k5_os_mutex_* operations are the OS-specific versions,
 
158
   applied to the OS-specific data, and k5_mutex_* uses k5_os_mutex_*
 
159
   to do the OS-specific parts of the work.  */
272
160
 
273
161
/* Define the OS mutex bit.  */
274
162
 
275
 
/* First, if we're not actually doing multiple threads, do we
276
 
   want the debug support or not?  */
277
 
 
278
 
#ifdef DEBUG_THREADS
279
 
 
280
 
enum k5_mutex_init_states {
281
 
    K5_MUTEX_DEBUG_PARTLY_INITIALIZED = 0x12,
282
 
    K5_MUTEX_DEBUG_INITIALIZED,
283
 
    K5_MUTEX_DEBUG_DESTROYED
284
 
};
285
 
enum k5_mutex_flag_states {
286
 
    K5_MUTEX_DEBUG_UNLOCKED = 0x23,
287
 
    K5_MUTEX_DEBUG_LOCKED
288
 
};
289
 
 
290
 
typedef struct {
291
 
    enum k5_mutex_init_states initialized;
292
 
    enum k5_mutex_flag_states locked;
293
 
} k5_os_nothread_mutex;
294
 
 
295
 
# define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER \
296
 
        { K5_MUTEX_DEBUG_PARTLY_INITIALIZED, K5_MUTEX_DEBUG_UNLOCKED }
297
 
 
298
 
# define k5_os_nothread_mutex_finish_init(M)                            \
299
 
        (assert((M)->initialized != K5_MUTEX_DEBUG_INITIALIZED),        \
300
 
         assert((M)->initialized == K5_MUTEX_DEBUG_PARTLY_INITIALIZED), \
301
 
         assert((M)->locked == K5_MUTEX_DEBUG_UNLOCKED),                \
302
 
         (M)->initialized = K5_MUTEX_DEBUG_INITIALIZED, 0)
303
 
# define k5_os_nothread_mutex_init(M)                   \
304
 
        ((M)->initialized = K5_MUTEX_DEBUG_INITIALIZED, \
305
 
         (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, 0)
306
 
# define k5_os_nothread_mutex_destroy(M)                                \
307
 
        (assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),        \
308
 
         (M)->initialized = K5_MUTEX_DEBUG_DESTROYED, 0)
309
 
 
310
 
# define k5_os_nothread_mutex_lock(M)                   \
311
 
        (k5_os_nothread_mutex_assert_unlocked(M),       \
312
 
         (M)->locked = K5_MUTEX_DEBUG_LOCKED, 0)
313
 
# define k5_os_nothread_mutex_unlock(M)                 \
314
 
        (k5_os_nothread_mutex_assert_locked(M),         \
315
 
         (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, 0)
316
 
 
317
 
# define k5_os_nothread_mutex_assert_locked(M)                          \
318
 
        (assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),        \
319
 
         assert((M)->locked != K5_MUTEX_DEBUG_UNLOCKED),                \
320
 
         assert((M)->locked == K5_MUTEX_DEBUG_LOCKED))
321
 
# define k5_os_nothread_mutex_assert_unlocked(M)                        \
322
 
        (assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),        \
323
 
         assert((M)->locked != K5_MUTEX_DEBUG_LOCKED),                  \
324
 
         assert((M)->locked == K5_MUTEX_DEBUG_UNLOCKED))
325
 
 
326
 
#else /* threads disabled and not debugging */
327
 
 
328
163
typedef char k5_os_nothread_mutex;
329
164
# define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER       0
330
165
/* Empty inline functions avoid the "statement with no effect"
345
180
static inline int k5_os_nothread_mutex_unlock(k5_os_nothread_mutex *m) {
346
181
    return 0;
347
182
}
348
 
# define k5_os_nothread_mutex_assert_locked(M)          ((void)0)
349
 
# define k5_os_nothread_mutex_assert_unlocked(M)        ((void)0)
350
 
 
351
 
#endif
352
183
 
353
184
/* Values:
354
185
   2 - function has not been run
373
204
# define k5_os_mutex_destroy            k5_os_nothread_mutex_destroy
374
205
# define k5_os_mutex_lock               k5_os_nothread_mutex_lock
375
206
# define k5_os_mutex_unlock             k5_os_nothread_mutex_unlock
376
 
# define k5_os_mutex_assert_locked      k5_os_nothread_mutex_assert_locked
377
 
# define k5_os_mutex_assert_unlocked    k5_os_nothread_mutex_assert_unlocked
378
207
 
379
208
# define k5_once_t                      k5_os_nothread_once_t
380
209
# define K5_ONCE_INIT                   K5_OS_NOTHREAD_ONCE_INIT
388
217
 
389
218
   Linux: Stub mutex routines exist, but pthread_once does not.
390
219
 
391
 
   Solaris: In libc there's a pthread_once that doesn't seem to do
 
220
   Solaris <10: In libc there's a pthread_once that doesn't seem to do
392
221
   anything.  Bleah.  But pthread_mutexattr_setrobust_np is defined
393
222
   only in libpthread.  However, some version of GNU libc (Red Hat's
394
223
   Fedora Core 5, reportedly) seems to have that function, but no
396
225
   address.  We now have tests to see if pthread_once actually works,
397
226
   so stick with that for now.
398
227
 
 
228
   Solaris 10: The real thread support now lives in libc, and
 
229
   libpthread is just a filter object.  So we might as well use the
 
230
   real functions unconditionally.  Since we haven't got a test for
 
231
   this property yet, we use NO_WEAK_PTHREADS defined in aclocal.m4
 
232
   depending on the OS type.
 
233
 
399
234
   IRIX 6.5 stub pthread support in libc is really annoying.  The
400
235
   pthread_mutex_lock function returns ENOSYS for a program not linked
401
236
   against -lpthread.  No link-time failure, no weak symbols, etc.
410
245
   If we find a platform with non-functional stubs and no weak
411
246
   references, we may have to resort to some hack like dlsym on the
412
247
   symbol tables of the current process.  */
413
 
#ifdef HAVE_PRAGMA_WEAK_REF
 
248
extern int krb5int_pthread_loaded(void)
 
249
#ifdef __GNUC__
 
250
     /* We should always get the same answer for the life of the process.  */
 
251
     __attribute__((const))
 
252
#endif
 
253
     ;
 
254
#if defined(HAVE_PRAGMA_WEAK_REF) && !defined(NO_WEAK_PTHREADS)
414
255
# pragma weak pthread_once
415
256
# pragma weak pthread_mutex_lock
416
257
# pragma weak pthread_mutex_unlock
418
259
# pragma weak pthread_mutex_init
419
260
# pragma weak pthread_self
420
261
# pragma weak pthread_equal
421
 
extern int krb5int_pthread_loaded(void);
422
262
# define K5_PTHREADS_LOADED     (krb5int_pthread_loaded())
423
 
#else
424
 
/* no pragma weak support */
425
 
# define K5_PTHREADS_LOADED     (1)
426
 
#endif
427
 
 
428
 
#if defined(__mips) && defined(__sgi) && (defined(_SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__))
429
 
/* IRIX 6.5 stub pthread support in libc is really annoying.  The
430
 
   pthread_mutex_lock function returns ENOSYS for a program not linked
431
 
   against -lpthread.  No link-time failure, no weak reference tests,
432
 
   etc.
433
 
 
434
 
   The C library doesn't provide pthread_once; we can use weak
435
 
   reference support for that.  */
436
 
# ifndef HAVE_PRAGMA_WEAK_REF
437
 
#  if defined(__GNUC__) && __GNUC__ < 3
438
 
#   error "Please update to a newer gcc with weak symbol support, or switch to native cc, reconfigure and recompile."
439
 
#  else
440
 
#   error "Weak reference support is required"
441
 
#  endif
442
 
# endif
443
 
#endif
444
 
 
445
 
#ifdef HAVE_PRAGMA_WEAK_REF
446
263
# define USE_PTHREAD_LOCK_ONLY_IF_LOADED
447
 
#endif
448
264
 
449
 
#ifdef HAVE_PRAGMA_WEAK_REF
450
265
/* Can't rely on useful stubs -- see above regarding Solaris.  */
451
266
typedef struct {
452
267
    pthread_once_t o;
456
271
# define k5_once(O,F)   (K5_PTHREADS_LOADED                     \
457
272
                         ? pthread_once(&(O)->o,F)              \
458
273
                         : k5_os_nothread_once(&(O)->n,F))
 
274
 
459
275
#else
 
276
 
 
277
/* no pragma weak support */
 
278
# define K5_PTHREADS_LOADED     (1)
 
279
 
460
280
typedef pthread_once_t k5_once_t;
461
281
# define K5_ONCE_INIT   PTHREAD_ONCE_INIT
462
282
# define k5_once        pthread_once
463
 
#endif
464
 
 
465
 
typedef struct {
466
 
    pthread_mutex_t p;
467
 
#ifdef DEBUG_THREADS
468
 
    pthread_t owner;
469
 
#endif
470
 
#ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED
471
 
    k5_os_nothread_mutex n;
472
 
#endif
473
 
} k5_os_mutex;
474
 
 
475
 
#ifdef DEBUG_THREADS
476
 
# ifdef __GNUC__
477
 
#  define k5_pthread_mutex_lock(M)                      \
478
 
        ({                                              \
479
 
            k5_os_mutex *_m2 = (M);                     \
480
 
            int _r2 = pthread_mutex_lock(&_m2->p);      \
481
 
            if (_r2 == 0) _m2->owner = pthread_self();  \
482
 
            _r2;                                        \
483
 
        })
484
 
# else
485
 
static inline int
486
 
k5_pthread_mutex_lock(k5_os_mutex *m)
487
 
{
488
 
    int r = pthread_mutex_lock(&m->p);
489
 
    if (r)
490
 
        return r;
491
 
    m->owner = pthread_self();
492
 
    return 0;
493
 
}
494
 
# endif
495
 
# define k5_pthread_assert_locked(M)                            \
496
 
        (K5_PTHREADS_LOADED                                     \
497
 
         ? assert(pthread_equal((M)->owner, pthread_self()))    \
498
 
         : (void)0)
499
 
# define k5_pthread_mutex_unlock(M)     \
500
 
        (k5_pthread_assert_locked(M),   \
501
 
         (M)->owner = (pthread_t) 0,    \
502
 
         pthread_mutex_unlock(&(M)->p))
503
 
#else
504
 
# define k5_pthread_mutex_lock(M) pthread_mutex_lock(&(M)->p)
505
 
static inline void k5_pthread_assert_locked(k5_os_mutex *m) { }
506
 
# define k5_pthread_mutex_unlock(M) pthread_mutex_unlock(&(M)->p)
507
 
#endif
508
 
 
509
 
/* Define as functions to:
510
 
   (1) eliminate "statement with no effect" warnings for "0"
511
 
   (2) encourage type-checking in calling code  */
512
 
 
513
 
static inline void k5_pthread_assert_unlocked(pthread_mutex_t *m) { }
514
 
 
515
 
#if defined(DEBUG_THREADS_SLOW) && HAVE_SCHED_H && (HAVE_SCHED_YIELD || HAVE_PRAGMA_WEAK_REF)
516
 
# include <sched.h>
517
 
# if !HAVE_SCHED_YIELD
518
 
#  pragma weak sched_yield
519
 
#  define MAYBE_SCHED_YIELD()   ((void)((&sched_yield != NULL) ? sched_yield() : 0))
520
 
# else
521
 
#  define MAYBE_SCHED_YIELD()   ((void)sched_yield())
522
 
# endif
523
 
#else
524
 
# define MAYBE_SCHED_YIELD()    ((void)0)
525
 
#endif
526
 
 
527
 
/* It may not be obvious why this function is desirable.
528
 
 
529
 
   I want to call pthread_mutex_lock, then sched_yield, then look at
530
 
   the return code from pthread_mutex_lock.  That can't be implemented
531
 
   in a macro without a temporary variable, or GNU C extensions.
532
 
 
533
 
   There used to be an inline function which did it, with both
534
 
   functions called from the inline function.  But that messes with
535
 
   the debug information on a lot of configurations, and you can't
536
 
   tell where the inline function was called from.  (Typically, gdb
537
 
   gives you the name of the function from which the inline function
538
 
   was called, and a line number within the inline function itself.)
539
 
 
540
 
   With this auxiliary function, pthread_mutex_lock can be called at
541
 
   the invoking site via a macro; once it returns, the inline function
542
 
   is called (with messed-up line-number info for gdb hopefully
543
 
   localized to just that call).  */
544
 
#ifdef __GNUC__
545
 
#define return_after_yield(R)                   \
546
 
        __extension__ ({                        \
547
 
            int _r = (R);                       \
548
 
            MAYBE_SCHED_YIELD();                \
549
 
            _r;                                 \
550
 
        })
551
 
#else
552
 
static inline int return_after_yield(int r)
553
 
{
554
 
    MAYBE_SCHED_YIELD();
555
 
    return r;
556
 
}
557
 
#endif
558
 
 
559
 
#ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED
560
 
 
561
 
# if defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) && defined(DEBUG_THREADS)
562
 
#  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
563
 
        { PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, (pthread_t) 0, \
564
 
          K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
565
 
# elif defined(DEBUG_THREADS)
566
 
#  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
567
 
        { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, \
568
 
          K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
569
 
# else
570
 
#  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
571
 
        { PTHREAD_MUTEX_INITIALIZER, K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
572
 
# endif
573
 
 
574
 
# define k5_os_mutex_finish_init(M)             \
575
 
        k5_os_nothread_mutex_finish_init(&(M)->n)
 
283
 
 
284
#endif
 
285
 
 
286
#if defined(__mips) && defined(__sgi) && (defined(_SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__))
 
287
# ifndef HAVE_PRAGMA_WEAK_REF
 
288
#  if defined(__GNUC__) && __GNUC__ < 3
 
289
#   error "Please update to a newer gcc with weak symbol support, or switch to native cc, reconfigure and recompile."
 
290
#  else
 
291
#   error "Weak reference support is required"
 
292
#  endif
 
293
# endif
 
294
#endif
 
295
 
 
296
typedef pthread_mutex_t k5_os_mutex;
 
297
# define K5_OS_MUTEX_PARTIAL_INITIALIZER \
 
298
        PTHREAD_MUTEX_INITIALIZER
 
299
 
 
300
#ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED
 
301
 
 
302
# define k5_os_mutex_finish_init(M)             (0)
576
303
# define k5_os_mutex_init(M)                    \
577
 
        (k5_os_nothread_mutex_init(&(M)->n),    \
578
 
         (K5_PTHREADS_LOADED                    \
579
 
          ? pthread_mutex_init(&(M)->p, 0)      \
580
 
          : 0))
 
304
        (K5_PTHREADS_LOADED ? pthread_mutex_init((M), 0) : 0)
581
305
# define k5_os_mutex_destroy(M)                 \
582
 
        (k5_os_nothread_mutex_destroy(&(M)->n), \
583
 
         (K5_PTHREADS_LOADED                    \
584
 
          ? pthread_mutex_destroy(&(M)->p)      \
585
 
          : 0))
586
 
 
587
 
# define k5_os_mutex_lock(M)                                            \
588
 
        return_after_yield(K5_PTHREADS_LOADED                           \
589
 
                           ? k5_pthread_mutex_lock(M)                   \
590
 
                           : k5_os_nothread_mutex_lock(&(M)->n))
591
 
# define k5_os_mutex_unlock(M)                          \
592
 
        (MAYBE_SCHED_YIELD(),                           \
593
 
         (K5_PTHREADS_LOADED                            \
594
 
          ? k5_pthread_mutex_unlock(M)                  \
595
 
          : k5_os_nothread_mutex_unlock(&(M)->n)))
596
 
 
597
 
# define k5_os_mutex_assert_unlocked(M)                 \
598
 
        (K5_PTHREADS_LOADED                             \
599
 
         ? k5_pthread_assert_unlocked(&(M)->p)          \
600
 
         : k5_os_nothread_mutex_assert_unlocked(&(M)->n))
601
 
# define k5_os_mutex_assert_locked(M)                   \
602
 
        (K5_PTHREADS_LOADED                             \
603
 
         ? k5_pthread_assert_locked(M)                  \
604
 
         : k5_os_nothread_mutex_assert_locked(&(M)->n))
 
306
        (K5_PTHREADS_LOADED ? pthread_mutex_destroy((M)) : 0)
 
307
# define k5_os_mutex_lock(M)                    \
 
308
        (K5_PTHREADS_LOADED ? pthread_mutex_lock(M) : 0)
 
309
# define k5_os_mutex_unlock(M)                  \
 
310
        (K5_PTHREADS_LOADED ? pthread_mutex_unlock(M) : 0)
605
311
 
606
312
#else
607
313
 
608
 
# ifdef DEBUG_THREADS
609
 
#  ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
610
 
#   define K5_OS_MUTEX_PARTIAL_INITIALIZER \
611
 
        { PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, (pthread_t) 0 }
612
 
#  else
613
 
#   define K5_OS_MUTEX_PARTIAL_INITIALIZER \
614
 
        { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0 }
615
 
#  endif
616
 
# else
617
 
#  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
618
 
        { PTHREAD_MUTEX_INITIALIZER }
619
 
# endif
620
 
 
621
314
static inline int k5_os_mutex_finish_init(k5_os_mutex *m) { return 0; }
622
 
# define k5_os_mutex_init(M)            pthread_mutex_init(&(M)->p, 0)
623
 
# define k5_os_mutex_destroy(M)         pthread_mutex_destroy(&(M)->p)
624
 
# define k5_os_mutex_lock(M)    return_after_yield(k5_pthread_mutex_lock(M))
625
 
# define k5_os_mutex_unlock(M)          (MAYBE_SCHED_YIELD(),k5_pthread_mutex_unlock(M))
626
 
 
627
 
# define k5_os_mutex_assert_unlocked(M) k5_pthread_assert_unlocked(&(M)->p)
628
 
# define k5_os_mutex_assert_locked(M)   k5_pthread_assert_locked(M)
 
315
# define k5_os_mutex_init(M)            pthread_mutex_init((M), 0)
 
316
# define k5_os_mutex_destroy(M)         pthread_mutex_destroy((M))
 
317
# define k5_os_mutex_lock(M)            pthread_mutex_lock(M)
 
318
# define k5_os_mutex_unlock(M)          pthread_mutex_unlock(M)
629
319
 
630
320
#endif /* is pthreads always available? */
631
321
 
669
359
         (M)->is_locked = 0,                            \
670
360
         ReleaseMutex((M)->h) ? 0 : GetLastError())
671
361
 
672
 
# define k5_os_mutex_assert_unlocked(M) ((void)0)
673
 
# define k5_os_mutex_assert_locked(M)   ((void)0)
674
 
 
675
362
#else
676
363
 
677
364
# error "Thread support enabled, but thread system unknown"
681
368
 
682
369
 
683
370
 
684
 
typedef struct {
685
 
    k5_debug_loc loc_last, loc_created;
686
 
    k5_os_mutex os;
687
 
    k5_debug_mutex_stats stats;
688
 
} k5_mutex_t;
689
 
#define K5_MUTEX_PARTIAL_INITIALIZER            \
690
 
        { K5_DEBUG_LOC_INIT, K5_DEBUG_LOC_INIT, \
691
 
          K5_OS_MUTEX_PARTIAL_INITIALIZER, K5_MUTEX_STATS_INIT }
692
 
static inline int k5_mutex_init_1(k5_mutex_t *m, k5_debug_loc l)
693
 
{
694
 
    int err = k5_os_mutex_init(&m->os);
695
 
    if (err) return err;
696
 
    m->loc_created = m->loc_last = l;
697
 
    err = k5_mutex_init_stats(&m->stats);
698
 
    assert(err == 0);
699
 
    return 0;
700
 
}
701
 
#define k5_mutex_init(M)        k5_mutex_init_1((M), K5_DEBUG_LOC)
702
 
static inline int k5_mutex_finish_init_1(k5_mutex_t *m, k5_debug_loc l)
703
 
{
704
 
    int err = k5_os_mutex_finish_init(&m->os);
705
 
    if (err) return err;
706
 
    m->loc_created = m->loc_last = l;
707
 
    err = k5_mutex_finish_init_stats(&m->stats);
708
 
    assert(err == 0);
709
 
    return 0;
710
 
}
711
 
#define k5_mutex_finish_init(M) k5_mutex_finish_init_1((M), K5_DEBUG_LOC)
 
371
typedef k5_os_mutex k5_mutex_t;
 
372
#define K5_MUTEX_PARTIAL_INITIALIZER    K5_OS_MUTEX_PARTIAL_INITIALIZER
 
373
static inline int k5_mutex_init(k5_mutex_t *m)
 
374
{
 
375
    return k5_os_mutex_init(m);
 
376
}
 
377
static inline int k5_mutex_finish_init(k5_mutex_t *m)
 
378
{
 
379
    return k5_os_mutex_finish_init(m);
 
380
}
712
381
#define k5_mutex_destroy(M)                     \
713
 
        (k5_os_mutex_assert_unlocked(&(M)->os), \
714
 
         krb5int_mutex_report_stats(M),         \
715
 
         k5_mutex_lock(M), (M)->loc_last = K5_DEBUG_LOC, k5_mutex_unlock(M), \
716
 
         k5_os_mutex_destroy(&(M)->os))
717
 
#ifdef __GNUC__
718
 
#define k5_mutex_lock(M)                                                 \
719
 
        __extension__ ({                                                 \
720
 
            int _err = 0;                                                \
721
 
            k5_mutex_stats_tmp _stats = k5_mutex_stats_start();          \
722
 
            k5_mutex_t *_m = (M);                                        \
723
 
            _err = k5_os_mutex_lock(&_m->os);                            \
724
 
            if (_err == 0) _m->loc_last = K5_DEBUG_LOC;                  \
725
 
            if (_err == 0) k5_mutex_lock_update_stats(&_m->stats, _stats); \
726
 
            _err;                                                        \
727
 
        })
728
 
#else
729
 
static inline int k5_mutex_lock_1(k5_mutex_t *m, k5_debug_loc l)
 
382
    (k5_os_mutex_destroy(M))
 
383
 
 
384
#if __GNUC__ >= 4
 
385
static int k5_mutex_lock(k5_mutex_t *)
 
386
    __attribute__((warn_unused_result));
 
387
#endif
 
388
static inline int k5_mutex_lock(k5_mutex_t *m)
730
389
{
731
 
    int err = 0;
732
 
    k5_mutex_stats_tmp stats = k5_mutex_stats_start();
733
 
    err = k5_os_mutex_lock(&m->os);
734
 
    if (err)
735
 
        return err;
736
 
    m->loc_last = l;
737
 
    k5_mutex_lock_update_stats(&m->stats, stats);
738
 
    return err;
 
390
    return k5_os_mutex_lock(m);
739
391
}
740
 
#define k5_mutex_lock(M)        k5_mutex_lock_1(M, K5_DEBUG_LOC)
741
 
#endif
 
392
 
742
393
#define k5_mutex_unlock(M)                              \
743
 
        (k5_mutex_assert_locked(M),                     \
744
 
         k5_mutex_unlock_update_stats(&(M)->stats),     \
745
 
         (M)->loc_last = K5_DEBUG_LOC,                  \
746
 
         k5_os_mutex_unlock(&(M)->os))
747
 
 
748
 
#define k5_mutex_assert_locked(M)       k5_os_mutex_assert_locked(&(M)->os)
749
 
#define k5_mutex_assert_unlocked(M)     k5_os_mutex_assert_unlocked(&(M)->os)
750
 
 
 
394
        (k5_os_mutex_unlock(M))
 
395
 
 
396
#define k5_mutex_assert_locked(M)       ((void)(M))
 
397
#define k5_mutex_assert_unlocked(M)     ((void)(M))
751
398
#define k5_assert_locked        k5_mutex_assert_locked
752
399
#define k5_assert_unlocked      k5_mutex_assert_unlocked
753
400
 
761
408
    K5_KEY_COM_ERR,
762
409
    K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME,
763
410
    K5_KEY_GSS_KRB5_CCACHE_NAME,
 
411
    K5_KEY_GSS_KRB5_ERROR_MESSAGE,
 
412
    K5_KEY_KIM_ERROR_MESSAGE,
 
413
#if defined(__MACH__) && defined(__APPLE__)
 
414
    K5_KEY_IPC_CONNECTION_INFO,
 
415
    K5_KEY_COM_ERR_REENTER,
 
416
#endif
764
417
    K5_KEY_MAX
765
418
} k5_key_t;
766
419
/* rename shorthand symbols for export */
775
428
 
776
429
extern int  KRB5_CALLCONV krb5int_mutex_alloc  (k5_mutex_t **);
777
430
extern void KRB5_CALLCONV krb5int_mutex_free   (k5_mutex_t *);
778
 
extern int  KRB5_CALLCONV krb5int_mutex_lock   (k5_mutex_t *);
 
431
extern int  KRB5_CALLCONV krb5int_mutex_lock   (k5_mutex_t *)
 
432
#if __GNUC__ >= 4
 
433
    __attribute__((warn_unused_result))
 
434
#endif
 
435
    ;
779
436
extern int  KRB5_CALLCONV krb5int_mutex_unlock (k5_mutex_t *);
780
437
 
781
438
/* In time, many of the definitions above should move into the support
787
444
 
788
445
   For now, plugins should use the exported functions, and not the
789
446
   above macros, and use krb5int_mutex_alloc for allocations.  */
790
 
#ifdef PLUGIN
 
447
#if defined(PLUGIN) || (defined(CONFIG_SMALL) && !defined(THREAD_SUPPORT_IMPL))
791
448
#undef k5_mutex_lock
792
449
#define k5_mutex_lock krb5int_mutex_lock
793
450
#undef k5_mutex_unlock