Coverage Report

Created: 2024-06-18 07:03

/src/server/mysys/my_thr_init.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2000, 2011 Oracle and/or its affiliates.
2
   Copyright 2008, 2021, MariaDB Corporation.
3
4
   This program is free software; you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; version 2 of the License.
7
8
   This program is distributed in the hope that it will be useful,
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
   GNU General Public License for more details.
12
13
   You should have received a copy of the GNU General Public License
14
   along with this program; if not, write to the Free Software
15
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
16
17
/*
18
  Functions to handle initializating and allocationg of all mysys & debug
19
  thread variables.
20
*/
21
22
#include "mysys_priv.h"
23
#include <m_string.h>
24
#include <signal.h>
25
26
pthread_key(struct st_my_thread_var*, THR_KEY_mysys=-1);
27
mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open,
28
              THR_LOCK_lock, THR_LOCK_myisam, THR_LOCK_heap,
29
              THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads,
30
              THR_LOCK_myisam_mmap;
31
32
mysql_cond_t  THR_COND_threads;
33
uint            THR_thread_count= 0;
34
uint    my_thread_end_wait_time= 5;
35
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
36
mysql_mutex_t LOCK_localtime_r;
37
#endif
38
#ifdef _MSC_VER
39
static void install_sigabrt_handler();
40
#endif
41
42
/** True if @c my_thread_global_init() has been called. */
43
static my_bool my_thread_global_init_done= 0;
44
/* True if THR_KEY_mysys is created */
45
my_bool my_thr_key_mysys_exists= 0;
46
47
48
/*
49
  These are mutexes not used by safe_mutex or my_thr_init.c
50
51
  We want to free these earlier than other mutex so that safe_mutex
52
  can detect if all mutex and memory is freed properly.
53
*/
54
55
static void my_thread_init_common_mutex(void)
56
0
{
57
0
  mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
58
0
  mysql_mutex_init(key_THR_LOCK_lock, &THR_LOCK_lock, MY_MUTEX_INIT_FAST);
59
0
  mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW);
60
0
  mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap, MY_MUTEX_INIT_FAST);
61
0
  mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
62
0
  mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
63
0
  mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
64
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
65
  mysql_mutex_init(key_LOCK_localtime_r, &LOCK_localtime_r, MY_MUTEX_INIT_SLOW);
66
#endif
67
0
}
68
69
void my_thread_destroy_common_mutex(void)
70
0
{
71
0
  mysql_mutex_destroy(&THR_LOCK_open);
72
0
  mysql_mutex_destroy(&THR_LOCK_lock);
73
0
  mysql_mutex_destroy(&THR_LOCK_myisam);
74
0
  mysql_mutex_destroy(&THR_LOCK_myisam_mmap);
75
0
  mysql_mutex_destroy(&THR_LOCK_heap);
76
0
  mysql_mutex_destroy(&THR_LOCK_net);
77
0
  mysql_mutex_destroy(&THR_LOCK_charset);
78
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
79
  mysql_mutex_destroy(&LOCK_localtime_r);
80
#endif
81
0
}
82
83
84
/*
85
  These mutexes are used by my_thread_init() and after
86
  my_thread_destroy_mutex()
87
*/
88
89
static void my_thread_init_internal_mutex(void)
90
0
{
91
0
  mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
92
0
  mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
93
0
  mysql_cond_init(key_THR_COND_threads, &THR_COND_threads, NULL);
94
0
}
95
96
void my_thread_destroy_internal_mutex(void)
97
0
{
98
0
  mysql_mutex_destroy(&THR_LOCK_threads);
99
0
  mysql_mutex_destroy(&THR_LOCK_malloc);
100
0
  mysql_cond_destroy(&THR_COND_threads);
101
0
}
102
103
static void my_thread_init_thr_mutex(struct st_my_thread_var *var)
104
0
{
105
0
  mysql_mutex_init(key_my_thread_var_mutex, &var->mutex, MY_MUTEX_INIT_FAST);
106
0
  mysql_cond_init(key_my_thread_var_suspend, &var->suspend, NULL);
107
0
}
108
109
static void my_thread_destory_thr_mutex(struct st_my_thread_var *var)
110
0
{
111
0
  mysql_mutex_destroy(&var->mutex);
112
0
  mysql_cond_destroy(&var->suspend);
113
0
}
114
115
116
/**
117
  Re-initialize components initialized early with @c my_thread_global_init.
118
  Some mutexes were initialized before the instrumentation.
119
  Destroy + create them again, now that the instrumentation
120
  is in place.
121
  This is safe, since this function() is called before creating new threads,
122
  so the mutexes are not in use.
123
*/
124
void my_thread_global_reinit(void)
125
0
{
126
0
  struct st_my_thread_var *tmp;
127
128
0
  DBUG_ASSERT(my_thread_global_init_done);
129
130
0
#ifdef HAVE_PSI_INTERFACE
131
0
  my_init_mysys_psi_keys();
132
0
#endif
133
134
0
  my_thread_destroy_common_mutex();
135
0
  my_thread_init_common_mutex();
136
137
0
  my_thread_destroy_internal_mutex();
138
0
  my_thread_init_internal_mutex();
139
140
0
  tmp= my_thread_var;
141
0
  DBUG_ASSERT(tmp);
142
143
0
  my_thread_destory_thr_mutex(tmp);
144
0
  my_thread_init_thr_mutex(tmp);
145
0
}
146
147
/*
148
  initialize thread environment
149
150
  SYNOPSIS
151
    my_thread_global_init()
152
153
  RETURN
154
    0  ok
155
    1  error (Couldn't create THR_KEY_mysys)
156
*/
157
158
my_bool my_thread_global_init(void)
159
0
{
160
0
  int pth_ret;
161
162
  /* Normally this should never be called twice */
163
0
  DBUG_ASSERT(my_thread_global_init_done == 0);
164
0
  if (my_thread_global_init_done)
165
0
    return 0;
166
0
  my_thread_global_init_done= 1;
167
168
  /*
169
    THR_KEY_mysys is deleted in my_end() as DBUG libraries are using it even
170
    after my_thread_global_end() is called.
171
    my_thr_key_mysys_exist is used to protect against application like QT
172
    that calls my_thread_global_init() + my_thread_global_end() multiple times
173
    without calling my_init() + my_end().
174
  */
175
0
  if (!my_thr_key_mysys_exists &&
176
0
      (pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
177
0
  {
178
0
    fprintf(stderr, "Can't initialize threads: error %d\n", pth_ret);
179
0
    return 1;
180
0
  }
181
0
  my_thr_key_mysys_exists= 1;
182
183
  /* Mutex used by my_thread_init() and after my_thread_destroy_mutex() */
184
0
  my_thread_init_internal_mutex();
185
186
0
  if (my_thread_init())
187
0
    return 1;
188
189
190
0
  my_thread_init_common_mutex();
191
192
0
  return 0;
193
0
}
194
195
196
/**
197
   End the mysys thread system. Called when ending the last thread
198
*/
199
200
void my_thread_global_end(void)
201
0
{
202
0
  struct timespec abstime;
203
0
  my_bool all_threads_killed= 1;
204
205
0
  set_timespec(abstime, my_thread_end_wait_time);
206
0
  mysql_mutex_lock(&THR_LOCK_threads);
207
0
  while (THR_thread_count > 0)
208
0
  {
209
0
    int error= mysql_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
210
0
                                    &abstime);
211
0
    if (error == ETIMEDOUT || error == ETIME)
212
0
    {
213
0
#ifdef HAVE_PTHREAD_KILL
214
      /*
215
        We shouldn't give an error here, because if we don't have
216
        pthread_kill(), programs like mysqld can't ensure that all threads
217
        are killed when we enter here.
218
      */
219
0
      if (THR_thread_count)
220
0
        fprintf(stderr,
221
0
                "Error in my_thread_global_end(): %d threads didn't exit\n",
222
0
                THR_thread_count);
223
0
#endif /* HAVE_PTHREAD_KILL */
224
#ifdef SAFEMALLOC
225
      /* We know we will have memoryleaks, suppress the leak report */
226
      sf_leaking_memory= 1;
227
#endif /* SAFEMALLOC */
228
0
      all_threads_killed= 0;
229
0
      break;
230
0
    }
231
0
  }
232
0
  mysql_mutex_unlock(&THR_LOCK_threads);
233
234
0
  my_thread_destroy_common_mutex();
235
236
  /*
237
    Only destroy the mutex & conditions if we don't have other threads around
238
    that could use them.
239
  */
240
0
  if (all_threads_killed)
241
0
    my_thread_destroy_internal_mutex();
242
0
  my_thread_global_init_done= 0;
243
0
}
244
245
static my_thread_id thread_id= 0;
246
247
/*
248
  Allocate thread specific memory for the thread, used by mysys and dbug
249
250
  SYNOPSIS
251
    my_thread_init()
252
253
  NOTES
254
    We can't use mutex_locks here if we are using windows as
255
    we may have compiled the program with SAFE_MUTEX, in which
256
    case the checking of mutex_locks will not work until
257
    the pthread_self thread specific variable is initialized.
258
259
   This function may called multiple times for a thread, for example
260
   if one uses my_init() followed by mysql_server_init().
261
262
  RETURN
263
    0  ok
264
    1  Fatal error; mysys/dbug functions can't be used
265
*/
266
267
my_bool my_thread_init(void)
268
0
{
269
0
  struct st_my_thread_var *tmp;
270
0
  my_bool error=0;
271
272
0
  if (!my_thread_global_init_done)
273
0
    return 1; /* cannot proceed with uninitialized library */
274
275
#ifdef EXTRA_DEBUG_THREADS
276
  fprintf(stderr,"my_thread_init(): pthread_self: %p\n", pthread_self());
277
#endif  
278
279
0
  if (my_thread_var)
280
0
  {
281
#ifdef EXTRA_DEBUG_THREADS
282
    fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
283
            (long) pthread_self());
284
#endif    
285
0
    goto end;
286
0
  }
287
288
#ifdef _MSC_VER
289
  install_sigabrt_handler();
290
#endif
291
292
0
  if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
293
0
  {
294
0
    error= 1;
295
0
    goto end;
296
0
  }
297
0
  set_mysys_var(tmp);
298
0
  tmp->pthread_self= pthread_self();
299
0
  my_thread_init_thr_mutex(tmp);
300
301
0
  tmp->stack_ends_here= (char*)&tmp +
302
0
                         STACK_DIRECTION * (long)my_thread_stack_size;
303
304
0
  mysql_mutex_lock(&THR_LOCK_threads);
305
0
  tmp->id= tmp->dbug_id= ++thread_id;
306
0
  ++THR_thread_count;
307
0
  mysql_mutex_unlock(&THR_LOCK_threads);
308
0
  tmp->init= 1;
309
#ifndef DBUG_OFF
310
  /* Generate unique name for thread */
311
  (void) my_thread_name();
312
#endif
313
314
0
end:
315
0
  return error;
316
0
}
317
318
319
/*
320
  Deallocate memory used by the thread for book-keeping
321
322
  SYNOPSIS
323
    my_thread_end()
324
325
  NOTE
326
    This may be called multiple times for a thread.
327
    This happens for example when one calls 'mysql_server_init()'
328
    mysql_server_end() and then ends with a mysql_end().
329
*/
330
331
void my_thread_end(void)
332
0
{
333
0
  struct st_my_thread_var *tmp;
334
0
  tmp= my_thread_var;
335
336
#ifdef EXTRA_DEBUG_THREADS
337
  fprintf(stderr,"my_thread_end(): tmp: %p  pthread_self: %p  thread_id: %ld\n",
338
    tmp, pthread_self(), tmp ? (long) tmp->id : 0L);
339
#endif  
340
341
  /*
342
    Remove the instrumentation for this thread.
343
    This must be done before trashing st_my_thread_var,
344
    because the LF_HASH depends on it.
345
  */
346
0
  PSI_CALL_delete_current_thread();
347
348
  /*
349
    We need to disable DBUG early for this thread to ensure that the
350
    the mutex calls doesn't enable it again
351
    To this we have to both do DBUG_POP() and also reset THR_KEY_mysys
352
    as the key is used by DBUG.
353
  */
354
0
  DBUG_POP();
355
0
  set_mysys_var(NULL);
356
357
0
  if (tmp && tmp->init)
358
0
  {
359
#if !defined(DBUG_OFF)
360
    /* tmp->dbug is allocated inside DBUG library */
361
    if (tmp->dbug)
362
    {
363
      free(tmp->dbug);
364
      tmp->dbug=0;
365
    }
366
#endif
367
0
    my_thread_destory_thr_mutex(tmp);
368
369
    /*
370
      Decrement counter for number of running threads. We are using this
371
      in my_thread_global_end() to wait until all threads have called
372
      my_thread_end and thus freed all memory they have allocated in
373
      my_thread_init() and DBUG_xxxx
374
    */
375
0
    mysql_mutex_lock(&THR_LOCK_threads);
376
0
    DBUG_ASSERT(THR_thread_count != 0);
377
0
    if (--THR_thread_count == 0)
378
0
      mysql_cond_signal(&THR_COND_threads);
379
0
    mysql_mutex_unlock(&THR_LOCK_threads);
380
381
    /* Trash variable so that we can detect false accesses to my_thread_var */
382
0
    tmp->init= 2;
383
0
    free(tmp);
384
0
  }
385
0
}
386
387
struct st_my_thread_var *_my_thread_var(void)
388
0
{
389
0
  return  my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
390
0
}
391
392
int set_mysys_var(struct st_my_thread_var *mysys_var)
393
0
{
394
0
  return my_pthread_setspecific_ptr(THR_KEY_mysys, mysys_var);
395
0
}
396
397
/****************************************************************************
398
  Get name of current thread.
399
****************************************************************************/
400
401
my_thread_id my_thread_dbug_id()
402
0
{
403
  /*
404
    We need to do this test as some system thread may not yet have called
405
    my_thread_init().
406
  */
407
0
  struct st_my_thread_var *tmp= my_thread_var;
408
0
  return tmp ? tmp->dbug_id : 0;
409
0
}
410
411
#ifdef DBUG_OFF
412
const char *my_thread_name(void)
413
0
{
414
0
  return "no_name";
415
0
}
416
417
#else
418
419
const char *my_thread_name(void)
420
{
421
  char name_buff[100];
422
  struct st_my_thread_var *tmp=my_thread_var;
423
  if (!tmp->name[0])
424
  {
425
    my_thread_id id= my_thread_dbug_id();
426
    snprintf(name_buff, sizeof(name_buff), "T@%lu", (ulong) id);
427
    strmake_buf(tmp->name, name_buff);
428
  }
429
  return tmp->name;
430
}
431
432
/* Return pointer to DBUG for holding current state */
433
434
extern void **my_thread_var_dbug()
435
{
436
  struct st_my_thread_var *tmp;
437
  if (!my_thread_global_init_done)
438
    return NULL;
439
  tmp= my_thread_var;
440
  return tmp && tmp->init ? &tmp->dbug : 0;
441
}
442
#endif /* DBUG_OFF */
443
444
/* Return pointer to mutex_in_use */
445
446
safe_mutex_t **my_thread_var_mutex_in_use()
447
0
{
448
0
  struct st_my_thread_var *tmp;
449
0
  if (!my_thread_global_init_done)
450
0
    return NULL;
451
0
  tmp= my_thread_var;
452
0
  return tmp ? &tmp->mutex_in_use : 0;
453
0
}
454
455
#ifdef _WIN32
456
/*
457
  In Visual Studio 2005 and later, default SIGABRT handler will overwrite
458
  any unhandled exception filter set by the application  and will try to
459
  call JIT debugger. This is not what we want, this we calling __debugbreak
460
  to stop in debugger, if process is being debugged or to generate 
461
  EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
462
*/
463
464
#if (_MSC_VER >= 1400)
465
static void my_sigabrt_handler(int sig)
466
{
467
  __debugbreak();
468
}
469
#endif /*_MSC_VER >=1400 */
470
471
static void install_sigabrt_handler(void)
472
{
473
#if (_MSC_VER >=1400)
474
  /*abort() should not override our exception filter*/
475
  _set_abort_behavior(0,_CALL_REPORTFAULT);
476
  signal(SIGABRT,my_sigabrt_handler);
477
#endif /* _MSC_VER >=1400 */
478
}
479
#endif
480
481
#ifdef HAVE_PSI_MUTEX_INTERFACE
482
ATTRIBUTE_COLD int psi_mutex_lock(mysql_mutex_t *that,
483
                                  const char *file, uint line)
484
0
{
485
0
  PSI_mutex_locker_state state;
486
0
  PSI_mutex_locker *locker= PSI_MUTEX_CALL(start_mutex_wait)
487
0
    (&state, that->m_psi, PSI_MUTEX_LOCK, file, line);
488
# ifdef SAFE_MUTEX
489
  int result= safe_mutex_lock(&that->m_mutex, FALSE, file, line);
490
# else
491
0
  int result= pthread_mutex_lock(&that->m_mutex);
492
0
# endif
493
0
  if (locker)
494
0
    PSI_MUTEX_CALL(end_mutex_wait)(locker, result);
495
0
  return result;
496
0
}
497
498
ATTRIBUTE_COLD int psi_mutex_trylock(mysql_mutex_t *that,
499
                                     const char *file, uint line)
500
0
{
501
0
  PSI_mutex_locker_state state;
502
0
  PSI_mutex_locker *locker= PSI_MUTEX_CALL(start_mutex_wait)
503
0
    (&state, that->m_psi, PSI_MUTEX_TRYLOCK, file, line);
504
# ifdef SAFE_MUTEX
505
  int result= safe_mutex_lock(&that->m_mutex, TRUE, file, line);
506
# else
507
0
  int result= pthread_mutex_trylock(&that->m_mutex);
508
0
# endif
509
0
  if (locker)
510
0
    PSI_MUTEX_CALL(end_mutex_wait)(locker, result);
511
0
  return result;
512
0
}
513
#endif /* HAVE_PSI_MUTEX_INTERFACE */
514
515
#ifdef HAVE_PSI_RWLOCK_INTERFACE
516
ATTRIBUTE_COLD
517
int psi_rwlock_rdlock(mysql_rwlock_t *that, const char *file, uint line)
518
0
{
519
0
  PSI_rwlock_locker_state state;
520
0
  PSI_rwlock_locker *locker= PSI_RWLOCK_CALL(start_rwlock_rdwait)
521
0
    (&state, that->m_psi, PSI_RWLOCK_READLOCK, file, line);
522
0
  int result= rw_rdlock(&that->m_rwlock);
523
0
  if (locker)
524
0
    PSI_RWLOCK_CALL(end_rwlock_rdwait)(locker, result);
525
0
  return result;
526
0
}
527
528
ATTRIBUTE_COLD
529
int psi_rwlock_tryrdlock(mysql_rwlock_t *that, const char *file, uint line)
530
0
{
531
0
  PSI_rwlock_locker_state state;
532
0
  PSI_rwlock_locker *locker= PSI_RWLOCK_CALL(start_rwlock_rdwait)
533
0
    (&state, that->m_psi, PSI_RWLOCK_TRYREADLOCK, file, line);
534
0
  int result= rw_tryrdlock(&that->m_rwlock);
535
0
  if (locker)
536
0
    PSI_RWLOCK_CALL(end_rwlock_rdwait)(locker, result);
537
0
  return result;
538
0
}
539
540
ATTRIBUTE_COLD
541
int psi_rwlock_trywrlock(mysql_rwlock_t *that, const char *file, uint line)
542
0
{
543
0
  PSI_rwlock_locker_state state;
544
0
  PSI_rwlock_locker *locker= PSI_RWLOCK_CALL(start_rwlock_wrwait)
545
0
    (&state, that->m_psi, PSI_RWLOCK_TRYWRITELOCK, file, line);
546
0
  int result= rw_trywrlock(&that->m_rwlock);
547
0
  if (locker)
548
0
    PSI_RWLOCK_CALL(end_rwlock_wrwait)(locker, result);
549
0
  return result;
550
0
}
551
552
ATTRIBUTE_COLD
553
int psi_rwlock_wrlock(mysql_rwlock_t *that, const char *file, uint line)
554
0
{
555
0
  PSI_rwlock_locker_state state;
556
0
  PSI_rwlock_locker *locker= PSI_RWLOCK_CALL(start_rwlock_wrwait)
557
0
    (&state, that->m_psi, PSI_RWLOCK_WRITELOCK, file, line);
558
0
  int result= rw_wrlock(&that->m_rwlock);
559
0
  if (locker)
560
0
    PSI_RWLOCK_CALL(end_rwlock_wrwait)(locker, result);
561
0
  return result;
562
0
}
563
564
# ifndef DISABLE_MYSQL_PRLOCK_H
565
ATTRIBUTE_COLD
566
int psi_prlock_rdlock(mysql_prlock_t *that, const char *file, uint line)
567
0
{
568
0
  PSI_rwlock_locker_state state;
569
0
  PSI_rwlock_locker *locker= PSI_RWLOCK_CALL(start_rwlock_rdwait)
570
0
    (&state, that->m_psi, PSI_RWLOCK_READLOCK, file, line);
571
0
  int result= rw_pr_rdlock(&that->m_prlock);
572
0
  if (locker)
573
0
    PSI_RWLOCK_CALL(end_rwlock_rdwait)(locker, result);
574
0
  return result;
575
0
}
576
577
ATTRIBUTE_COLD
578
int psi_prlock_wrlock(mysql_prlock_t *that, const char *file, uint line)
579
0
{
580
0
  PSI_rwlock_locker_state state;
581
0
  PSI_rwlock_locker *locker= PSI_RWLOCK_CALL(start_rwlock_wrwait)
582
0
    (&state, that->m_psi, PSI_RWLOCK_WRITELOCK, file, line);
583
0
  int result= rw_pr_wrlock(&that->m_prlock);
584
0
  if (locker)
585
0
    PSI_RWLOCK_CALL(end_rwlock_wrwait)(locker, result);
586
0
  return result;
587
0
}
588
# endif /* !DISABLE_MYSQL_PRLOCK_H */
589
#endif /* HAVE_PSI_RWLOCK_INTERFACE */
590
591
#ifdef HAVE_PSI_COND_INTERFACE
592
ATTRIBUTE_COLD int psi_cond_wait(mysql_cond_t *that, mysql_mutex_t *mutex,
593
                                 const char *file, uint line)
594
0
{
595
0
  PSI_cond_locker_state state;
596
0
  PSI_cond_locker *locker= PSI_COND_CALL(start_cond_wait)
597
0
    (&state, that->m_psi, mutex->m_psi, PSI_COND_WAIT, file, line);
598
0
  int result= my_cond_wait(&that->m_cond, &mutex->m_mutex);
599
0
  if (locker)
600
0
    PSI_COND_CALL(end_cond_wait)(locker, result);
601
0
  return result;
602
0
}
603
604
ATTRIBUTE_COLD int psi_cond_timedwait(mysql_cond_t *that, mysql_mutex_t *mutex,
605
                                      const struct timespec *abstime,
606
                                      const char *file, uint line)
607
0
{
608
0
  PSI_cond_locker_state state;
609
0
  PSI_cond_locker *locker= PSI_COND_CALL(start_cond_wait)
610
0
    (&state, that->m_psi, mutex->m_psi, PSI_COND_TIMEDWAIT, file, line);
611
0
  int result= my_cond_timedwait(&that->m_cond, &mutex->m_mutex, abstime);
612
0
  if (psi_likely(locker))
613
0
    PSI_COND_CALL(end_cond_wait)(locker, result);
614
0
  return result;
615
0
}
616
#endif /* HAVE_PSI_COND_INTERFACE */