MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_init.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "mysys_priv.h"
17 #include "my_static.h"
18 #include "mysys_err.h"
19 #include <m_string.h>
20 #include <m_ctype.h>
21 #include <signal.h>
22 #include <mysql/psi/mysql_stage.h>
23 #ifdef __WIN__
24 #ifdef _MSC_VER
25 #include <locale.h>
26 #include <crtdbg.h>
27 /* WSAStartup needs winsock library*/
28 #pragma comment(lib, "ws2_32")
29 #endif
30 my_bool have_tcpip=0;
31 static void my_win_init(void);
32 static my_bool win32_init_tcp_ip();
33 #else
34 #define my_win_init()
35 #endif
36 
37 #define SCALE_SEC 100
38 #define SCALE_USEC 10000
39 
40 my_bool my_init_done= 0;
41 ulong my_thread_stack_size= 65536;
42 
43 static ulong atoi_octal(const char *str)
44 {
45  long int tmp;
46  while (*str && my_isspace(&my_charset_latin1, *str))
47  str++;
48  str2int(str,
49  (*str == '0' ? 8 : 10), /* Octalt or decimalt */
50  0, INT_MAX, &tmp);
51  return (ulong) tmp;
52 }
53 
54 MYSQL_FILE *mysql_stdin= NULL;
55 static MYSQL_FILE instrumented_stdin;
56 
57 
65 my_bool my_init(void)
66 {
67  char *str;
68 
69  if (my_init_done)
70  return 0;
71 
72  my_init_done= 1;
73 
74  my_umask= 0660; /* Default umask for new files */
75  my_umask_dir= 0700; /* Default umask for new directories */
76 
77  /* Default creation of new files */
78  if ((str= getenv("UMASK")) != 0)
79  my_umask= (int) (atoi_octal(str) | 0600);
80  /* Default creation of new dir's */
81  if ((str= getenv("UMASK_DIR")) != 0)
82  my_umask_dir= (int) (atoi_octal(str) | 0700);
83 
84  init_glob_errs();
85 
86  instrumented_stdin.m_file= stdin;
87  instrumented_stdin.m_psi= NULL; /* not yet instrumented */
88  mysql_stdin= & instrumented_stdin;
89 
90  if (my_thread_global_init())
91  return 1;
92 
93 #if defined(SAFE_MUTEX)
94  safe_mutex_global_init(); /* Must be called early */
95 #endif
96 
97 #if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
98  fastmutex_global_init(); /* Must be called early */
99 #endif
100 
101  /* $HOME is needed early to parse configuration files located in ~/ */
102  if ((home_dir= getenv("HOME")) != 0)
103  home_dir= intern_filename(home_dir_buff, home_dir);
104 
105  {
106  DBUG_ENTER("my_init");
107  DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
108  my_win_init();
109  DBUG_PRINT("exit", ("home: '%s'", home_dir));
110 #ifdef __WIN__
111  win32_init_tcp_ip();
112 #endif
113  DBUG_RETURN(0);
114  }
115 } /* my_init */
116 
117 
118  /* End my_sys */
119 
120 void my_end(int infoflag)
121 {
122  /*
123  this code is suboptimal to workaround a bug in
124  Sun CC: Sun C++ 5.6 2004/06/02 for x86, and should not be
125  optimized until this compiler is not in use anymore
126  */
127  FILE *info_file= DBUG_FILE;
128  my_bool print_info= (info_file != stderr);
129 
130  if (!my_init_done)
131  return;
132 
133  /*
134  We do not use DBUG_ENTER here, as after cleanup DBUG is no longer
135  operational, so we cannot use DBUG_RETURN.
136  */
137  DBUG_PRINT("info",("Shutting down: infoflag: %d print_info: %d",
138  infoflag, print_info));
139  if (!info_file)
140  {
141  info_file= stderr;
142  print_info= 0;
143  }
144 
145  if ((infoflag & MY_CHECK_ERROR) || print_info)
146 
147  { /* Test if some file is left open */
148  if (my_file_opened | my_stream_opened)
149  {
150  char ebuff[512];
151  my_snprintf(ebuff, sizeof(ebuff), EE(EE_OPEN_WARNING),
152  my_file_opened, my_stream_opened);
153  my_message_stderr(EE_OPEN_WARNING, ebuff, ME_BELL);
154  DBUG_PRINT("error", ("%s", ebuff));
155  my_print_open_files();
156  }
157  }
158  free_charsets();
159  my_error_unregister_all();
160  my_once_free();
161 
162  if ((infoflag & MY_GIVE_INFO) || print_info)
163  {
164 #ifdef HAVE_GETRUSAGE
165  struct rusage rus;
166 #ifdef HAVE_purify
167  /* Purify assumes that rus is uninitialized after getrusage call */
168  memset(&rus, 0, sizeof(rus));
169 #endif
170  if (!getrusage(RUSAGE_SELF, &rus))
171  fprintf(info_file,"\n\
172 User time %.2f, System time %.2f\n\
173 Maximum resident set size %ld, Integral resident set size %ld\n\
174 Non-physical pagefaults %ld, Physical pagefaults %ld, Swaps %ld\n\
175 Blocks in %ld out %ld, Messages in %ld out %ld, Signals %ld\n\
176 Voluntary context switches %ld, Involuntary context switches %ld\n",
177  (rus.ru_utime.tv_sec * SCALE_SEC +
178  rus.ru_utime.tv_usec / SCALE_USEC) / 100.0,
179  (rus.ru_stime.tv_sec * SCALE_SEC +
180  rus.ru_stime.tv_usec / SCALE_USEC) / 100.0,
181  rus.ru_maxrss, rus.ru_idrss,
182  rus.ru_minflt, rus.ru_majflt,
183  rus.ru_nswap, rus.ru_inblock, rus.ru_oublock,
184  rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
185  rus.ru_nvcsw, rus.ru_nivcsw);
186 #endif
187 #if defined(__WIN__) && defined(_MSC_VER)
188  _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
189  _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
190  _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
191  _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
192  _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
193  _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
194  _CrtCheckMemory();
195  _CrtDumpMemoryLeaks();
196 #endif
197  }
198 
199  if (!(infoflag & MY_DONT_FREE_DBUG))
200  {
201  DBUG_END(); /* Must be done before my_thread_end */
202  }
203 
204  my_thread_end();
205  my_thread_global_end();
206 #if defined(SAFE_MUTEX)
207  /*
208  Check on destroying of mutexes. A few may be left that will get cleaned
209  up by C++ destructors
210  */
211  safe_mutex_end((infoflag & (MY_GIVE_INFO | MY_CHECK_ERROR)) ? stderr :
212  (FILE *) 0);
213 #endif /* defined(SAFE_MUTEX) */
214 
215 #ifdef __WIN__
216  if (have_tcpip)
217  WSACleanup();
218 #endif /* __WIN__ */
219 
220  my_init_done=0;
221 } /* my_end */
222 
223 
224 #ifdef __WIN__
225 
226 
227 /*
228  my_parameter_handler
229 
230  Invalid parameter handler we will use instead of the one "baked"
231  into the CRT for MSC v8. This one just prints out what invalid
232  parameter was encountered. By providing this routine, routines like
233  lseek will return -1 when we expect them to instead of crash.
234 */
235 
236 void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
237  const wchar_t * file, unsigned int line,
238  uintptr_t pReserved)
239 {
240  DBUG_PRINT("my",("Expression: %s function: %s file: %s, line: %d",
241  expression, function, file, line));
242 }
243 
244 
245 #ifdef __MSVC_RUNTIME_CHECKS
246 #include <rtcapi.h>
247 
248 /* Turn off runtime checks for 'handle_rtc_failure' */
249 #pragma runtime_checks("", off)
250 
251 /*
252  handle_rtc_failure
253  Catch the RTC error and dump it to stderr
254 */
255 
256 int handle_rtc_failure(int err_type, const char *file, int line,
257  const char* module, const char *format, ...)
258 {
259  va_list args;
260  va_start(args, format);
261  fprintf(stderr, "Error:");
262  vfprintf(stderr, format, args);
263  fprintf(stderr, " At %s:%d\n", file, line);
264  va_end(args);
265  (void) fflush(stderr);
266 
267  return 0; /* Error is handled */
268 }
269 #pragma runtime_checks("", restore)
270 #endif
271 
272 #define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10)
273 #define MS 10000000
274 
275 static void win_init_time(void)
276 {
277  /* The following is used by time functions */
278  FILETIME ft;
279  LARGE_INTEGER li, t_cnt;
280 
281  DBUG_ASSERT(sizeof(LARGE_INTEGER) == sizeof(query_performance_frequency));
282 
283  if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0)
284  query_performance_frequency= 0;
285  else
286  {
287  GetSystemTimeAsFileTime(&ft);
288  li.LowPart= ft.dwLowDateTime;
289  li.HighPart= ft.dwHighDateTime;
290  query_performance_offset= li.QuadPart-OFFSET_TO_EPOC;
291  QueryPerformanceCounter(&t_cnt);
292  query_performance_offset-= (t_cnt.QuadPart /
293  query_performance_frequency * MS +
294  t_cnt.QuadPart %
295  query_performance_frequency * MS /
296  query_performance_frequency);
297  }
298 }
299 
300 
301 /*
302  Open HKEY_LOCAL_MACHINE\SOFTWARE\MySQL and set any strings found
303  there as environment variables
304 */
305 static void win_init_registry(void)
306 {
307  HKEY key_handle;
308 
309  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)"SOFTWARE\\MySQL",
310  0, KEY_READ, &key_handle) == ERROR_SUCCESS)
311  {
312  LONG ret;
313  DWORD index= 0;
314  DWORD type;
315  char key_name[256], key_data[1024];
316  DWORD key_name_len= sizeof(key_name) - 1;
317  DWORD key_data_len= sizeof(key_data) - 1;
318 
319  while ((ret= RegEnumValue(key_handle, index++,
320  key_name, &key_name_len,
321  NULL, &type, (LPBYTE)&key_data,
322  &key_data_len)) != ERROR_NO_MORE_ITEMS)
323  {
324  char env_string[sizeof(key_name) + sizeof(key_data) + 2];
325 
326  if (ret == ERROR_MORE_DATA)
327  {
328  /* Registry value larger than 'key_data', skip it */
329  DBUG_PRINT("error", ("Skipped registry value that was too large"));
330  }
331  else if (ret == ERROR_SUCCESS)
332  {
333  if (type == REG_SZ)
334  {
335  strxmov(env_string, key_name, "=", key_data, NullS);
336 
337  /* variable for putenv must be allocated ! */
338  putenv(strdup(env_string)) ;
339  }
340  }
341  else
342  {
343  /* Unhandled error, break out of loop */
344  break;
345  }
346 
347  key_name_len= sizeof(key_name) - 1;
348  key_data_len= sizeof(key_data) - 1;
349  }
350 
351  RegCloseKey(key_handle);
352  }
353 }
354 
355 
356 static void my_win_init(void)
357 {
358  DBUG_ENTER("my_win_init");
359 
360 #if defined(_MSC_VER)
361 #if _MSC_VER < 1300
362  /*
363  Clear the OS system variable TZ and avoid the 100% CPU usage
364  Only for old versions of Visual C++
365  */
366  _putenv("TZ=");
367 #endif
368 #if _MSC_VER >= 1400
369  /* this is required to make crt functions return -1 appropriately */
370  _set_invalid_parameter_handler(my_parameter_handler);
371 #endif
372 #endif
373 
374 #ifdef __MSVC_RUNTIME_CHECKS
375  /*
376  Install handler to send RTC (Runtime Error Check) warnings
377  to log file
378  */
379  _RTC_SetErrorFunc(handle_rtc_failure);
380 #endif
381 
382  _tzset();
383 
384  win_init_time();
385  win_init_registry();
386 
387  DBUG_VOID_RETURN;
388 }
389 
390 
391 /*------------------------------------------------------------------
392  Name: CheckForTcpip| Desc: checks if tcpip has been installed on system
393  According to Microsoft Developers documentation the first registry
394  entry should be enough to check if TCP/IP is installed, but as expected
395  this doesn't work on all Win32 machines :(
396 ------------------------------------------------------------------*/
397 
398 #define TCPIPKEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
399 #define WINSOCK2KEY "SYSTEM\\CurrentControlSet\\Services\\Winsock2\\Parameters"
400 #define WINSOCKKEY "SYSTEM\\CurrentControlSet\\Services\\Winsock\\Parameters"
401 
402 static my_bool win32_have_tcpip(void)
403 {
404  HKEY hTcpipRegKey;
405  if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, TCPIPKEY, 0, KEY_READ,
406  &hTcpipRegKey) != ERROR_SUCCESS)
407  {
408  if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCK2KEY, 0, KEY_READ,
409  &hTcpipRegKey) != ERROR_SUCCESS)
410  {
411  if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCKKEY, 0, KEY_READ,
412  &hTcpipRegKey) != ERROR_SUCCESS)
413  if (!getenv("HAVE_TCPIP") || have_tcpip) /* Provide a workaround */
414  return (FALSE);
415  }
416  }
417  RegCloseKey ( hTcpipRegKey);
418  return (TRUE);
419 }
420 
421 
422 static my_bool win32_init_tcp_ip()
423 {
424  if (win32_have_tcpip())
425  {
426  WORD wVersionRequested = MAKEWORD( 2, 2 );
427  WSADATA wsaData;
428  /* Be a good citizen: maybe another lib has already initialised
429  sockets, so dont clobber them unless necessary */
430  if (WSAStartup( wVersionRequested, &wsaData ))
431  {
432  /* Load failed, maybe because of previously loaded
433  incompatible version; try again */
434  WSACleanup( );
435  if (!WSAStartup( wVersionRequested, &wsaData ))
436  have_tcpip=1;
437  }
438  else
439  {
440  if (wsaData.wVersion != wVersionRequested)
441  {
442  /* Version is no good, try again */
443  WSACleanup( );
444  if (!WSAStartup( wVersionRequested, &wsaData ))
445  have_tcpip=1;
446  }
447  else
448  have_tcpip=1;
449  }
450  }
451  return(0);
452 }
453 #endif /* __WIN__ */
454 
455 PSI_stage_info stage_waiting_for_table_level_lock=
456 {0, "Waiting for table level lock", 0};
457 
458 #ifdef HAVE_PSI_INTERFACE
459 
460 #if !defined(HAVE_PREAD) && !defined(_WIN32)
461 PSI_mutex_key key_my_file_info_mutex;
462 #endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
463 
464 #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
465 PSI_mutex_key key_LOCK_localtime_r;
466 #endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
467 
468 PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
469  key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
470  key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
471  key_THR_LOCK_lock, key_THR_LOCK_malloc,
472  key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
473  key_THR_LOCK_open, key_THR_LOCK_threads,
474  key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap;
475 
476 static PSI_mutex_info all_mysys_mutexes[]=
477 {
478 #if !defined(HAVE_PREAD) && !defined(_WIN32)
479  { &key_my_file_info_mutex, "st_my_file_info:mutex", 0},
480 #endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
481 #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
482  { &key_LOCK_localtime_r, "LOCK_localtime_r", PSI_FLAG_GLOBAL},
483 #endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
484  { &key_BITMAP_mutex, "BITMAP::mutex", 0},
485  { &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0},
486  { &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0},
487  { &key_KEY_CACHE_cache_lock, "KEY_CACHE::cache_lock", 0},
488  { &key_LOCK_alarm, "LOCK_alarm", PSI_FLAG_GLOBAL},
489  { &key_my_thread_var_mutex, "my_thread_var::mutex", 0},
490  { &key_THR_LOCK_charset, "THR_LOCK_charset", PSI_FLAG_GLOBAL},
491  { &key_THR_LOCK_heap, "THR_LOCK_heap", PSI_FLAG_GLOBAL},
492  { &key_THR_LOCK_lock, "THR_LOCK_lock", PSI_FLAG_GLOBAL},
493  { &key_THR_LOCK_malloc, "THR_LOCK_malloc", PSI_FLAG_GLOBAL},
494  { &key_THR_LOCK_mutex, "THR_LOCK::mutex", 0},
495  { &key_THR_LOCK_myisam, "THR_LOCK_myisam", PSI_FLAG_GLOBAL},
496  { &key_THR_LOCK_net, "THR_LOCK_net", PSI_FLAG_GLOBAL},
497  { &key_THR_LOCK_open, "THR_LOCK_open", PSI_FLAG_GLOBAL},
498  { &key_THR_LOCK_threads, "THR_LOCK_threads", PSI_FLAG_GLOBAL},
499  { &key_TMPDIR_mutex, "TMPDIR_mutex", PSI_FLAG_GLOBAL},
500  { &key_THR_LOCK_myisam_mmap, "THR_LOCK_myisam_mmap", PSI_FLAG_GLOBAL}
501 };
502 
503 PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond,
504  key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
505  key_THR_COND_threads;
506 
507 static PSI_cond_info all_mysys_conds[]=
508 {
509  { &key_COND_alarm, "COND_alarm", PSI_FLAG_GLOBAL},
510  { &key_IO_CACHE_SHARE_cond, "IO_CACHE_SHARE::cond", 0},
511  { &key_IO_CACHE_SHARE_cond_writer, "IO_CACHE_SHARE::cond_writer", 0},
512  { &key_my_thread_var_suspend, "my_thread_var::suspend", 0},
513  { &key_THR_COND_threads, "THR_COND_threads", 0}
514 };
515 
516 #ifdef USE_ALARM_THREAD
517 PSI_thread_key key_thread_alarm;
518 
519 static PSI_thread_info all_mysys_threads[]=
520 {
521  { &key_thread_alarm, "alarm", PSI_FLAG_GLOBAL}
522 };
523 #endif /* USE_ALARM_THREAD */
524 
525 #ifdef HUGETLB_USE_PROC_MEMINFO
526 PSI_file_key key_file_proc_meminfo;
527 #endif /* HUGETLB_USE_PROC_MEMINFO */
528 PSI_file_key key_file_charset, key_file_cnf;
529 
530 static PSI_file_info all_mysys_files[]=
531 {
532 #ifdef HUGETLB_USE_PROC_MEMINFO
533  { &key_file_proc_meminfo, "proc_meminfo", 0},
534 #endif /* HUGETLB_USE_PROC_MEMINFO */
535  { &key_file_charset, "charset", 0},
536  { &key_file_cnf, "cnf", 0}
537 };
538 
539 PSI_stage_info *all_mysys_stages[]=
540 {
541  & stage_waiting_for_table_level_lock
542 };
543 
544 void my_init_mysys_psi_keys()
545 {
546  const char* category= "mysys";
547  int count;
548 
549  count= sizeof(all_mysys_mutexes)/sizeof(all_mysys_mutexes[0]);
550  mysql_mutex_register(category, all_mysys_mutexes, count);
551 
552  count= sizeof(all_mysys_conds)/sizeof(all_mysys_conds[0]);
553  mysql_cond_register(category, all_mysys_conds, count);
554 
555 #ifdef USE_ALARM_THREAD
556  count= sizeof(all_mysys_threads)/sizeof(all_mysys_threads[0]);
557  mysql_thread_register(category, all_mysys_threads, count);
558 #endif /* USE_ALARM_THREAD */
559 
560  count= sizeof(all_mysys_files)/sizeof(all_mysys_files[0]);
561  mysql_file_register(category, all_mysys_files, count);
562 
563  count= array_elements(all_mysys_stages);
564  mysql_stage_register(category, all_mysys_stages, count);
565 }
566 #endif /* HAVE_PSI_INTERFACE */
567