标签:static pair key load sch rmi 方式 copyright value
typedef struct{
//指向共享内存的事实上地址
u_char* addr;
//共享内存的长度
size_t size;
//这块共享内存的名称
ngx_str_t name;
//记录日志的ngx_log_t对象
ngx_lot_t* log;
//表示共享内存是否已经分配过的标志位。为1时表示已经存在
ngx_uint_t exists;
} ngx_shm_t;
int socketpair ( int d, int type, int protocol, int sv[2] );
通常在父子进程之间通信前。会先调用socketpair创建一组套接字,在调用fork方法创建出子进程后。将会在父进程中关闭sv[1]套接字,子进程关闭sv[0]套接字。
ngx_channel_t频道结构体是Nginx定义的master父进程和worker子进程间通信的消息格式。
例如以下所看到的:
typedef struct{
//传递的TCP消息中的命令
ngx_uint_t command;
//进程ID。通常是发送命令方的进程ID
ngx_pid_t pid;
//表示发送命令方在ngx_processes进程数组间的序号
ngx_int_t slot;
//通信的套接字句柄
ngx_fd_t fd;
} ngx_channel_t;
ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t* ch, size_t size, ngx_log_t*log);
这里的s參数是要使用的TCP套接字。ch參数是ngx_channel_t类型的消息,size參数是ngx_channel_t结构体的大小,log參数是日志对象。
读取消息的方法ngx_read_channel
ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t* ch, size_t size, ngx_log_t* log);
worker进程使用ngx_add_channel_event方法把接受频道消息的套接字加入到epoll中,当接收到父进程消息时子进程会通过epoll的事件回调对应的handler方法来处理这个频道消息。
ngx_int_t ngx_add_channel_event(ngx_cycle_t* cycle, ngx_fd_t fd, ngx_int_t event,ngx_event_handler_pt handler);
cycle參数是每一个nginx进程必须具备的ngx_cycle_t核心结构体;fd參数是上面说过的须要接受消息的套接字。
event參数是须要检測的事件类型。这里必定是EPOLLIN;handler參数指向的方法就是用于读取消息的方法。
void ngx_close_channel(ngx_fd_t* fd, ngx_lot_t* log);
參数fd就是上面说过的套接字数组。
typedef struct{
//须要处理的信号
int signo;
//信号相应的字符串名称
char* siname;
//这个信号相应着的Nginx命令
char* name;
//收到signo信号后就会回调handler方法
void (*handler)(int signo);
} ngx_signal_t;
ngx_signal_t signals[] = {
{
ngx_signal_value(NGX_RECOFIGURE_SIGNAL),
“SIG” ngx_value(NGX_RECONFIGURE_SIGNAL),
“reload”,
ngx_signal_handler
},
…
}
ngx_int_t ngx_init_signals(nx_log_t* log)
{
ngx_signal_t* sig;
struct signaction sa;
//遍历signals数组。处理每个ngx_signal_t类型的结构体
for(sig = signals; sig->signo != 0; sig++){
ngx_memzero(&sa, sizeof(struct, sigaction));
//设置信号的处理方法为handler方法
sa.sa_handler = sig->handler;
//将sa中的为所有设置为0
sigemptyset(&sa.sa_mask);
//注冊信号的回调方法
if(sigaction(sig->signo, &sa, NULL) == -1){
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
“sigaction(%s) failed”, sig->signame);
return NGX_ERROR;
}
}
return NGX_OK;
}
对信号设置并生是在fork()函数调用之前进行的,所以工作金曾等都能受此作用。当然,普通情况下,我们不会向工作进程等子进程发送控制信息。而主要想监控进程父进程发送,父进程收到信号做对应处理后,在依据情况看是否把信号再通知到其它全部子进程。
这两个方法都能够用来改动原子变量的值,而ngx_atomic_cmp_set方法同一时候还能够比較原子变量的值。
以下看一下它的源代码:
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
//函数:基于原子操作的自旋锁方法ngx_spinlock的实现
//參数解释:
//lock:原子变量表达的锁
//value:标志位。锁是否被某一进程占用
//spin:在多处理器系统内,当ngx_spinlock方法没有拿到锁时,当前进程在内核的一次调度中该方法等待其它处理器释放锁的时间
void
ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
{
#if (NGX_HAVE_ATOMIC_OPS)//支持原子操作
ngx_uint_t i, n;
//一直处于循环中,直到获取到锁
for ( ;; ) {
//lock为0表示没有其它进程持有锁,这时将lock值设置为value參数表示当前进程持有了锁
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
return;
}
//假设是多处理器系统
if (ngx_ncpu > 1) {
/*
在多处理器下。当发现锁被其它进程占用时,当前进程并非立马让出正在使用的CPU处理器,而是等待一段时间,看看其它处理器上的进程是否会释放锁,这会降低进程间切换的次数。
*/
for (n = 1; n < spin; n <<= 1) {
//随着等待的次数越来越多,实际去检查锁的间隔时间越来越大
for (i = 0; i < n; i++) {
/*
ngx_cpu_pause是很多架构体系中专门为了自旋锁而提供的指令,它会告诉CPU如今处于自旋锁等待状态,通常一个CPU会将自己置于节能状态,降低功耗。可是当前进程并没有让出正在使用的处理器。
*/
ngx_cpu_pause();//
}
/*
检查锁是否被释放了,假设lock值为0且释放了锁后。就把它的值设为value,当前进程持有锁成功并返回
*/
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
return;
}
}
}
/*
` 当前进程让出处理器,但仍然处于可运行状态,使得处理器优先调度其它可运行状态的进程,这样。在进程被内核再次调度时,在for循环代码中能够期望其它进程释放锁。
*/
ngx_sched_yield();
}
#else
#if (NGX_THREADS)
#error ngx_spinlock() or ngx_atomic_cmp_set() are not defined !
#endif
#endif
}
不做具体解释。
typedef struct{
#if ( NGX_HAVE_ATOMIC_OPS)
//原子变量锁
ngx_atomic_t* lock;
#if (NGX_HAVE_POSIX_SEM)
//semaphore为1 时表示获取锁将可能使用到的信号量
ngx_uint_t semaphonre;
//sem就是信号量锁
sem_t sem;
#endif;
#else
//使用文件锁时fd表示使用的文件句柄
ngx_fd_t fd;
//name表示文件名称
u_char* name;
#endif
/*自旋次数。表示在自旋状态下等待其它处理器结果中释放的时间。由文件锁实现,spin没有不论什么意义*/
ngx_uint_t spin;
} ngx_shmtx_t;
这两个成员使用上面介绍的文件锁来提供堵塞、非堵塞的相互排斥锁。
标签:static pair key load sch rmi 方式 copyright value
原文地址:http://www.cnblogs.com/cxchanpin/p/7241346.html