Many files:

  Exit all threads created by innoDB at shutdown
parent 3317cfdc
...@@ -301,6 +301,13 @@ os_aio( ...@@ -301,6 +301,13 @@ os_aio(
are ignored */ are ignored */
void* message2); void* message2);
/**************************************************************************** /****************************************************************************
Wakes up all async i/o threads so that they know to exit themselves in
shutdown. */
void
os_aio_wake_all_threads_at_shutdown(void);
/*=====================================*/
/****************************************************************************
Waits until there are no pending writes in os_aio_write_array. There can Waits until there are no pending writes in os_aio_write_array. There can
be other, synchronous, pending writes. */ be other, synchronous, pending writes. */
......
...@@ -38,6 +38,13 @@ typedef os_mutex_str_t* os_mutex_t; ...@@ -38,6 +38,13 @@ typedef os_mutex_str_t* os_mutex_t;
#define OS_SYNC_TIME_EXCEEDED 1 #define OS_SYNC_TIME_EXCEEDED 1
/* Mutex protecting the thread count */
extern os_mutex_t os_thread_count_mutex;
/* This is incremented by 1 in os_thread_create and decremented by 1 in
os_thread_exit */
extern ulint os_thread_count;
/************************************************************* /*************************************************************
Creates an event semaphore, i.e., a semaphore which may Creates an event semaphore, i.e., a semaphore which may
just have two states: signaled and nonsignaled. just have two states: signaled and nonsignaled.
...@@ -85,7 +92,10 @@ os_event_free( ...@@ -85,7 +92,10 @@ os_event_free(
/*==========*/ /*==========*/
os_event_t event); /* in: event to free */ os_event_t event); /* in: event to free */
/************************************************************** /**************************************************************
Waits for an event object until it is in the signaled state. */ Waits for an event object until it is in the signaled state. If
srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
waiting thread when the event becomes signaled (or immediately if the
event is already in the signaled state). */
void void
os_event_wait( os_event_wait(
......
...@@ -11,6 +11,7 @@ Created 9/8/1995 Heikki Tuuri ...@@ -11,6 +11,7 @@ Created 9/8/1995 Heikki Tuuri
#define os0thread_h #define os0thread_h
#include "univ.i" #include "univ.i"
#include "os0sync.h"
/* Maximum number of threads which can be created in the program; /* Maximum number of threads which can be created in the program;
this is also the size of the wait slot array for MySQL threads which this is also the size of the wait slot array for MySQL threads which
...@@ -41,7 +42,6 @@ typedef os_thread_t os_thread_id_t; /* In Unix we use the thread ...@@ -41,7 +42,6 @@ typedef os_thread_t os_thread_id_t; /* In Unix we use the thread
the thread */ the thread */
#endif #endif
/* Define a function pointer type to use in a typecast */ /* Define a function pointer type to use in a typecast */
typedef void* (*os_posix_f_t) (void*); typedef void* (*os_posix_f_t) (void*);
...@@ -83,12 +83,13 @@ os_thread_create( ...@@ -83,12 +83,13 @@ os_thread_create(
os_thread_id_t* thread_id); /* out: id of the created os_thread_id_t* thread_id); /* out: id of the created
thread */ thread */
/********************************************************************* /*********************************************************************
A thread calling this function ends its execution. */ Exits the current thread. */
void void
os_thread_exit( os_thread_exit(
/*===========*/ /*===========*/
ulint code); /* in: exit code */ void* exit_value); /* in: exit value; in Windows this void*
is cast as a DWORD */
/********************************************************************* /*********************************************************************
Returns the thread identifier of current thread. */ Returns the thread identifier of current thread. */
...@@ -144,7 +145,6 @@ ulint ...@@ -144,7 +145,6 @@ ulint
os_thread_get_last_error(void); os_thread_get_last_error(void);
/*==========================*/ /*==========================*/
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "os0thread.ic" #include "os0thread.ic"
#endif #endif
......
...@@ -375,7 +375,7 @@ log_pad_current_log_block(void) ...@@ -375,7 +375,7 @@ log_pad_current_log_block(void)
log_close(); log_close();
log_release(); log_release();
ut_a((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) ut_ad((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE)
== LOG_BLOCK_HDR_SIZE); == LOG_BLOCK_HDR_SIZE);
} }
...@@ -998,6 +998,8 @@ log_group_file_header_flush( ...@@ -998,6 +998,8 @@ log_group_file_header_flush(
{ {
byte* buf; byte* buf;
ulint dest_offset; ulint dest_offset;
UT_NOT_USED(type);
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
...@@ -1068,8 +1070,8 @@ log_group_write_buf( ...@@ -1068,8 +1070,8 @@ log_group_write_buf(
ulint i; ulint i;
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
if (new_data_offset == 0) { if (new_data_offset == 0) {
write_header = TRUE; write_header = TRUE;
...@@ -2901,10 +2903,9 @@ logs_empty_and_mark_files_at_shutdown(void) ...@@ -2901,10 +2903,9 @@ logs_empty_and_mark_files_at_shutdown(void)
dulint lsn; dulint lsn;
ulint arch_log_no; ulint arch_log_no;
if (srv_print_verbose_log) if (srv_print_verbose_log) {
{ ut_print_timestamp(stderr);
ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Starting shutdown...\n");
fprintf(stderr, " InnoDB: Starting shutdown...\n");
} }
/* Wait until the master thread and all other operations are idle: our /* Wait until the master thread and all other operations are idle: our
algorithm only works if the server is idle at shutdown */ algorithm only works if the server is idle at shutdown */
...@@ -3006,15 +3007,17 @@ loop: ...@@ -3006,15 +3007,17 @@ loop:
goto loop; goto loop;
} }
/* Make some checks that the server really is quiet */
ut_a(buf_all_freed());
ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
fil_write_flushed_lsn_to_data_files(lsn, arch_log_no); fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
fil_flush_file_spaces(FIL_TABLESPACE); fil_flush_file_spaces(FIL_TABLESPACE);
if (srv_print_verbose_log) /* Make some checks that the server really is quiet */
{ ut_a(buf_all_freed());
ut_print_timestamp(stderr); ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
fprintf(stderr, " InnoDB: Shutdown completed\n");
}
} }
/********************************************************** /**********************************************************
......
...@@ -1295,7 +1295,6 @@ os_aio_array_create( ...@@ -1295,7 +1295,6 @@ os_aio_array_create(
#endif #endif
ut_a(n > 0); ut_a(n > 0);
ut_a(n_segments > 0); ut_a(n_segments > 0);
ut_a(n % n_segments == 0);
array = ut_malloc(sizeof(os_aio_array_t)); array = ut_malloc(sizeof(os_aio_array_t));
...@@ -1404,6 +1403,50 @@ os_aio_init( ...@@ -1404,6 +1403,50 @@ os_aio_init(
pthread_sigmask(SIG_BLOCK, &sigset, NULL); */ pthread_sigmask(SIG_BLOCK, &sigset, NULL); */
#endif #endif
} }
#ifdef WIN_ASYNC_IO
/****************************************************************************
Wakes up all async i/o threads in the array in Windows async i/o at
shutdown. */
static
void
os_aio_array_wake_win_aio_at_shutdown(
/*==================================*/
os_aio_array_t* array) /* in: aio array */
{
ulint i;
for (i = 0; i < array->n_slots; i++) {
os_event_set(*(array->events + i));
}
}
#endif
/****************************************************************************
Wakes up all async i/o threads so that they know to exit themselves in
shutdown. */
void
os_aio_wake_all_threads_at_shutdown(void)
/*=====================================*/
{
ulint i;
#ifdef WIN_ASYNC_IO
/* This code wakes up all ai/o threads in Windows native aio */
os_aio_array_wake_win_aio_at_shutdown(os_aio_read_array);
os_aio_array_wake_win_aio_at_shutdown(os_aio_write_array);
os_aio_array_wake_win_aio_at_shutdown(os_aio_ibuf_array);
os_aio_array_wake_win_aio_at_shutdown(os_aio_log_array);
#endif
/* This loop wakes up all simulated ai/o threads */
for (i = 0; i < os_aio_n_segments; i++) {
os_event_set(os_aio_segment_wait_events[i]);
}
}
/**************************************************************************** /****************************************************************************
Waits until there are no pending writes in os_aio_write_array. There can Waits until there are no pending writes in os_aio_write_array. There can
......
...@@ -17,6 +17,7 @@ Created 9/6/1995 Heikki Tuuri ...@@ -17,6 +17,7 @@ Created 9/6/1995 Heikki Tuuri
#endif #endif
#include "ut0mem.h" #include "ut0mem.h"
#include "srv0start.h"
/* Type definition for an operating system mutex struct */ /* Type definition for an operating system mutex struct */
struct os_mutex_struct{ struct os_mutex_struct{
...@@ -26,9 +27,16 @@ struct os_mutex_struct{ ...@@ -26,9 +27,16 @@ struct os_mutex_struct{
recursively lock the mutex: we recursively lock the mutex: we
do not assume that the OS mutex do not assume that the OS mutex
supports recursive locking, though supports recursive locking, though
NT seems to do that */ NT seems to do that */
}; };
/* Mutex protecting the thread count */
os_mutex_t os_thread_count_mutex;
/* This is incremented by 1 in os_thread_create and decremented by 1 in
os_thread_exit */
ulint os_thread_count = 0;
/************************************************************* /*************************************************************
Creates an event semaphore, i.e., a semaphore which may Creates an event semaphore, i.e., a semaphore which may
just have two states: signaled and nonsignaled. just have two states: signaled and nonsignaled.
...@@ -190,7 +198,10 @@ os_event_free( ...@@ -190,7 +198,10 @@ os_event_free(
} }
/************************************************************** /**************************************************************
Waits for an event object until it is in the signaled state. */ Waits for an event object until it is in the signaled state. If
srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
waiting thread when the event becomes signaled (or immediately if the
event is already in the signaled state). */
void void
os_event_wait( os_event_wait(
...@@ -206,12 +217,20 @@ os_event_wait( ...@@ -206,12 +217,20 @@ os_event_wait(
err = WaitForSingleObject(event, INFINITE); err = WaitForSingleObject(event, INFINITE);
ut_a(err == WAIT_OBJECT_0); ut_a(err == WAIT_OBJECT_0);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
}
#else #else
os_fast_mutex_lock(&(event->os_mutex)); os_fast_mutex_lock(&(event->os_mutex));
loop: loop:
if (event->is_set == TRUE) { if (event->is_set == TRUE) {
os_fast_mutex_unlock(&(event->os_mutex)); os_fast_mutex_unlock(&(event->os_mutex));
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
}
/* Ok, we may return */ /* Ok, we may return */
return; return;
...@@ -299,6 +318,10 @@ os_event_wait_multiple( ...@@ -299,6 +318,10 @@ os_event_wait_multiple(
ut_a(index >= WAIT_OBJECT_0); ut_a(index >= WAIT_OBJECT_0);
ut_a(index < WAIT_OBJECT_0 + n); ut_a(index < WAIT_OBJECT_0 + n);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
}
return(index - WAIT_OBJECT_0); return(index - WAIT_OBJECT_0);
#else #else
ut_a(n == 0); ut_a(n == 0);
......
/****************************************************** /******************************************************
The interface to the operating system The interface to the operating system thread control primitives
process and thread control primitives
(c) 1995 Innobase Oy (c) 1995 Innobase Oy
...@@ -102,6 +101,10 @@ os_thread_create( ...@@ -102,6 +101,10 @@ os_thread_create(
os_thread_t thread; os_thread_t thread;
ulint win_thread_id; ulint win_thread_id;
os_mutex_enter(os_thread_count_mutex);
os_thread_count++;
os_mutex_exit(os_thread_count_mutex);
thread = CreateThread(NULL, /* no security attributes */ thread = CreateThread(NULL, /* no security attributes */
0, /* default size stack */ 0, /* default size stack */
(LPTHREAD_START_ROUTINE)start_f, (LPTHREAD_START_ROUTINE)start_f,
...@@ -144,6 +147,9 @@ os_thread_create( ...@@ -144,6 +147,9 @@ os_thread_create(
exit(1); exit(1);
} }
#endif #endif
os_mutex_enter(os_thread_count_mutex);
os_thread_count++;
os_mutex_exit(os_thread_count_mutex);
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
ret = pthread_create(&pthread, pthread_attr_default, start_f, arg); ret = pthread_create(&pthread, pthread_attr_default, start_f, arg);
...@@ -170,6 +176,26 @@ os_thread_create( ...@@ -170,6 +176,26 @@ os_thread_create(
#endif #endif
} }
/*********************************************************************
Exits the current thread. */
void
os_thread_exit(
/*===========*/
void* exit_value) /* in: exit value; in Windows this void*
is cast as a DWORD */
{
os_mutex_enter(os_thread_count_mutex);
os_thread_count--;
os_mutex_exit(os_thread_count_mutex);
#ifdef __WIN__
ExitThread((DWORD)exit_value);
#else
pthread_exit(exit_value);
#endif
}
/********************************************************************* /*********************************************************************
Returns handle to the current thread. */ Returns handle to the current thread. */
......
...@@ -1702,6 +1702,8 @@ void ...@@ -1702,6 +1702,8 @@ void
srv_general_init(void) srv_general_init(void)
/*==================*/ /*==================*/
{ {
os_thread_count_mutex = os_mutex_create(NULL);
sync_init(); sync_init();
mem_init(srv_mem_pool_size); mem_init(srv_mem_pool_size);
thr_local_init(); thr_local_init();
...@@ -1720,6 +1722,8 @@ srv_general_free(void) ...@@ -1720,6 +1722,8 @@ srv_general_free(void)
/*==================*/ /*==================*/
{ {
sync_close(); sync_close();
os_mutex_free(os_thread_count_mutex);
} }
#endif /* __NETWARE__ */ #endif /* __NETWARE__ */
...@@ -2700,6 +2704,8 @@ loop: ...@@ -2700,6 +2704,8 @@ loop:
srv_error_monitor_active = FALSE; srv_error_monitor_active = FALSE;
os_thread_exit(NULL);
#ifndef __WIN__ #ifndef __WIN__
return(NULL); return(NULL);
#else #else
...@@ -3139,6 +3145,13 @@ suspend_thread: ...@@ -3139,6 +3145,13 @@ suspend_thread:
os_event_wait(event); os_event_wait(event);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
/* This is only extra safety, the thread should exit
already when the event wait ends */
os_thread_exit(NULL);
}
/* When there is user activity, InnoDB will set the event and the main /* When there is user activity, InnoDB will set the event and the main
thread goes back to loop: */ thread goes back to loop: */
......
...@@ -1470,6 +1470,8 @@ innobase_shutdown_for_mysql(void) ...@@ -1470,6 +1470,8 @@ innobase_shutdown_for_mysql(void)
/*=============================*/ /*=============================*/
/* out: DB_SUCCESS or error code */ /* out: DB_SUCCESS or error code */
{ {
ulint i;
if (!srv_was_started) { if (!srv_was_started) {
if (srv_is_being_started) { if (srv_is_being_started) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -1494,6 +1496,58 @@ innobase_shutdown_for_mysql(void) ...@@ -1494,6 +1496,58 @@ innobase_shutdown_for_mysql(void)
srv_conc_n_threads); srv_conc_n_threads);
} }
/* Now we will exit all threads InnoDB created */
srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS;
/* All threads end up waiting for certain events. Put those events
to the signaled state. Then the threads will exit themselves in
os_thread_event_wait(). */
for (i = 0; i < 1000; i++) {
/* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM
HERE OR EARLIER */
/* 1. Let the lock timeout thread exit */
os_event_set(srv_lock_timeout_thread_event);
/* 2. srv error monitor thread exits automatically, no need
to do anything here */
/* 3. We wake the master thread so that it exits */
srv_wake_master_thread();
/* 4. Exit the i/o threads */
os_aio_wake_all_threads_at_shutdown();
os_mutex_enter(os_thread_count_mutex);
if (os_thread_count == 0) {
/* All the threads have exited or are just exiting;
NOTE that the threads may not have completed their
exit yet. Should we use pthread_join() to make sure
they have exited? Now we just sleep 0.1 seconds and
hope that is enough! */
os_mutex_exit(os_thread_count_mutex);
os_thread_sleep(100000);
break;
}
os_mutex_exit(os_thread_count_mutex);
os_thread_sleep(100000);
}
if (i == 1000) {
fprintf(stderr,
"InnoDB: Warning: %lu threads created by InnoDB had not exited at shutdown!\n",
os_thread_count);
}
#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) #if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
/* /*
TODO: Fix this temporary solution TODO: Fix this temporary solution
...@@ -1518,6 +1572,10 @@ innobase_shutdown_for_mysql(void) ...@@ -1518,6 +1572,10 @@ innobase_shutdown_for_mysql(void)
/* NetWare requires this free */ /* NetWare requires this free */
ut_free_all_mem(); ut_free_all_mem();
#endif #endif
if (srv_print_verbose_log) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Shutdown completed\n");
}
return((int) DB_SUCCESS); return((int) DB_SUCCESS);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment