mariadb/os/os0thread.c
calvin a0385e8a98 branches/innodb+: Merge revisions 6238:6293 from branches/plugin-1.1
which was cloned from branches/zip revision 6237 as branches/plugin-2.0,
in order to work with MySQL 5.5.

Skip revision 6240: update the version number to 2.0.0

  ------------------------------------------------------------------------
  r6290 | calvin | 2009-12-10 02:26:45 -0600 (Thu, 10 Dec 2009) | 26 lines

  branches/plugin-2.0: merge of r2877 from MySQL

  This is r2877 in mysql-next-mr tree, backported from 6.0.
  -------------------------------------------------------------
  Bug#24509 - 2048 file descriptor limit on windows needs increasing, also
  WL#3049 - improved Windows I/O

  The patch replaces the use of the POSIX I/O interfaces in mysys on Windows with
  the Win32 API calls (CreateFile, WriteFile, etc). The Windows HANDLE for the open
  file is stored in the my_file_info struct, along with a flag for append mode
  because the Windows API does not support opening files in append mode in all cases)
  The default max open files has been increased to 16384 and can be increased further
  by setting --max-open-files=<value> during the server start.

  Another major change in this patch that almost all Windows specific file IO code
  has been moved to a new file my_winfile.c, greatly reducing the amount of code
  in #ifdef blocks within mysys, thus improving readability.

  Minor enhancements:
  - my_(f)stat() is changed to use __stati64 structure with 64 file size
  and timestamps. It will return correct file size now (C runtime implementation
  used to report outdated information)
  - my_lock on Windows is prepared to handle additional timeout parameter
  - after review : changed __WIN__ to _WIN32 in the new and changed code.
  ------------------------------------------------------------------------
  r6291 | calvin | 2009-12-10 02:31:27 -0600 (Thu, 10 Dec 2009) | 14 lines

  branches/plugin-2.0: merge of r2887.3.31 from MySQL

  This is r2887.3.31 in mysql-next-mr tree, backported from 6.0.

  Backport of:
  ----------------------------------------------------------
  revno: 2630.22.8
  committer: Konstantin Osipov <konstantin@mysql.com>
  branch nick: mysql-6.0-runtime
  timestamp: Sun 2008-08-10 18:49:52 +0400
  message:
  Get rid of typedef struct for the most commonly used types:
  TABLE, TABLE_SHARE, LEX. This simplifies use of tags
  and forward declarations.
  ------------------------------------------------------------------------
  r6292 | calvin | 2009-12-10 02:40:55 -0600 (Thu, 10 Dec 2009) | 41 lines

  branches/plugin-2.0: merge of r2936 from MySQL

  This is r2936 in mysql-next-mr tree, backported from 6.0.

  Backport of:
  -------------------------------------------------------------
  revno: 2877
  committer: Davi Arnaut <Davi.Arnaut@Sun.COM>
  branch nick: 35164-6.0
  timestamp: Wed 2008-10-15 19:53:18 -0300
  message:
  Bug#35164: Large number of invalid pthread_attr_setschedparam calls
  Bug#37536: Thread scheduling causes performance degradation at low thread count
  Bug#12702: Long queries take 100% of CPU and freeze other applications under Windows

  The problem is that although having threads with different priorities
  yields marginal improvements [1] in some platforms [2], relying on some
  statically defined priorities (QUERY_PRIOR and WAIT_PRIOR) to play well
  (or to work at all) with different scheduling practices and disciplines
  is, at best, a shot in the dark as the meaning of priority values may
  change depending on the scheduling policy set for the process.

  Another problem is that increasing priorities can hurt other concurrent
  (running on the same hardware) applications (such as AMP) by causing
  starvation problems as MySQL threads will successively preempt lower
  priority processes. This can be evidenced by Bug#12702.

  The solution is to not change the threads priorities and rely on the
  system scheduler to perform its job. This also enables a system admin
  to increase or decrease the scheduling priority of the MySQL process,
  if intended.

  Furthermore, the internal wrappers and code for changing the priority
  of threads is being removed as they are now unused and ancient.

  1. Due to unintentional side effects. On Solaris this could artificially
  help benchmarks as calling the priority changing syscall millions of
  times is more beneficial than the actual setting of the priority.

  2. Where it actually works. It has never worked on Linux as the default
  scheduling policy SCHED_OTHER only accepts the static priority 0.
  ------------------------------------------------------------------------
  r6293 | calvin | 2009-12-10 02:45:27 -0600 (Thu, 10 Dec 2009) | 13 lines

  branches/plugin-2.0: merge of r2938 from MySQL

  This is r2938 in mysql-next-mr tree, backported from 6.0.

  Backport of:
  ----------------------------------------------------------------------
  ChangeSet@1.2571, 2008-04-08 12:30:06+02:00, vvaintroub@wva. +122 -0
  Bug#32082 : definition of VOID in my_global.h conflicts with Windows
  SDK headers

  VOID macro is now removed. Its usage is replaced with void cast.
  In some cases, where cast does not make much sense (pthread_*, printf,
  hash_delete, my_seek), cast is ommited.
  ------------------------------------------------------------------------
2010-03-12 22:06:55 +00:00

361 lines
8.3 KiB
C

/*****************************************************************************
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*****************************************************************************/
/**************************************************//**
@file os/os0thread.c
The interface to the operating system thread control primitives
Created 9/8/1995 Heikki Tuuri
*******************************************************/
#include "os0thread.h"
#ifdef UNIV_NONINL
#include "os0thread.ic"
#endif
#ifdef __WIN__
#include <windows.h>
#endif
#ifndef UNIV_HOTBACKUP
#include "srv0srv.h"
#include "os0sync.h"
/***************************************************************//**
Compares two thread ids for equality.
@return TRUE if equal */
UNIV_INTERN
ibool
os_thread_eq(
/*=========*/
os_thread_id_t a, /*!< in: OS thread or thread id */
os_thread_id_t b) /*!< in: OS thread or thread id */
{
#ifdef __WIN__
if (a == b) {
return(TRUE);
}
return(FALSE);
#else
if (pthread_equal(a, b)) {
return(TRUE);
}
return(FALSE);
#endif
}
/****************************************************************//**
Converts an OS thread id to a ulint. It is NOT guaranteed that the ulint is
unique for the thread though!
@return thread identifier as a number */
UNIV_INTERN
ulint
os_thread_pf(
/*=========*/
os_thread_id_t a) /*!< in: OS thread identifier */
{
#ifdef UNIV_HPUX10
/* In HP-UX-10.20 a pthread_t is a struct of 3 fields: field1, field2,
field3. We do not know if field1 determines the thread uniquely. */
return((ulint)(a.field1));
#else
return((ulint)a);
#endif
}
/*****************************************************************//**
Returns the thread identifier of current thread. Currently the thread
identifier in Unix is the thread handle itself. Note that in HP-UX
pthread_t is a struct of 3 fields.
@return current thread identifier */
UNIV_INTERN
os_thread_id_t
os_thread_get_curr_id(void)
/*=======================*/
{
#ifdef __WIN__
return(GetCurrentThreadId());
#else
return(pthread_self());
#endif
}
/****************************************************************//**
Creates a new thread of execution. The execution starts from
the function given. The start function takes a void* parameter
and returns an ulint.
@return handle to the thread */
UNIV_INTERN
os_thread_t
os_thread_create(
/*=============*/
#ifndef __WIN__
os_posix_f_t start_f,
#else
ulint (*start_f)(void*), /*!< in: pointer to function
from which to start */
#endif
void* arg, /*!< in: argument to start
function */
os_thread_id_t* thread_id) /*!< out: id of the created
thread, or NULL */
{
#ifdef __WIN__
os_thread_t thread;
DWORD win_thread_id;
os_mutex_enter(os_sync_mutex);
os_thread_count++;
os_mutex_exit(os_sync_mutex);
thread = CreateThread(NULL, /* no security attributes */
0, /* default size stack */
(LPTHREAD_START_ROUTINE)start_f,
arg,
0, /* thread runs immediately */
&win_thread_id);
if (thread_id) {
*thread_id = win_thread_id;
}
return(thread);
#else
int ret;
os_thread_t pthread;
pthread_attr_t attr;
#ifndef UNIV_HPUX10
pthread_attr_init(&attr);
#endif
#ifdef UNIV_AIX
/* We must make sure a thread stack is at least 32 kB, otherwise
InnoDB might crash; we do not know if the default stack size on
AIX is always big enough. An empirical test on AIX-4.3 suggested
the size was 96 kB, though. */
ret = pthread_attr_setstacksize(&attr,
(size_t)(PTHREAD_STACK_MIN
+ 32 * 1024));
if (ret) {
fprintf(stderr,
"InnoDB: Error: pthread_attr_setstacksize"
" returned %d\n", ret);
exit(1);
}
#endif
#ifdef __NETWARE__
ret = pthread_attr_setstacksize(&attr,
(size_t) NW_THD_STACKSIZE);
if (ret) {
fprintf(stderr,
"InnoDB: Error: pthread_attr_setstacksize"
" returned %d\n", ret);
exit(1);
}
#endif
os_mutex_enter(os_sync_mutex);
os_thread_count++;
os_mutex_exit(os_sync_mutex);
#ifdef UNIV_HPUX10
ret = pthread_create(&pthread, pthread_attr_default, start_f, arg);
#else
ret = pthread_create(&pthread, &attr, start_f, arg);
#endif
if (ret) {
fprintf(stderr,
"InnoDB: Error: pthread_create returned %d\n", ret);
exit(1);
}
#ifndef UNIV_HPUX10
pthread_attr_destroy(&attr);
#endif
if (thread_id) {
*thread_id = pthread;
}
return(pthread);
#endif
}
/*****************************************************************//**
Exits the current thread. */
UNIV_INTERN
void
os_thread_exit(
/*===========*/
void* exit_value) /*!< in: exit value; in Windows this void*
is cast as a DWORD */
{
#ifdef UNIV_DEBUG_THREAD_CREATION
fprintf(stderr, "Thread exits, id %lu\n",
os_thread_pf(os_thread_get_curr_id()));
#endif
os_mutex_enter(os_sync_mutex);
os_thread_count--;
os_mutex_exit(os_sync_mutex);
#ifdef __WIN__
ExitThread((DWORD)exit_value);
#else
pthread_detach(pthread_self());
pthread_exit(exit_value);
#endif
}
/*****************************************************************//**
Returns handle to the current thread.
@return current thread handle */
UNIV_INTERN
os_thread_t
os_thread_get_curr(void)
/*====================*/
{
#ifdef __WIN__
return(GetCurrentThread());
#else
return(pthread_self());
#endif
}
/*****************************************************************//**
Advises the os to give up remainder of the thread's time slice. */
UNIV_INTERN
void
os_thread_yield(void)
/*=================*/
{
#if defined(__WIN__)
Sleep(0);
#elif (defined(HAVE_SCHED_YIELD) && defined(HAVE_SCHED_H))
sched_yield();
#elif defined(HAVE_PTHREAD_YIELD_ZERO_ARG)
pthread_yield();
#elif defined(HAVE_PTHREAD_YIELD_ONE_ARG)
pthread_yield(0);
#else
os_thread_sleep(0);
#endif
}
#endif /* !UNIV_HOTBACKUP */
/*****************************************************************//**
The thread sleeps at least the time given in microseconds. */
UNIV_INTERN
void
os_thread_sleep(
/*============*/
ulint tm) /*!< in: time in microseconds */
{
#ifdef __WIN__
Sleep((DWORD) tm / 1000);
#elif defined(__NETWARE__)
delay(tm / 1000);
#else
struct timeval t;
t.tv_sec = tm / 1000000;
t.tv_usec = tm % 1000000;
select(0, NULL, NULL, NULL, &t);
#endif
}
#ifndef UNIV_HOTBACKUP
/******************************************************************//**
Sets a thread priority. */
UNIV_INTERN
void
os_thread_set_priority(
/*===================*/
os_thread_t handle, /*!< in: OS handle to the thread */
ulint pri) /*!< in: priority */
{
#ifdef __WIN__
int os_pri;
if (pri == OS_THREAD_PRIORITY_BACKGROUND) {
os_pri = THREAD_PRIORITY_BELOW_NORMAL;
} else if (pri == OS_THREAD_PRIORITY_NORMAL) {
os_pri = THREAD_PRIORITY_NORMAL;
} else if (pri == OS_THREAD_PRIORITY_ABOVE_NORMAL) {
os_pri = THREAD_PRIORITY_HIGHEST;
} else {
ut_error;
}
ut_a(SetThreadPriority(handle, os_pri));
#else
UT_NOT_USED(handle);
UT_NOT_USED(pri);
#endif
}
/******************************************************************//**
Gets a thread priority.
@return priority */
UNIV_INTERN
ulint
os_thread_get_priority(
/*===================*/
os_thread_t handle __attribute__((unused)))
/*!< in: OS handle to the thread */
{
#ifdef __WIN__
int os_pri;
ulint pri;
os_pri = GetThreadPriority(handle);
if (os_pri == THREAD_PRIORITY_BELOW_NORMAL) {
pri = OS_THREAD_PRIORITY_BACKGROUND;
} else if (os_pri == THREAD_PRIORITY_NORMAL) {
pri = OS_THREAD_PRIORITY_NORMAL;
} else if (os_pri == THREAD_PRIORITY_HIGHEST) {
pri = OS_THREAD_PRIORITY_ABOVE_NORMAL;
} else {
ut_error;
}
return(pri);
#else
return(0);
#endif
}
/******************************************************************//**
Gets the last operating system error code for the calling thread.
@return last error on Windows, 0 otherwise */
UNIV_INTERN
ulint
os_thread_get_last_error(void)
/*==========================*/
{
#ifdef __WIN__
return(GetLastError());
#else
return(0);
#endif
}
#endif /* !UNIV_HOTBACKUP */