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