/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_THREAD_H_INCLUDED_
#define _NGX_THREAD_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#if (NGX_THREADS)
#define NGX_MAX_THREADS 128
#if (NGX_USE_RFORK)
#include <ngx_freebsd_rfork_thread.h>
#else /* use pthreads */
#include <pthread.h>
typedef pthread_t ngx_tid_t;
#define ngx_thread_self() pthread_self()
#define ngx_log_tid (int) ngx_thread_self()
#if (NGX_FREEBSD) && !(NGX_LINUXTHREADS)
#define NGX_TID_T_FMT "%p"
#else
#define NGX_TID_T_FMT "%d"
#endif
typedef pthread_key_t ngx_tls_key_t;
#define ngx_thread_key_create(key) pthread_key_create(key, NULL)
#define ngx_thread_key_create_n "pthread_key_create()"
#define ngx_thread_set_tls pthread_setspecific
#define ngx_thread_set_tls_n "pthread_setspecific()"
#define ngx_thread_get_tls pthread_getspecific
#define NGX_MUTEX_LIGHT 0
typedef struct {
pthread_mutex_t mutex;
ngx_log_t *log;
} ngx_mutex_t;
typedef struct {
pthread_cond_t cond;
ngx_log_t *log;
} ngx_cond_t;
#define ngx_thread_sigmask pthread_sigmask
#define ngx_thread_sigmask_n "pthread_sigmask()"
#define ngx_thread_join(t, p) pthread_join(t, p)
#define ngx_setthrtitle(n)
ngx_int_t ngx_mutex_trylock(ngx_mutex_t *m);
void ngx_mutex_lock(ngx_mutex_t *m);
void ngx_mutex_unlock(ngx_mutex_t *m);
#endif
#define ngx_thread_volatile volatile
typedef struct {
ngx_tid_t tid;
ngx_cond_t *cv;
ngx_uint_t state;
} ngx_thread_t;
#define NGX_THREAD_FREE 1
#define NGX_THREAD_BUSY 2
#define NGX_THREAD_EXIT 3
#define NGX_THREAD_DONE 4
extern ngx_int_t ngx_threads_n;
extern volatile ngx_thread_t ngx_threads[NGX_MAX_THREADS];
typedef void * ngx_thread_value_t;
ngx_int_t ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle);
ngx_err_t ngx_create_thread(ngx_tid_t *tid,
ngx_thread_value_t (*func)(void *arg), void *arg, ngx_log_t *log);
ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, ngx_uint_t flags);
void ngx_mutex_destroy(ngx_mutex_t *m);
ngx_cond_t *ngx_cond_init(ngx_log_t *log);
void ngx_cond_destroy(ngx_cond_t *cv);
ngx_int_t ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m);
ngx_int_t ngx_cond_signal(ngx_cond_t *cv);
#else /* !NGX_THREADS */
#define ngx_thread_volatile
#define ngx_log_tid 0
#define NGX_TID_T_FMT "%d"
#define ngx_mutex_trylock(m) NGX_OK
#define ngx_mutex_lock(m)
#define ngx_mutex_unlock(m)
#define ngx_cond_signal(cv)
#define ngx_thread_main() 1
#endif
#endif /* _NGX_THREAD_H_INCLUDED_ */
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
static ngx_uint_t nthreads;
static ngx_uint_t max_threads;
static pthread_attr_t thr_attr;
ngx_err_t
ngx_create_thread( ngx_tid_t *tid, ngx_thread_value_t (*func)( void *arg ),
void *arg, ngx_log_t *log )
{
int err;
if ( nthreads >= max_threads )
{
ngx_log_error( NGX_LOG_CRIT, log, 0,
"no more than %ui threads can be created", max_threads );
return NGX_ERROR;
}
err = pthread_create( tid, &thr_attr, func, arg );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, log, err, "pthread_create() failed" );
return err;
}
ngx_log_debug1( NGX_LOG_DEBUG_CORE, log, 0,
"thread is created: " NGX_TID_T_FMT, *tid );
nthreads++; // 全局变量nthreads记录了创建的线程总数
return err;
}
//初始化全局变量thr_attr,设置栈的大小为参数size
ngx_int_t
ngx_init_threads( int n, size_t size, ngx_cycle_t *cycle )
{
int err;
max_threads = n;
err = pthread_attr_init( &thr_attr );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, cycle->log, err,
"pthread_attr_init() failed" );
return NGX_ERROR;
}
err = pthread_attr_setstacksize( &thr_attr, size );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, cycle->log, err,
"pthread_attr_setstacksize() failed" );
return NGX_ERROR;
}
ngx_threaded = 1; //设置为1表示已经初始化线程属性初始化好了
return NGX_OK;
}
//分配空间,初始化一个线程锁
ngx_mutex_t *
ngx_mutex_init( ngx_log_t *log, ngx_uint_t flags )
{
int err;
ngx_mutex_t *m;
m = ngx_alloc( sizeof ( ngx_mutex_t ), log );
if ( m == NULL )
{
return NULL;
}
m->log = log;
err = pthread_mutex_init( &m->mutex, NULL );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, m->log, err,
"pthread_mutex_init() failed" );
return NULL;
}
return m;
}
//释放一个线程锁
void
ngx_mutex_destroy( ngx_mutex_t *m )
{
int err;
err = pthread_mutex_destroy( &m->mutex );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, m->log, err,
"pthread_mutex_destroy(%p) failed", m );
}
ngx_free(m);
}
//锁住mutex m
void
ngx_mutex_lock( ngx_mutex_t *m )
{
int err;
if ( !ngx_threaded ) //没有初始化线程属性结构体,则直接返回
{
return;
}
ngx_log_debug1( NGX_LOG_DEBUG_MUTEX, m->log, 0, "lock mutex %p", m );
err = pthread_mutex_lock( &m->mutex );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, m->log, err,
"pthread_mutex_lock(%p) failed", m );
ngx_abort();
}
ngx_log_debug1( NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m );
return;
}
ngx_int_t
ngx_mutex_trylock( ngx_mutex_t *m )
{
int err;
if ( !ngx_threaded )
{
return NGX_OK;
}
ngx_log_debug1( NGX_LOG_DEBUG_MUTEX, m->log, 0, "try lock mutex %p", m );
err = pthread_mutex_trylock( &m->mutex );
if ( err == NGX_EBUSY ) // 锁被别的线程占住了,返回EAGAIN
{
return NGX_AGAIN;
}
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, m->log, err,
"pthread_mutex_trylock(%p) failed", m );
ngx_abort();
}
ngx_log_debug1( NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m );
return NGX_OK;
}
void
ngx_mutex_unlock( ngx_mutex_t *m )
{
int err;
if ( !ngx_threaded )
{
return;
}
ngx_log_debug1( NGX_LOG_DEBUG_MUTEX, m->log, 0, "unlock mutex %p", m );
err = pthread_mutex_unlock( &m->mutex );
if (err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, m->log, err,
"pthread_mutex_unlock(%p) failed", m );
ngx_abort();
}
ngx_log_debug1( NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is unlocked", m );
return;
}
ngx_cond_t *
ngx_cond_init( ngx_log_t *log )
{
int err;
ngx_cond_t *cv;
cv = ngx_alloc( sizeof( ngx_cond_t ), log );
if ( cv == NULL )
{
return NULL;
}
cv->log = log;
err = pthread_cond_init( &cv->cond, NULL );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, cv->log, err,
"pthread_cond_init() failed" );
return NULL;
}
return cv;
}
void
ngx_cond_destroy( ngx_cond_t *cv )
{
int err;
err = pthread_cond_destroy( &cv->cond );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, cv->log, err,
"pthread_cond_destroy(%p) failed", cv );
}
ngx_free( cv );
}
ngx_int_t
ngx_cond_wait( ngx_cond_t *cv, ngx_mutex_t *m )
{
int err;
ngx_log_debug1( NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p wait", cv );
err = pthread_cond_wait( &cv->cond, &m->mutex );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, cv->log, err,
"pthread_cond_wait(%p) failed", cv );
return NGX_ERROR;
}
ngx_log_debug1( NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is waked up", cv );
ngx_log_debug1( NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m );
return NGX_OK;
}
ngx_int_t
ngx_cond_signal( ngx_cond_t *cv )
{
int err;
ngx_log_debug1( NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p to signal", cv );
err = pthread_cond_signal( &cv->cond );
if ( err != 0 )
{
ngx_log_error( NGX_LOG_ALERT, cv->log, err,
"pthread_cond_signal(%p) failed", cv );
return NGX_ERROR;
}
ngx_log_debug1( NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is signaled", cv );
return NGX_OK;
}