0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <stdio.h>
0037 #include <stdlib.h>
0038 #include <time.h>
0039
0040 #include <unistd.h>
0041 #include <stdarg.h>
0042 #include <ctype.h>
0043 #include <memory.h>
0044 #include <errno.h>
0045 #include <signal.h>
0046 #include <limits.h>
0047 #include <pthread.h>
0048 #include <string.h>
0049
0050 #include <ndrstandard.h>
0051 #include <ndebug.h>
0052 #include <nstdutil.h>
0053 #include <limits.h>
0054
0055 #include <sys_unix.h>
0056
0057
0058
0059
0060 #define EX_POLL_SETS_MAX 1024
0061
0062 #define ERROR_BUFFER 1024
0063
0064 #define EX_EPOLL_API_ENTRY {NSTD_TLS_ENTRY; \
0065 G_nstd_tls->M_last_err = 0; \
0066 G_nstd_tls->M_last_err_msg[0] = EXEOS;}
0067
0068
0069
0070
0071
0072
0073 struct ndrx_epoll_set
0074 {
0075 int fd;
0076
0077 struct pollfd *fdtab;
0078 int nrfds;
0079
0080 EX_hash_handle hh;
0081 };
0082 typedef struct ndrx_epoll_set ndrx_epoll_set_t;
0083
0084
0085
0086 exprivate ndrx_epoll_set_t *M_psets = NULL;
0087 MUTEX_LOCKDECL(M_psets_lock);
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 exprivate ndrx_epoll_set_t* pset_find(int epfd)
0099 {
0100 ndrx_epoll_set_t *ret = NULL;
0101
0102 EXHASH_FIND_INT( M_psets, &epfd, ret);
0103
0104 return ret;
0105 }
0106
0107
0108
0109
0110
0111
0112
0113 exprivate int fd_find(ndrx_epoll_set_t *pset, int fd)
0114 {
0115 int i;
0116
0117 for (i=0; i<pset->nrfds; i++)
0118 {
0119 if (fd==pset->fdtab[i].fd)
0120 {
0121 return i;
0122 }
0123 }
0124
0125 return EXFAIL;
0126 }
0127
0128
0129
0130
0131
0132 exprivate void ndrx_epoll_set_err(int error_code, const char *fmt, ...)
0133 {
0134 char msg[ERROR_BUFFER+1] = {EXEOS};
0135 va_list ap;
0136
0137 NSTD_TLS_ENTRY;
0138
0139 va_start(ap, fmt);
0140 (void) vsnprintf(msg, sizeof(msg), fmt, ap);
0141 va_end(ap);
0142
0143 strcpy(G_nstd_tls->M_last_err_msg, msg);
0144 G_nstd_tls->M_last_err = error_code;
0145
0146 NDRX_LOG(log_warn, "ndrx_epoll_set_err: %d (%s) (%s)",
0147 error_code, strerror(G_nstd_tls->M_last_err),
0148 G_nstd_tls->M_last_err_msg);
0149
0150 }
0151
0152
0153
0154
0155 expublic inline void ndrx_epoll_sys_init(void)
0156 {
0157 return;
0158 }
0159
0160
0161
0162
0163 expublic inline void ndrx_epoll_sys_uninit(void)
0164 {
0165 return;
0166 }
0167
0168
0169
0170
0171
0172 expublic inline char * ndrx_epoll_mode(void)
0173 {
0174 static char *mode = "fdpoll";
0175
0176 return mode;
0177 }
0178
0179
0180
0181
0182
0183
0184
0185
0186 expublic inline int ndrx_epoll_ctl(int epfd, int op, int fd, struct ndrx_epoll_event *event)
0187 {
0188 int ret = EXSUCCEED;
0189 ndrx_epoll_set_t* set = NULL;
0190 char *fn = "ndrx_epoll_ctl";
0191
0192 EX_EPOLL_API_ENTRY;
0193
0194 MUTEX_LOCK_V(M_psets_lock);
0195
0196 if (NULL==(set = pset_find(epfd)))
0197 {
0198 NDRX_LOG(log_error, "ndrx_epoll set %d not found", epfd);
0199 ndrx_epoll_set_err(ENOSYS, "ndrx_epoll set %d not found", epfd);
0200 EXFAIL_OUT(ret);
0201 }
0202
0203 if (EX_EPOLL_CTL_ADD == op)
0204 {
0205 NDRX_LOG(log_info, "%s: Add operation on ndrx_epoll set %d, fd %d", fn, epfd, fd);
0206
0207
0208 if (EXFAIL!=fd_find(set, fd))
0209 {
0210
0211 ndrx_epoll_set_err(EINVAL, "fd %d already exists in ndrx_epoll set (epfd %d)",
0212 fd, set->fd);
0213 NDRX_LOG(log_error, "fd %d already exists in ndrx_epoll set (epfd %d)",
0214 fd, set->fd);
0215 EXFAIL_OUT(ret);
0216 }
0217
0218
0219 set->nrfds++;
0220
0221 NDRX_LOG(log_info, "set nrfds incremented to %d", set->nrfds);
0222
0223 if (NULL==(set->fdtab=NDRX_REALLOC(set->fdtab, sizeof(struct pollfd)*set->nrfds)))
0224 {
0225 ndrx_epoll_set_err(errno, "Failed to realloc %d/%d",
0226 set->nrfds, sizeof(struct pollfd)*set->nrfds);
0227 NDRX_LOG(log_error, "Failed to realloc %d/%d",
0228 set->nrfds, sizeof(struct pollfd)*set->nrfds);
0229 EXFAIL_OUT(ret);
0230 }
0231
0232 set->fdtab[set->nrfds-1].fd = fd;
0233 set->fdtab[set->nrfds-1].events = event->events;
0234
0235 }
0236 else if (EX_EPOLL_CTL_DEL == op)
0237 {
0238 int found = EXFALSE;
0239 int i;
0240 NDRX_LOG(log_info, "%s: Delete operation on ndrx_epoll set %d, fd %d", fn, epfd, fd);
0241
0242
0243 if (EXFAIL==fd_find(set, fd))
0244 {
0245 ndrx_epoll_set_err(EINVAL, "fd %d not found in ndrx_epoll set (epfd %d)",
0246 fd, set->fd);
0247 NDRX_LOG(log_error, "fd %d not found in ndrx_epoll set (epfd %d)",
0248 fd, set->fd);
0249 EXFAIL_OUT(ret);
0250 }
0251
0252
0253
0254 for (i = 0; i < set->nrfds; i++)
0255 {
0256 if (set->fdtab[i].fd == fd)
0257 {
0258
0259 if (i!=set->nrfds-1 && set->nrfds>1)
0260 {
0261
0262 memmove(&set->fdtab[i], &set->fdtab[i+1],
0263 sizeof(struct pollfd)*(set->nrfds-i-1));
0264 }
0265
0266 set->nrfds--;
0267
0268 NDRX_LOG(log_info, "set nrfds decremented to %d", set->nrfds);
0269
0270 if (0==set->nrfds)
0271 {
0272 NDRX_LOG(log_warn, "set->nrfds == 0, => free");
0273 NDRX_FREE((char *)set->fdtab);
0274 }
0275 else if (NULL==(set->fdtab=NDRX_REALLOC(set->fdtab,
0276 sizeof(struct pollfd)*set->nrfds)))
0277 {
0278 ndrx_epoll_set_err(errno, "Failed to realloc %d/%d",
0279 set->nrfds, sizeof(struct pollfd)*set->nrfds);
0280
0281 NDRX_LOG(log_error, "Failed to realloc %d/%d",
0282 set->nrfds, sizeof(struct pollfd)*set->nrfds);
0283
0284 EXFAIL_OUT(ret);
0285 }
0286
0287 found = EXTRUE;
0288
0289 break;
0290 }
0291 }
0292
0293 if (!found)
0294 {
0295 NDRX_LOG(log_warn, "File descriptor %d was requested for removal, "
0296 "but not found epoll set %d!", fd, epfd);
0297 }
0298 }
0299 else
0300 {
0301 ndrx_epoll_set_err(EINVAL, "Invalid operation %d", op);
0302 NDRX_LOG(log_error, "Invalid operation %d", op);
0303
0304 EXFAIL_OUT(ret);
0305 }
0306
0307 out:
0308
0309 MUTEX_UNLOCK_V(M_psets_lock);
0310
0311 NDRX_LOG(log_info, "%s return %d", fn, ret);
0312
0313 return ret;
0314 }
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324 expublic inline int ndrx_epoll_ctl_mq(int epfd, int op, mqd_t fd, struct ndrx_epoll_event *event)
0325 {
0326 return ndrx_epoll_ctl(epfd, op, (int)fd, event);
0327 }
0328
0329
0330
0331
0332
0333
0334 expublic inline int ndrx_epoll_create(int size)
0335 {
0336 int ret = EXSUCCEED;
0337 int i = 1;
0338 ndrx_epoll_set_t *set;
0339
0340 EX_EPOLL_API_ENTRY;
0341
0342 while (NULL!=(set=pset_find(i)) && i < EX_POLL_SETS_MAX)
0343 {
0344 i++;
0345 }
0346
0347
0348 if (NULL!=set)
0349 {
0350 ndrx_epoll_set_err(EMFILE, "Max ndrx_epoll_sets_reached");
0351 NDRX_LOG(log_error, "Max ndrx_epoll_sets_reached");
0352
0353
0354 set = NULL;
0355 EXFAIL_OUT(ret);
0356 }
0357
0358 NDRX_LOG(log_info, "Creating ndrx_epoll set: %d", i);
0359
0360 if (NULL==(set = (ndrx_epoll_set_t *)NDRX_CALLOC(1, sizeof(*set))))
0361 {
0362 ndrx_epoll_set_err(errno, "Failed to alloc: %d bytes", sizeof(*set));
0363
0364 NDRX_LOG(log_error, "Failed to alloc: %d bytes", sizeof(*set));
0365
0366 EXFAIL_OUT(ret);
0367 }
0368
0369 set->nrfds = 0;
0370 set->fd = i;
0371
0372
0373 MUTEX_LOCK_V(M_psets_lock);
0374 EXHASH_ADD_INT(M_psets, fd, set);
0375 MUTEX_UNLOCK_V(M_psets_lock);
0376
0377 NDRX_LOG(log_info, "ndrx_epoll_create succeed, fd=%d", i);
0378
0379 out:
0380
0381 if (EXSUCCEED!=ret)
0382 {
0383
0384 if (NULL!=set)
0385 {
0386 NDRX_FREE((char *)set);
0387 }
0388
0389 return EXFAIL;
0390 }
0391
0392 return i;
0393 }
0394
0395
0396
0397
0398 expublic inline int ndrx_epoll_close(int epfd)
0399 {
0400 int ret = EXSUCCEED;
0401 ndrx_epoll_set_t* set = NULL;
0402
0403 NDRX_LOG(log_debug, "ndrx_epoll_close(%d) enter", epfd);
0404
0405 MUTEX_LOCK_V(M_psets_lock);
0406
0407 NDRX_LOG(log_debug, "ndrx_epoll_close(%d) enter (after lock", epfd);
0408
0409 if (NULL==(set = pset_find(epfd)))
0410 {
0411 MUTEX_UNLOCK_V(M_psets_lock);
0412
0413 ndrx_epoll_set_err(EINVAL, "ndrx_epoll_close set %d not found", epfd);
0414 NDRX_LOG(log_error, "ndrx_epoll_close set %d not found", epfd);
0415
0416
0417 EXFAIL_OUT(ret);
0418 }
0419 MUTEX_UNLOCK_V(M_psets_lock);
0420
0421 while (set->nrfds > 0)
0422 {
0423 ndrx_epoll_ctl(set->fd, EX_EPOLL_CTL_DEL, set->fdtab[0].fd, NULL);
0424 }
0425
0426 MUTEX_LOCK_V(M_psets_lock);
0427 EXHASH_DEL(M_psets, set);
0428 NDRX_FREE(set);
0429 MUTEX_UNLOCK_V(M_psets_lock);
0430
0431 out:
0432 return EXFAIL;
0433 }
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445 expublic inline int ndrx_epoll_wait(int epfd, struct ndrx_epoll_event *events, int maxevents, int timeout,
0446 char **buf, int *buf_len)
0447 {
0448 int ret = EXSUCCEED;
0449 int numevents = 0;
0450 ndrx_epoll_set_t* set = NULL;
0451 char *fn = "ndrx_epoll_wait";
0452 int i;
0453 int retpoll;
0454
0455 EX_EPOLL_API_ENTRY;
0456
0457
0458 MUTEX_LOCK_V(M_psets_lock);
0459
0460 if (NULL==(set = pset_find(epfd)))
0461 {
0462 MUTEX_UNLOCK_V(M_psets_lock);
0463
0464 ndrx_epoll_set_err(EINVAL, "ndrx_epoll set %d not found", epfd);
0465
0466 NDRX_LOG(log_error, "ndrx_epoll set %d not found", epfd);
0467
0468 EXFAIL_OUT(ret);
0469 }
0470
0471 MUTEX_UNLOCK_V(M_psets_lock);
0472
0473
0474
0475
0476
0477
0478 for (i=0; i<set->nrfds; i++)
0479 {
0480 set->fdtab[i].revents = 0;
0481 NDRX_LOG(log_debug, "poll i=%d, fd=%d, events=%d",
0482 i, set->fdtab[i].fd, set->fdtab[i].events);
0483 }
0484
0485 NDRX_LOG(log_debug, "%s: epfd=%d, events=%p, maxevents=%d, "
0486 "timeout=%d - about to poll(nrfds=%d)",
0487 fn, epfd, events, maxevents, timeout, set->nrfds);
0488
0489 retpoll = poll( set->fdtab, set->nrfds, timeout);
0490
0491 NDRX_LOG(log_debug, "retpoll=%d", retpoll);
0492
0493 for (i=0; i<set->nrfds; i++)
0494 {
0495 NDRX_LOG(log_debug, "fd=%d, i=%d revents=%d",
0496 set->fdtab[i].fd, i, set->fdtab[i].revents);
0497 if (set->fdtab[i].revents && maxevents > numevents)
0498 {
0499 NDRX_LOG(log_debug, "Returning...");
0500
0501 numevents++;
0502
0503 events[numevents-1].data.fd = set->fdtab[i].fd;
0504 events[numevents-1].events = set->fdtab[i].revents;
0505 events[numevents-1].is_mqd = EXFAIL;
0506 }
0507 }
0508
0509 out:
0510
0511 NDRX_LOG(log_info, "%s ret=%d numevents=%d", fn, ret, numevents);
0512
0513 if (EXSUCCEED==ret)
0514 {
0515 return numevents;
0516 }
0517 else
0518 {
0519 return EXFAIL;
0520 }
0521 }
0522
0523
0524
0525
0526
0527 expublic int ndrx_epoll_errno(void)
0528 {
0529 NSTD_TLS_ENTRY;
0530 return G_nstd_tls->M_last_err;
0531 }
0532
0533
0534
0535
0536
0537
0538 expublic char * ndrx_poll_strerror(int err)
0539 {
0540 NSTD_TLS_ENTRY;
0541
0542 sprintf(G_nstd_tls->poll_strerr, "%s (last error: %s)",
0543 strerror(err), G_nstd_tls->M_last_err_msg);
0544
0545 return G_nstd_tls->poll_strerr;
0546 }
0547
0548