mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-30 00:00:16 +01:00
extpoll use hashtable for fd tracking
This implements a much faster, hashtable-based tracking scheme for external poll fds. Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
parent
29da6d9443
commit
5fc460cd41
1 changed files with 114 additions and 24 deletions
|
@ -25,6 +25,7 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "../lib/libwebsockets.h"
|
#include "../lib/libwebsockets.h"
|
||||||
|
|
||||||
|
@ -37,9 +38,47 @@ static int close_testing;
|
||||||
#else
|
#else
|
||||||
#define MAX_POLL_ELEMENTS (MAX_CLIENTS)
|
#define MAX_POLL_ELEMENTS (MAX_CLIENTS)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct poll_hash_map {
|
||||||
|
int fd;
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define POLL_HASH_BITS 8
|
||||||
|
|
||||||
|
#define POLL_HASH_BUCKETS (1 << POLL_HASH_BITS)
|
||||||
|
#define POLL_ENTRIES_PER_BUCKET (MAX_POLL_ELEMENTS / (1 << (POLL_HASH_BITS - 2)))
|
||||||
|
#define POLL_HASH(num) (num & (POLL_HASH_BUCKETS - 1))
|
||||||
|
|
||||||
struct pollfd pollfds[MAX_POLL_ELEMENTS];
|
struct pollfd pollfds[MAX_POLL_ELEMENTS];
|
||||||
|
struct poll_hash_map pollfd_maps[POLL_HASH_BUCKETS][POLL_ENTRIES_PER_BUCKET];
|
||||||
|
int pollfd_count[POLL_HASH_BUCKETS];
|
||||||
int count_pollfds = 0;
|
int count_pollfds = 0;
|
||||||
#endif
|
|
||||||
|
static int find_poll_map_index(int hash, int fd)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n = 0; n < pollfd_count[hash]; n++)
|
||||||
|
if (pollfd_maps[hash][n].fd == fd)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_pollfd_index(int fd)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
int hash = POLL_HASH(fd);
|
||||||
|
|
||||||
|
n = find_poll_map_index(hash, fd);
|
||||||
|
if (n < 0)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
return pollfd_maps[hash][n].index;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* EXTERNAL_POLL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This demo server shows how to use libwebsockets for one or more
|
* This demo server shows how to use libwebsockets for one or more
|
||||||
|
@ -80,7 +119,9 @@ static int callback_http(struct libwebsocket_context *context,
|
||||||
char client_name[128];
|
char client_name[128];
|
||||||
char client_ip[128];
|
char client_ip[128];
|
||||||
#ifdef EXTERNAL_POLL
|
#ifdef EXTERNAL_POLL
|
||||||
int n;
|
int n, m, m1;
|
||||||
|
int hash, hash1;
|
||||||
|
int fd = (int)(long)user;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
|
@ -139,8 +180,20 @@ static int callback_http(struct libwebsocket_context *context,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case LWS_CALLBACK_ADD_POLL_FD:
|
case LWS_CALLBACK_ADD_POLL_FD:
|
||||||
if (count_pollfds == MAX_POLL_ELEMENTS)
|
if (count_pollfds == MAX_POLL_ELEMENTS) {
|
||||||
|
fprintf(stderr, "LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
hash = POLL_HASH(fd);
|
||||||
|
if (pollfd_count[hash] == POLL_ENTRIES_PER_BUCKET) {
|
||||||
|
fprintf(stderr, "LWS_CALLBACK_ADD_POLL_FD: hash table overflow\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fprintf(stderr, "Adding fd %d at pollfd_maps[%d][%d], pollfds[%d]\n", fd, hash, pollfd_count[hash], count_pollfds);
|
||||||
|
|
||||||
|
pollfd_maps[hash][pollfd_count[hash]].fd = fd;
|
||||||
|
pollfd_maps[hash][pollfd_count[hash]++].index = count_pollfds;
|
||||||
|
|
||||||
pollfds[count_pollfds].fd = (int)(long)user;
|
pollfds[count_pollfds].fd = (int)(long)user;
|
||||||
pollfds[count_pollfds].events = (int)len;
|
pollfds[count_pollfds].events = (int)len;
|
||||||
|
@ -148,34 +201,71 @@ static int callback_http(struct libwebsocket_context *context,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LWS_CALLBACK_DEL_POLL_FD:
|
case LWS_CALLBACK_DEL_POLL_FD:
|
||||||
for (n = 0; n < count_pollfds; n++) {
|
hash = POLL_HASH(fd);
|
||||||
if (pollfds[n].fd != (int)(long)user)
|
n = find_poll_map_index(hash, fd);
|
||||||
continue;
|
if (n < 0) {
|
||||||
|
fprintf(stderr, "unable to find fd %d in poll_maps\n", fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
m = pollfd_maps[hash][n].index;
|
||||||
|
|
||||||
|
assert(pollfds[m].fd == fd);
|
||||||
|
assert(count_pollfds);
|
||||||
|
assert(pollfd_count[hash]);
|
||||||
|
|
||||||
|
// fprintf(stderr, "Removing fd %d at pollfd_maps[%d][%d], pollfds[%d]\n", fd, hash, n, m);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* swap the end guy into our vacant slot...
|
* swap the end guy into our vacant slot...
|
||||||
* works ok if n is the end guy
|
* works ok if n is the end guy
|
||||||
*/
|
*/
|
||||||
pollfds[n] = pollfds[count_pollfds - 1];
|
|
||||||
pollfds[count_pollfds - 1].fd = -1;
|
|
||||||
count_pollfds--;
|
count_pollfds--;
|
||||||
break;
|
if (count_pollfds) {
|
||||||
|
|
||||||
|
/* end guy... */
|
||||||
|
hash1 = POLL_HASH(pollfds[count_pollfds].fd);
|
||||||
|
m1 = find_poll_map_index(hash1, pollfds[count_pollfds].fd);
|
||||||
|
/* your index has changed... */
|
||||||
|
pollfd_maps[hash1][m1].index = m;
|
||||||
|
|
||||||
|
pollfds[m] = pollfds[count_pollfds];
|
||||||
|
pollfds[count_pollfds].fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* similar trick with hashtable
|
||||||
|
* old end guy goes into vacant slot in hash table
|
||||||
|
*/
|
||||||
|
|
||||||
|
pollfd_count[hash]--;
|
||||||
|
if (pollfd_count[hash]) {
|
||||||
|
pollfd_maps[hash][n].index = pollfd_maps[hash][pollfd_count[hash]].index;
|
||||||
|
pollfd_maps[hash][n].fd = pollfd_maps[hash][pollfd_count[hash]].fd;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LWS_CALLBACK_SET_MODE_POLL_FD:
|
case LWS_CALLBACK_SET_MODE_POLL_FD:
|
||||||
for (n = 0; n < count_pollfds; n++)
|
n = find_pollfd_index(fd);
|
||||||
if (pollfds[n].fd == (int)(long)user) {
|
if (n < 0) {
|
||||||
pollfds[n].events |= (int)(long)len;
|
fprintf(stderr, "unable to find fd %d\n", fd);
|
||||||
break;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if(pollfds[n].fd != fd) {
|
||||||
|
fprintf(stderr, "Setting fd %d, found at pollfd_index %d, actually fd %d\n", fd, n, pollfds[n].fd);
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
pollfds[n].events |= (int)(long)len;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
|
case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
|
||||||
for (n = 0; n < count_pollfds; n++)
|
n = find_pollfd_index(fd);
|
||||||
if (pollfds[n].fd == (int)(long)user) {
|
if (n < 0) {
|
||||||
pollfds[n].events &= ~(int)(long)len;
|
fprintf(stderr, "unable to find fd %d\n", fd);
|
||||||
break;
|
return 1;
|
||||||
}
|
}
|
||||||
|
assert(pollfds[n].fd == fd);
|
||||||
|
pollfds[n].events &= ~(int)(long)len;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Add table
Reference in a new issue