Coverage Report

Created: 2024-06-18 07:03

/src/server/mysys/my_init.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   Copyright (c) 2000, 2012, Oracle and/or its affiliates
3
   Copyright (c) 2009, 2011, Monty Program Ab
4
5
   This program is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; version 2 of the License.
8
9
   This program is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with this program; if not, write to the Free Software
16
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
17
18
#include "mysys_priv.h"
19
#include "my_static.h"
20
#include "mysys_err.h"
21
#include <m_string.h>
22
#include <m_ctype.h>
23
#include <signal.h>
24
#include <mysql/psi/mysql_stage.h>
25
#ifdef HAVE_UNISTD_H
26
#include <unistd.h>
27
#endif
28
#ifdef _WIN32
29
#ifdef _MSC_VER
30
#include <locale.h>
31
#include <crtdbg.h>
32
/* WSAStartup needs winsock library*/
33
#pragma comment(lib, "ws2_32")
34
#endif
35
static void my_win_init(void);
36
static my_bool win32_init_tcp_ip();
37
static void setup_codepages();
38
#else
39
#define my_win_init()
40
#endif
41
42
#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)
43
#define _SC_PAGESIZE _SC_PAGE_SIZE
44
#endif
45
46
#if defined(__linux__)
47
0
#define EXE_LINKPATH "/proc/self/exe"
48
#elif defined(__FreeBSD__)
49
/* unfortunately, not mounted by default */
50
#define EXE_LINKPATH "/proc/curproc/file"
51
#endif
52
53
extern pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
54
55
#define SCALE_SEC       100
56
#define SCALE_USEC      10000
57
58
my_bool my_init_done= 0;
59
uint  mysys_usage_id= 0;              /* Incremented for each my_init() */
60
size_t  my_system_page_size= 8192;  /* Default if no sysconf() */
61
62
ulonglong   my_thread_stack_size= (sizeof(void*) <= 4)? 65536: ((256-16)*1024);
63
64
static ulong atoi_octal(const char *str)
65
0
{
66
0
  long int tmp;
67
0
  while (*str && my_isspace(&my_charset_latin1, *str))
68
0
    str++;
69
0
  str2int(str,
70
0
    (*str == '0' ? 8 : 10),       /* Octalt or decimalt */
71
0
    0, INT_MAX, &tmp);
72
0
  return (ulong) tmp;
73
0
}
74
75
MYSQL_FILE *mysql_stdin= NULL;
76
static MYSQL_FILE instrumented_stdin;
77
78
#ifdef _WIN32
79
static UINT orig_console_cp, orig_console_output_cp;
80
81
static void reset_console_cp(void)
82
{
83
  /*
84
    We try not to call SetConsoleCP unnecessarily, to workaround a bug on
85
    older Windows 10 (1803), which could switch truetype console fonts to
86
    raster, eventhough SetConsoleCP would be a no-op (switch from UTF8 to UTF8).
87
  */
88
  if (GetConsoleCP() != orig_console_cp)
89
    SetConsoleCP(orig_console_cp);
90
  if (GetConsoleOutputCP() != orig_console_output_cp)
91
    SetConsoleOutputCP(orig_console_output_cp);
92
}
93
94
/*
95
  The below fixes discrepancies in console output and
96
  command line parameter encoding. command line is in
97
  ANSI codepage, output to console by default is in OEM, but
98
  we like them to be in the same encoding.
99
100
  We do this only if current codepage is UTF8, i.e when we
101
  know we're on Windows that can handle UTF8 well.
102
*/
103
static void setup_codepages()
104
{
105
  UINT acp;
106
  BOOL is_a_tty= fileno(stdout) >= 0 && isatty(fileno(stdout));
107
108
  if (is_a_tty)
109
  {
110
    /*
111
      Save console codepages, in case we change them,
112
      to restore them on exit.
113
    */
114
    orig_console_cp= GetConsoleCP();
115
    orig_console_output_cp= GetConsoleOutputCP();
116
    if (orig_console_cp && orig_console_output_cp)
117
      atexit(reset_console_cp);
118
  }
119
120
  if ((acp= GetACP()) != CP_UTF8)
121
    return;
122
123
  /*
124
    Use setlocale to make mbstowcs/mkdir/getcwd behave, see
125
    https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale
126
  */
127
  setlocale(LC_ALL, "en_US.UTF8");
128
129
  if (is_a_tty && (orig_console_cp != acp || orig_console_output_cp != acp))
130
  {
131
    /*
132
      If ANSI codepage is UTF8, we actually want to switch console
133
      to it as well.
134
    */
135
    SetConsoleCP(acp);
136
    SetConsoleOutputCP(acp);
137
  }
138
}
139
#endif
140
141
/**
142
  Initialize my_sys functions, resources and variables
143
144
  @return Initialization result
145
    @retval 0 Success
146
    @retval 1 Error. Couldn't initialize environment
147
*/
148
my_bool my_init(void)
149
0
{
150
0
  char *str;
151
152
0
  if (my_init_done)
153
0
    return 0;
154
155
0
  my_init_done= 1;
156
157
0
  mysys_usage_id++;
158
0
  my_umask= 0660;                       /* Default umask for new files */
159
0
  my_umask_dir= 0700;                   /* Default umask for new directories */
160
0
  my_global_flags= 0;
161
0
#ifdef _SC_PAGESIZE
162
0
  my_system_page_size= sysconf(_SC_PAGESIZE);
163
0
#endif
164
165
  /* Default creation of new files */
166
0
  if ((str= getenv("UMASK")) != 0)
167
0
    my_umask= (int) (atoi_octal(str) | 0600);
168
  /* Default creation of new dir's */
169
0
  if ((str= getenv("UMASK_DIR")) != 0)
170
0
    my_umask_dir= (int) (atoi_octal(str) | 0700);
171
172
0
  init_glob_errs();
173
174
0
  instrumented_stdin.m_file= stdin;
175
0
  instrumented_stdin.m_psi= NULL;       /* not yet instrumented */
176
0
  mysql_stdin= & instrumented_stdin;
177
178
0
  my_progname_short= "unknown";
179
  /* Initialize our mutex handling */
180
0
  my_mutex_init();
181
182
0
  if (my_thread_global_init())
183
0
    return 1;
184
185
0
  if (my_progname)
186
0
  {
187
0
    char link_name[FN_REFLEN];
188
0
    my_progname_short= my_progname + dirname_length(my_progname);
189
    /*
190
      if my_progname_short doesn't start from "mariadb", but it's
191
      a symlink to an actual executable, that does - warn the user.
192
      First try to find the actual name via /proc, but if it's unmounted
193
      (which it usually is on FreeBSD) resort to my_progname
194
    */
195
0
    if (strncmp(my_progname_short, "mariadb", 7))
196
0
    {
197
0
      int res= 1;
198
0
#ifdef EXE_LINKPATH
199
0
      res= my_readlink(link_name, EXE_LINKPATH, MYF(0));
200
0
#endif
201
0
      if ((res == 0 || my_readlink(link_name, my_progname, MYF(0)) == 0) &&
202
0
           strncmp(link_name + dirname_length(link_name), "mariadb", 7) == 0)
203
0
      my_error(EE_NAME_DEPRECATED, MYF(MY_WME), link_name);
204
0
    }
205
0
  }
206
207
#if defined(SAFEMALLOC) && !defined(DBUG_OFF)
208
  dbug_sanity= sf_sanity;
209
#endif
210
211
  /* $HOME is needed early to parse configuration files located in ~/ */
212
0
  if ((home_dir= getenv("HOME")) != 0)
213
0
    home_dir= intern_filename(home_dir_buff, home_dir);
214
215
0
  {
216
0
    DBUG_ENTER("my_init");
217
0
    DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
218
0
    my_time_init();
219
0
    my_win_init();
220
0
    DBUG_PRINT("exit", ("home: '%s'", home_dir));
221
#ifdef _WIN32
222
    if (win32_init_tcp_ip())
223
      DBUG_RETURN(1);
224
#endif
225
#ifdef CHECK_UNLIKELY
226
    init_my_likely();
227
#endif
228
0
    DBUG_RETURN(0);
229
0
  }
230
0
} /* my_init */
231
232
233
  /* End my_sys */
234
235
void my_end(int infoflag)
236
0
{
237
  /*
238
    this code is suboptimal to workaround a bug in
239
    Sun CC: Sun C++ 5.6 2004/06/02 for x86, and should not be
240
    optimized until this compiler is not in use anymore
241
  */
242
0
  FILE *info_file= DBUG_FILE;
243
0
  my_bool print_info= (info_file != stderr);
244
245
0
  if (!my_init_done)
246
0
    return;
247
248
  /*
249
    We do not use DBUG_ENTER here, as after cleanup DBUG is no longer
250
    operational, so we cannot use DBUG_RETURN.
251
  */
252
0
  DBUG_PRINT("info",("Shutting down: infoflag: %d  print_info: %d",
253
0
                     infoflag, print_info));
254
0
  if (!info_file)
255
0
  {
256
0
    info_file= stderr;
257
0
    print_info= 0;
258
0
  }
259
260
0
  if ((infoflag & MY_CHECK_ERROR) || print_info)
261
0
  {                                     /* Test if some file is left open */
262
0
    char ebuff[512];
263
0
    uint i, open_files, open_streams;
264
265
0
    for (open_streams= open_files= i= 0 ; i < my_file_limit ; i++)
266
0
    {
267
0
      if (my_file_info[i].type == UNOPEN)
268
0
        continue;
269
0
      if (my_file_info[i].type == STREAM_BY_FOPEN ||
270
0
          my_file_info[i].type == STREAM_BY_FDOPEN)
271
0
        open_streams++;
272
0
      else
273
0
        open_files++;
274
275
#ifdef EXTRA_DEBUG
276
      fprintf(stderr, EE(EE_FILE_NOT_CLOSED), my_file_info[i].name, i);
277
      fputc('\n', stderr);
278
#endif
279
0
    }
280
0
    if (open_files || open_streams)
281
0
    {
282
0
      my_snprintf(ebuff, sizeof(ebuff), EE(EE_OPEN_WARNING),
283
0
                  open_files, open_streams);
284
0
      my_message_stderr(EE_OPEN_WARNING, ebuff, ME_BELL);
285
0
      DBUG_PRINT("error", ("%s", ebuff));
286
0
    }
287
288
#ifdef CHECK_UNLIKELY
289
    end_my_likely(info_file);
290
#endif
291
0
  }
292
0
  free_charsets();
293
0
  my_error_unregister_all();
294
0
  my_once_free();
295
296
0
  if ((infoflag & MY_GIVE_INFO) || print_info)
297
0
  {
298
0
#ifdef HAVE_GETRUSAGE
299
0
    struct rusage rus;
300
#ifdef HAVE_valgrind
301
    /* Purify assumes that rus is uninitialized after getrusage call */
302
    bzero((char*) &rus, sizeof(rus));
303
#endif
304
0
    if (!getrusage(RUSAGE_SELF, &rus))
305
0
      fprintf(info_file,"\n\
306
0
User time %.2f, System time %.2f\n\
307
0
Maximum resident set size %ld, Integral resident set size %ld\n\
308
0
Non-physical pagefaults %ld, Physical pagefaults %ld, Swaps %ld\n\
309
0
Blocks in %ld out %ld, Messages in %ld out %ld, Signals %ld\n\
310
0
Voluntary context switches %ld, Involuntary context switches %ld\n",
311
0
        (rus.ru_utime.tv_sec * SCALE_SEC +
312
0
         rus.ru_utime.tv_usec / SCALE_USEC) / 100.0,
313
0
        (rus.ru_stime.tv_sec * SCALE_SEC +
314
0
         rus.ru_stime.tv_usec / SCALE_USEC) / 100.0,
315
0
        rus.ru_maxrss, rus.ru_idrss,
316
0
        rus.ru_minflt, rus.ru_majflt,
317
0
        rus.ru_nswap, rus.ru_inblock, rus.ru_oublock,
318
0
        rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
319
0
        rus.ru_nvcsw, rus.ru_nivcsw);
320
0
#endif
321
#if defined(_MSC_VER)
322
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
323
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
324
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
325
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
326
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
327
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
328
   _CrtCheckMemory();
329
#endif
330
0
  }
331
332
0
  my_thread_end();
333
0
  my_thread_global_end();
334
335
0
  if (!(infoflag & MY_DONT_FREE_DBUG))
336
0
    DBUG_END();                /* Must be done as late as possible */
337
338
0
  my_mutex_end();
339
#if defined(SAFE_MUTEX)
340
  /*
341
    Check on destroying of mutexes. A few may be left that will get cleaned
342
    up by C++ destructors
343
  */
344
  safe_mutex_end((infoflag & (MY_GIVE_INFO | MY_CHECK_ERROR)) ? stderr :
345
                 (FILE *) 0);
346
#endif /* defined(SAFE_MUTEX) */
347
348
#ifdef _WIN32
349
   WSACleanup();
350
#endif
351
 
352
  /* At very last, delete mysys key, it is used everywhere including DBUG */
353
0
  pthread_key_delete(THR_KEY_mysys);
354
0
  my_init_done= my_thr_key_mysys_exists= 0;
355
0
} /* my_end */
356
357
#ifdef DBUG_ASSERT_EXISTS
358
/* Dummy tag function for debugging */
359
360
void my_debug_put_break_here(void)
361
{
362
}
363
#endif
364
365
#ifdef _WIN32
366
367
368
/*
369
  my_parameter_handler
370
  
371
  Invalid parameter handler we will use instead of the one "baked"
372
  into the CRT.
373
*/
374
375
void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
376
                          const wchar_t * file, unsigned int line,
377
                          uintptr_t pReserved)
378
{
379
  __debugbreak();
380
}
381
382
383
#ifdef __MSVC_RUNTIME_CHECKS
384
#include <rtcapi.h>
385
386
/* Turn off runtime checks for 'handle_rtc_failure' */
387
#pragma runtime_checks("", off)
388
389
/*
390
  handle_rtc_failure
391
  Catch the RTC error and dump it to stderr
392
*/
393
394
int handle_rtc_failure(int err_type, const char *file, int line,
395
                       const char* module, const char *format, ...)
396
{
397
  va_list args;
398
  va_start(args, format);
399
  fprintf(stderr, "Error:");
400
  vfprintf(stderr, format, args);
401
  fprintf(stderr, " At %s:%d\n", file, line);
402
  va_end(args);
403
  (void) fflush(stderr);
404
  __debugbreak();
405
406
  return 0; /* Error is handled */
407
}
408
#pragma runtime_checks("", restore)
409
#endif
410
411
412
static void my_win_init(void)
413
{
414
  DBUG_ENTER("my_win_init");
415
416
#if defined(_MSC_VER)
417
  _set_invalid_parameter_handler(my_parameter_handler);
418
#endif
419
420
#ifdef __MSVC_RUNTIME_CHECKS
421
  /*
422
    Install handler to send RTC (Runtime Error Check) warnings
423
    to log file
424
  */
425
  _RTC_SetErrorFunc(handle_rtc_failure);
426
#endif
427
428
  _tzset();
429
430
  /* Disable automatic LF->CRLF translation. */
431
  FILE* stdf[]= {stdin, stdout, stderr};
432
  for (int i= 0; i < array_elements(stdf); i++)
433
  {
434
    int fd= fileno(stdf[i]);
435
    if (fd >= 0)
436
      (void) _setmode(fd, O_BINARY);
437
  }
438
  _set_fmode(O_BINARY);
439
  setup_codepages();
440
  DBUG_VOID_RETURN;
441
}
442
443
444
static my_bool win32_init_tcp_ip()
445
{
446
  WORD wVersionRequested = MAKEWORD( 2, 2 );
447
  WSADATA wsaData;
448
  if (WSAStartup(wVersionRequested, &wsaData))
449
  {
450
    fprintf(stderr, "WSAStartup() failed with error: %d\n", WSAGetLastError());
451
    return 1;
452
  }
453
  return(0);
454
}
455
#endif /* _WIN32 */
456
457
PSI_stage_info stage_waiting_for_table_level_lock=
458
{0, "Waiting for table level lock", 0};
459
460
#ifdef HAVE_PSI_INTERFACE
461
#if !defined(HAVE_PREAD) && !defined(_WIN32)
462
PSI_mutex_key key_my_file_info_mutex;
463
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
464
465
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
466
PSI_mutex_key key_LOCK_localtime_r;
467
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
468
469
PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
470
  key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock,
471
  key_LOCK_timer,
472
  key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
473
  key_THR_LOCK_lock, key_THR_LOCK_malloc,
474
  key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
475
  key_THR_LOCK_open, key_THR_LOCK_threads,
476
  key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap, key_LOCK_uuid_generator;
477
478
static PSI_mutex_info all_mysys_mutexes[]=
479
{
480
#if !defined(HAVE_PREAD) && !defined(_WIN32)
481
  { &key_my_file_info_mutex, "st_my_file_info:mutex", 0},
482
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
483
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
484
  { &key_LOCK_localtime_r, "LOCK_localtime_r", PSI_FLAG_GLOBAL},
485
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
486
  { &key_BITMAP_mutex, "BITMAP::mutex", 0},
487
  { &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0},
488
  { &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0},
489
  { &key_KEY_CACHE_cache_lock, "KEY_CACHE::cache_lock", 0},
490
  { &key_LOCK_timer, "LOCK_timer", PSI_FLAG_GLOBAL},
491
  { &key_my_thread_var_mutex, "my_thread_var::mutex", 0},
492
  { &key_THR_LOCK_charset, "THR_LOCK_charset", PSI_FLAG_GLOBAL},
493
  { &key_THR_LOCK_heap, "THR_LOCK_heap", PSI_FLAG_GLOBAL},
494
  { &key_THR_LOCK_lock, "THR_LOCK_lock", PSI_FLAG_GLOBAL},
495
  { &key_THR_LOCK_malloc, "THR_LOCK_malloc", PSI_FLAG_GLOBAL},
496
  { &key_THR_LOCK_mutex, "THR_LOCK::mutex", 0},
497
  { &key_THR_LOCK_myisam, "THR_LOCK_myisam", PSI_FLAG_GLOBAL},
498
  { &key_THR_LOCK_net, "THR_LOCK_net", PSI_FLAG_GLOBAL},
499
  { &key_THR_LOCK_open, "THR_LOCK_open", PSI_FLAG_GLOBAL},
500
  { &key_THR_LOCK_threads, "THR_LOCK_threads", PSI_FLAG_GLOBAL},
501
  { &key_TMPDIR_mutex, "TMPDIR_mutex", PSI_FLAG_GLOBAL},
502
  { &key_THR_LOCK_myisam_mmap, "THR_LOCK_myisam_mmap", PSI_FLAG_GLOBAL},
503
  { &key_LOCK_uuid_generator, "LOCK_uuid_generator", PSI_FLAG_GLOBAL }
504
};
505
506
PSI_cond_key key_COND_timer, key_IO_CACHE_SHARE_cond,
507
  key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
508
  key_THR_COND_threads, key_WT_RESOURCE_cond;
509
510
static PSI_cond_info all_mysys_conds[]=
511
{
512
  { &key_COND_timer, "COND_timer", PSI_FLAG_GLOBAL},
513
  { &key_IO_CACHE_SHARE_cond, "IO_CACHE_SHARE::cond", 0},
514
  { &key_IO_CACHE_SHARE_cond_writer, "IO_CACHE_SHARE::cond_writer", 0},
515
  { &key_my_thread_var_suspend, "my_thread_var::suspend", 0},
516
  { &key_THR_COND_threads, "THR_COND_threads", PSI_FLAG_GLOBAL},
517
  { &key_WT_RESOURCE_cond, "WT_RESOURCE::cond", 0}
518
};
519
520
PSI_rwlock_key key_SAFEHASH_mutex;
521
522
static PSI_rwlock_info all_mysys_rwlocks[]=
523
{
524
  { &key_SAFEHASH_mutex, "SAFE_HASH::mutex", 0}
525
};
526
527
PSI_thread_key key_thread_timer;
528
529
static PSI_thread_info all_mysys_threads[]=
530
{
531
  { &key_thread_timer, "statement_timer", PSI_FLAG_GLOBAL}
532
};
533
534
535
PSI_file_key key_file_charset, key_file_cnf;
536
537
static PSI_file_info all_mysys_files[]=
538
{
539
  { &key_file_charset, "charset", 0},
540
  { &key_file_cnf, "cnf", 0}
541
};
542
543
PSI_stage_info *all_mysys_stages[]=
544
{
545
  & stage_waiting_for_table_level_lock
546
};
547
548
void my_init_mysys_psi_keys()
549
0
{
550
0
  const char* category= "mysys";
551
0
  int count;
552
553
0
  count= sizeof(all_mysys_mutexes)/sizeof(all_mysys_mutexes[0]);
554
0
  mysql_mutex_register(category, all_mysys_mutexes, count);
555
556
0
  count= sizeof(all_mysys_conds)/sizeof(all_mysys_conds[0]);
557
0
  mysql_cond_register(category, all_mysys_conds, count);
558
559
0
  count= sizeof(all_mysys_rwlocks)/sizeof(all_mysys_rwlocks[0]);
560
0
  mysql_rwlock_register(category, all_mysys_rwlocks, count);
561
562
0
  count= sizeof(all_mysys_threads)/sizeof(all_mysys_threads[0]);
563
0
  mysql_thread_register(category, all_mysys_threads, count);
564
565
0
  count= sizeof(all_mysys_files)/sizeof(all_mysys_files[0]);
566
0
  mysql_file_register(category, all_mysys_files, count);
567
568
0
  count= array_elements(all_mysys_stages);
569
0
  mysql_stage_register(category, all_mysys_stages, count);
570
0
}
571
#endif /* HAVE_PSI_INTERFACE */
572