Solaris 10 的新增加的特性。
一.API
1. port_create()
原型:int port_create(void);
port_create() 创建一个 Event ports 队列,返回一个文件描述符作为该
Event port 的代表。
相似:kqueue(),epoll_create()
2. port_associate()
原型:int port_associate(int port, int source, uintptr_t object,
int events, void *user);
port_associate() 将某一个对象的特定 event 与 Event port 相关联。当
source 为 PORT_SOURCE_FD 时,object 就是文件描述符。events 可以参考
poll(2) 的。user 是一个用户自定义的指针,与该 object 相关的。在
kqueue(2) 和 epoll(4) 也提供了类似的用户自定义指针。在前面的 echo
server 例子中,传入了一个函数指针给 user,这样在 main() 的事件处理
主循环中,代码就可以写得非常简洁。
需要注意的是,当用 port_get() 取得某个 object 的 event 之后,这个
object 与 port 也就不再相关联了。如果想继续取得这个 object 的 event,
必须再次调用 port_associate() 将 object 与 port 关联。这种设计显然
是为多线程程序而做的,当某一个线程取得一个 event 之后,object 就从
port 的对列中删掉了,这样可以保证这个线程完完整整地处理完这个 event,
不用担心别的线程也会取得这个 event。
相似:kevent(),epoll_ctl()
3. port_get()
原型:int port_get(int port, port_event_t *pe, const timespec_t
*timeout);
port_get() 每次从 port 中取回一个 event。如果 timeout 参数为 NULL,
port_get() 会一直等待,直到某一个 event 到来。pe 用于存储返回的
event。
相似:kevent(),epoll_wait()
4. port_getn()
原型:int port_getn(int port, port_event_t list[], uint_t max,
uint_t *nget, const timespec_t *timeout);
port_getn() 与 port_get() 都是用于从 port 中取回 event,不同的是
port_getn() 可以一次取回多个。list 数组用于存储返回的多个 events,
max 为 list 数组的元素个数。timeout 与 port_get() 的一致。
需要特别注意的是 nget 参数,这是一个 value-result 参数,也就是传入
n,告诉内核要取得 n 个 event,当 port_getn() 返回时,getn 的值表示
内核实际取得了多少个。当 timeout 为 NULL 时,port_getn() 会一直等待,
直到确实取得了 n 个 event 之后才会返回,这一点是与 kevent() 和
epoll_wait() 很不相同的地方。如果 timeout 不为 NULL,则只要超时就返
回,不管是不是已经取到了 n 个 event。(注:这里忽略了其他可能引起
port_getn() 返回的因素) 这也是前面的 echo server 代码中要设置一个
50 毫秒超时的原因。大家可以试试把 NULL 传给 timeout 的效果。
相似:kevent(),epoll_wait()
二.例子
str_srv.c:
/* 用 Event ports 实现的 UNPv1 ECHO Server 例子程序。
*
* 编译命令:
* gcc -o str_srv str_srv.c -lsocket
*
* flyriver 2004.11.02
*/
#include <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/poll.h>
#include <errno.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include <port.h> /* for event ports */
#define SERV_PORT 9877
#define MAXLINE 80
#ifndef OPEN_MAX
#define OPEN_MAX 256
#endif
typedef void (*port_func_t)(port_event_t *);
int portfd;
uint_t maxi;
static void echo(port_event_t *ev)
{
ssize_t n;
int sockfd;
char buf[MAXLINE];
sockfd = ev->portev_object;
if (ev->portev_events & POLLIN)
{
if ((n = read(sockfd, buf, MAXLINE)) < 0)
{
perror("read");
close(sockfd);
maxi--;
}
else if (n == 0) /* connection closed by client */
{
close(sockfd);
maxi--;
}
else
{
write(sockfd, buf, n);
/* 重新关联 client fd 到 event ports */
port_associate(portfd, PORT_SOURCE_FD, sockfd, POLLIN, echo);
}
}
}
static void new_conn(port_event_t *ev)
{
int connfd;
socklen_t clilen;
struct sockaddr_in cliaddr;
int listenfd;
listenfd = ev->portev_object;
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
/* 关联 client fd 到 event ports */
port_associate(portfd, PORT_SOURCE_FD, connfd, POLLIN, echo);
maxi++;
/* 重新关联 listenfd 到 event ports */
port_associate(portfd, PORT_SOURCE_FD, listenfd, POLLIN, new_conn);
}
int main()
{
int listenfd;
struct sockaddr_in servaddr;
int optval;
/* variables for event ports version */
int i;
uint_t nready;
port_event_t client[OPEN_MAX];
timespec_t timeout;
port_func_t port_func;
bzero(&servaddr, sizeof(servaddr));
listenfd = socket(AF_INET, SOCK_STREAM, 0);
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, 4);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 5);
/* 创建 event ports */
portfd = port_create();
/* 关联 listenfd 到 event ports */
port_associate(portfd, PORT_SOURCE_FD, listenfd, POLLIN, new_conn);
maxi++;
timeout.tv_sec = 0;
timeout.tv_nsec = 50000000; /* 50 毫秒 */
for (;;)
{
/* get events here*/
nready = maxi;
if (port_getn(portfd, client, OPEN_MAX, &nready, &timeout) < 0
&& errno != ETIME)
{
if (errno == EINTR)
continue;
else
{
perror("port_getn");
return -1;
}
}
for (i = 0; i < nready; i++)
{
if (client[i].portev_source == PORT_SOURCE_FD)
{
port_func = (port_func_t)client[i].portev_user;
port_func(&client[i]);
}
}
}
close(portfd);
return 0;
}
参考:http://www.smth.edu.cn/bbsgcon.php?board=OS&file=T/G.1099404898.p0&num=526
http://bbs.tsinghua.edu.cn/bbsgcon.php?board=OS&file=j/G.1099375601.80&num=525