[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[Libevent-users] Does bufferevent_openssl_socket_new() API support multi-thread?



Hi all.
Does bufferevent_openssl_socket_new() API support multi-thread?
I refer the sample of regress_ssl.c in the libevent source package, and write an SSL server with multi-thread.
But it is deadlock after receive the first message from client.
Anyone have idea? 
Thanks!

Brian

==

Here is the function stack at last:

(gdb) thread apply all bt

Thread 2 (Thread 0x40a00940 (LWP 30815)):
#0  0x00000034bbe0aee9 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x00002aaaaacfdf7e in evthread_posix_cond_wait (_cond=0x6039a0, _lock=0x603520, tv=0x0) at evthread_pthread.c:164
#2  0x00002aaaaaabdfc7 in event_del_internal (ev=0x6a2308) at event.c:2142
#3  0x00002aaaaaabde47 in event_del (ev=0x6a2308) at event.c:2110
#4  0x00002aaaaaf01f32 in consider_writing (bev_ssl=0x6a2270) at bufferevent_openssl.c:780
#5  0x00002aaaaaf027de in be_openssl_outbuf_cb (buf=0x6a2550, cbinfo=0x409ffff0, arg=0x6a2270) at bufferevent_openssl.c:1013
#6  0x00002aaaaaac141d in evbuffer_run_callbacks (buffer=0x6a2550, running_deferred=0) at buffer.c:443
#7  0x00002aaaaaac1f88 in evbuffer_invoke_callbacks (buffer=0x6a2550) at buffer.c:460
#8  0x00002aaaaaac4532 in evbuffer_add (buf=0x6a2550, data_in=0x401a78, datlen=94) at buffer.c:1557
#9  0x00002aaaaaac8238 in bufferevent_write (bufev=0x6a2270, data="" size=94) at bufferevent.c:376
#10 0x0000000000401330 in thread_write (arg=0x0) at bev_ssl.c:29
#11 0x00000034bbe0673d in start_thread () from /lib64/libpthread.so.0
#12 0x00000034bb6d3f6d in clone () from /lib64/libc.so.6

Thread 1 (Thread 0x2aaaab11ddd0 (LWP 30812)):
#0  0x00000034bbe0d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
#1  0x00000034bbe08e35 in _L_lock_1127 () from /lib64/libpthread.so.0
#2  0x00000034bbe08d33 in pthread_mutex_lock () from /lib64/libpthread.so.0
#3  0x00002aaaaacfdd56 in evthread_posix_lock (mode=0, _lock=0x624070) at evthread_pthread.c:78
#4  0x00002aaaaaac88f5 in _bufferevent_incref_and_lock (bufev=0x6a2270) at bufferevent.c:561
#5  0x00002aaaaaf020a6 in be_openssl_writeeventcb (fd=11, what=4, ptr=0x6a2270) at bufferevent_openssl.c:842
#6  0x00002aaaaaabb68f in event_persist_closure (base=0x6035a0, ev=0x6a2308) at event.c:1238
#7  0x00002aaaaaabb281 in event_process_active_single_queue (base=0x6035a0, activeq=0x603500) at event.c:1282
#8  0x00002aaaaaabb852 in event_process_active (base=0x6035a0) at event.c:1354
#9  0x00002aaaaaabbe48 in event_base_loop (base=0x6035a0, flags=0) at event.c:1551
#10 0x00002aaaaaabb8cd in event_base_dispatch (event_base=0x6035a0) at event.c:1382
#11 0x00000000004016e7 in main () at bev_ssl.c:176

==

Here is my code:

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <event.h>
#include <event2/listener.h>
#include <event2/bufferevent_ssl.h>
#include <event2/thread.h>
#include <openssl/ssl.h>
#include <pthread.h>

#include "const.h"
#include "bev.h"
#include "ssl.h"

struct event_base   *evbase;
SSL_CTX             *g_ssl_ctx = NULL;
struct bufferevent  *bev = NULL;
int                 flag = 0;

void *thread_write(void *arg)
{
    while (1) {
        if (flag) {
            if (bev != NULL) {
                bufferevent_write(bev, RESPONSE, strlen(RESPONSE));
            }
            
            flag = 0;
        }
        usleep(1000 * 1000 * 0.1);
    }
}

/*
 * read_cb()
 */
static void read_cb(struct bufferevent *bev, void *arg)
{
  char buff[BUFF_SIZE] = {0};  // tmp buff

  /* Read data */
  memset(buff, 0, sizeof(buff));
  bufferevent_read(bev, buff, sizeof(buff));
  
  fprintf(stderr, "Recv[%s]\n", buff);
  flag = 1;
}

/*
 * event_cb()
 */
static void event_cb(struct bufferevent *bev, short events, void *arg)
{
  if (events & BEV_EVENT_CONNECTED) {
    /* Do nothing here. */
    fprintf(stderr, "events[BEV_EVENT_CONNECTED]\n");
  } else {
    fprintf(stderr, "events[%d]\n", events);
    
    /* Close conn. */
    bufferevent_free(bev);
    bev = NULL;
  }
}

/*
 * accept_cb()
 */
static void accept_cb(struct evconnlistener *lev,
                       evutil_socket_t fd, struct sockaddr *sa,
                       int socklen, void *ctx)
{
  SSL  *ssl;

  if ((ssl = SSL_new(g_ssl_ctx)) == NULL) {
    goto err_ret;
  }
  
  /* Create security socket-based buffer event. */
  if ((bev = bufferevent_openssl_socket_new(evbase, fd, ssl, 
                                            BUFFEREVENT_SSL_ACCEPTING, 
                                            BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE))
      == NULL) {
    fprintf(stderr, "Cannot create bufferevent control socket");
    goto err_ret;
  }

  /* Set up callback functions. */
  bufferevent_setcb(bev, read_cb, NULL, event_cb, NULL);

  /* Enable read/write event. */
  bufferevent_enable(bev, EV_READ | EV_WRITE);
  
  return;

err_ret:
  evutil_closesocket(fd);
}

/*
 * server_init()
 */
int server_init()
{
  struct sockaddr_in    sin;            // connection address
  uint32_t              flags;          // socket options
  struct evconnlistener *lev;

  /* Set up connection address. */
  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = inet_addr(SVR_IP);
  sin.sin_port = htons(SVR_PORT);

  /* Bind listen socket. */
  flags = (LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_THREADSAFE);
  lev = evconnlistener_new_bind(evbase, accept_cb, NULL,
                                flags, -1,
                                (struct sockaddr *)&sin, sizeof(sin));

  return(lev ? 0 : -1);
}


/*
 * main()
 */
int main(void)
{
  pthread_t   tid;

  /* Set up libevent to work with pthread. */
  if (evthread_use_pthreads() < 0) {
    fprintf(stderr, "evthread_use_pthreads() fail\n");
    return -1;
  }
  
  /* Initialize event base. */
  if ((evbase = event_base_new()) == NULL) {
    DEBUG("Cannot create event base\n");
    return -1;
  }
  
  /* Allow other thread to wake up event base. */
  if (evthread_make_base_notifiable(evbase) < 0) {
    fprintf(stderr, "Cannot make event base notifiable");
    return -1;
  }

  /* Init. SSL */
  if (init_ssl() != 0) {
    fprintf(stderr, "Cannot init SSL\n");
    return -1;
  }
  
  /* Thread init */
  if (pthread_create(&tid, NULL, thread_write, NULL) != 0) {
    fprintf(stderr, "pthread_create() failed\n");
    return -1;
  }
  
  /* Set listener */
  if (server_init() != 0) {
    DEBUG("Cannot init server\n");
    return -1;
  }
  
  /*
   * Event loop
   */
  event_base_dispatch(evbase);

  /* End of program */
  SSL_CTX_free(g_ssl_ctx);
  
  return 0;
}