summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_thread.h
blob: 53b2d8c0f3c23116364eb5a9ae2eab0371482b69 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) NGINX, Inc.
 */

#ifndef _NXT_UNIX_THREAD_H_INCLUDED_
#define _NXT_UNIX_THREAD_H_INCLUDED_


/*
 * Thread Specific Data
 *
 * The interface unifies two TSD implementations: the __thread storage
 * class and pthread specific data.  It works also in non-threaded mode.
 * The interface is optimized for the __thread storage class and non-threaded
 * mode, since the __thread storage is faster and is supported in modern
 * versions of Linux, FreeBSD, Solaris, and MacOSX.  Pthread specific data
 * is considered as a fallback option.
 *
 * The underlining interfaces are different: pthread data must be allocated
 * by hand and may be accessed only by using pointers whereas __thread data
 * allocation is transparent and it is accessed directly.
 *
 * pthread_getspecific() is usually faster than pthread_setspecific()
 * (much faster on MacOSX), so there is no nxt_thread_set_data() interface
 * for this reason.  It is better to store frequently alterable thread
 * log pointer in nxt_thread_t, but not in a dedicated key.
 */

#if (NXT_HAVE_THREAD_STORAGE_CLASS)

#define nxt_thread_extern_data(type, tsd)                                     \
    NXT_EXPORT extern __thread type  tsd

#define nxt_thread_declare_data(type, tsd)                                    \
    __thread type  tsd

#define nxt_thread_init_data(tsd)

#define nxt_thread_get_data(tsd)                                              \
    &tsd


#else /* NXT_HAVE_PTHREAD_SPECIFIC_DATA */

/*
 * nxt_thread_get_data() is used as
 *    p = nxt_thread_get_data(tsd),
 * but the tsd address is actually required.  This could be resolved by macro
 *    #define nxt_thread_get_data(tsd)  nxt_thread_get_data_addr(&tsd)
 * or by definition nxt_thread_specific_data_t as an array.
 *
 * On Linux and Solaris pthread_key_t is unsigned integer.
 * On FreeBSD, NetBSD, OpenBSD, and HP-UX pthread_key_t is integer.
 * On MacOSX and AIX pthread_key_t is unsigned long integer.
 * On Cygwin pthread_key_t is pointer to void.
 */

typedef struct {
    nxt_atomic_t             key;
    size_t                   size;
} nxt_thread_specific_data_t[1];


#define nxt_thread_extern_data(type, tsd)                                     \
    NXT_EXPORT extern nxt_thread_specific_data_t  tsd

#define nxt_thread_declare_data(type, tsd)                                    \
    nxt_thread_specific_data_t tsd = { { (nxt_atomic_int_t) -1, sizeof(type) } }

NXT_EXPORT void nxt_thread_init_data(nxt_thread_specific_data_t tsd);

#define nxt_thread_get_data(tsd)                                              \
    pthread_getspecific((pthread_key_t) tsd->key)

#endif


typedef void (*nxt_thread_start_t)(void *data);

typedef struct {
    nxt_thread_start_t       start;
    nxt_event_engine_t       *engine;
    nxt_work_t               work;
} nxt_thread_link_t;


NXT_EXPORT nxt_int_t nxt_thread_create(nxt_thread_handle_t *handle,
    nxt_thread_link_t *link);
NXT_EXPORT nxt_thread_t *nxt_thread_init(void);
NXT_EXPORT void nxt_thread_exit(nxt_thread_t *thr);
NXT_EXPORT void nxt_thread_cancel(nxt_thread_handle_t handle);
NXT_EXPORT void nxt_thread_wait(nxt_thread_handle_t handle);


#define nxt_thread_handle()                                                   \
    pthread_self()


typedef pthread_mutex_t      nxt_thread_mutex_t;

NXT_EXPORT nxt_int_t nxt_thread_mutex_create(nxt_thread_mutex_t *mtx);
NXT_EXPORT void nxt_thread_mutex_destroy(nxt_thread_mutex_t *mtx);
NXT_EXPORT nxt_int_t nxt_thread_mutex_lock(nxt_thread_mutex_t *mtx);
NXT_EXPORT nxt_bool_t nxt_thread_mutex_trylock(nxt_thread_mutex_t *mtx);
NXT_EXPORT nxt_int_t nxt_thread_mutex_unlock(nxt_thread_mutex_t *mtx);


typedef pthread_cond_t       nxt_thread_cond_t;

NXT_EXPORT nxt_int_t nxt_thread_cond_create(nxt_thread_cond_t *cond);
NXT_EXPORT void nxt_thread_cond_destroy(nxt_thread_cond_t *cond);
NXT_EXPORT nxt_int_t nxt_thread_cond_signal(nxt_thread_cond_t *cond);
NXT_EXPORT nxt_err_t nxt_thread_cond_wait(nxt_thread_cond_t *cond,
    nxt_thread_mutex_t *mtx, nxt_nsec_t timeout);


#if (NXT_HAVE_PTHREAD_YIELD)
#define nxt_thread_yield()                                                    \
    pthread_yield()

#elif (NXT_HAVE_PTHREAD_YIELD_NP)
#define nxt_thread_yield()                                                    \
    pthread_yield_np()

#else
#define nxt_thread_yield()                                                    \
    nxt_sched_yield()

#endif


struct nxt_thread_s {
    nxt_log_t                *log;
    nxt_log_t                main_log;

    nxt_task_t               *task;

    nxt_tid_t                tid;
    nxt_thread_handle_t      handle;
    nxt_thread_link_t        *link;
    nxt_thread_pool_t        *thread_pool;

    nxt_thread_time_t        time;

    nxt_runtime_t            *runtime;
    nxt_event_engine_t       *engine;
    void                     *data;

#if 0
    /*
     * Although pointer to a current fiber should be a property of
     * engine->fibers, its placement here eliminates 2 memory accesses.
     */
    nxt_fiber_t              *fiber;
#endif

    nxt_random_t             random;
};


#endif /* _NXT_UNIX_THREAD_H_INCLUDED_ */