标签: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