Пример #1
0
static int sock_send_msg(lua_State *L, int index, int sock, ringbuffer_t *rb, copy_context_t *copy_context) {
   ringbuffer_push_write_pos(rb);
   int ret = rb_save(L, index, rb, 1);
   if (ret) return LUA_HANDLE_ERROR(L, ret);
   size_t len = ringbuffer_peek(rb);
   ringbuffer_pop_write_pos(rb);
   if (ret) return ret;
   ret = sock_send(sock, &len, sizeof(len), copy_context);
   if (ret < 0) return LUA_HANDLE_ERROR(L, errno);
   if (ret != sizeof(len)) return LUA_HANDLE_ERROR_STR(L, "failed to send the correct number of bytes");
   ret = sock_send(sock, ringbuffer_buf_ptr(rb), len, copy_context);
   if (ret < 0) return LUA_HANDLE_ERROR(L, errno);
   if ((size_t)ret != len) return LUA_HANDLE_ERROR_STR(L, "failed to send the correct number of bytes");
   return 0;
}
Пример #2
0
int workqueue_drain(lua_State *L) {
   context_t *context = (context_t *)lua_touserdata(L, 1);
   workqueue_t *workqueue = context->workqueue;
   if (!workqueue) return LUA_HANDLE_ERROR_STR(L, "workqueue is not open");
   if (workqueue->owner_thread != pthread_self()) return LUA_HANDLE_ERROR_STR(L, "workqueue drain is only available on the owner thread");
   pthread_mutex_lock(&workqueue->questions.mutex);
   pthread_mutex_lock(&workqueue->answers.mutex);
   uint32_t mark = workqueue->answers.num_items + workqueue->questions.num_items;
   pthread_mutex_unlock(&workqueue->questions.mutex);
   while (workqueue->answers.num_items < mark) {
      pthread_cond_wait(&workqueue->answers.read_avail_cond, &workqueue->answers.mutex);
   }
   pthread_mutex_unlock(&workqueue->answers.mutex);
   return 0;
}
Пример #3
0
int map_join(lua_State *L) {
   int rc = 0;
   int err_rc = -1;
   map_t *map = (map_t *)lua_touserdata(L, 1);
   for (uint32_t i = 0; i < map->num_threads; i++) {
      if (map->threads[i].rb) {
         int ret = pthread_join(map->threads[i].thread, NULL);
         if (ret) return LUA_HANDLE_ERROR(L, ret);
         if (map->threads[i].ret) {
            err_rc = rc;
         }
         while (ringbuffer_peek(map->threads[i].rb)) {
            rb_load(L, map->threads[i].rb);
            rc++;
         }
         ringbuffer_destroy(map->threads[i].rb);
      }
   }
   free(map->threads);
   map->threads = NULL;
   map->num_threads = 0;
   if (err_rc >= 0) {
      return LUA_HANDLE_ERROR_STR(L, lua_tostring(L, err_rc - rc));
   }
   return rc;
}
Пример #4
0
int map_open(lua_State *L) {
   uint32_t num_threads = lua_tonumber(L, 1);
   if (lua_type(L, 2) != LUA_TFUNCTION) return LUA_HANDLE_ERROR_STR(L, "map arg #2 expected a function");
   map_thread_t *threads = (map_thread_t *)calloc(num_threads, sizeof(map_thread_t));
   int k = lua_gettop(L);
   for (uint32_t i = 0; i < num_threads; i++) {
      threads[i].rb = ringbuffer_create(MAX_ARG_SIZE);
      for (int j = 2; j <= k; j++) {
         int ret = rb_save_with_growth(L, j, threads[i].rb);
         if (ret) return LUA_HANDLE_ERROR(L, ret);
      }
      lua_pushinteger(L, i + 1);
      int ret = rb_save_with_growth(L, k + 1, threads[i].rb);
      if (ret) return LUA_HANDLE_ERROR(L, ret);
      lua_pop(L, 1);
      ret = pthread_create(&threads[i].thread, NULL, thread_func, &threads[i]);
      if (ret) return LUA_HANDLE_ERROR(L, ret);
   }
   map_t *map = (map_t *)lua_newuserdata(L, sizeof(map_t));
   map->num_threads = num_threads;
   map->threads = threads;
   luaL_getmetatable(L, "ipc.map");
   lua_setmetatable(L, -2);
   return 1;
}
Пример #5
0
int cliser_server_client_close(lua_State *L) {
   server_client_t *server_client = (server_client_t *)lua_touserdata(L, 1);
   if (server_client->client == NULL) return LUA_HANDLE_ERROR_STR(L, "server client is invalid, either closed or used outside of server function scope");
   remove_client(server_client->server, server_client->client);
   destroy_client(L, server_client->client);
   server_client->server = NULL;
   server_client->client = NULL;
   return 0;
}
Пример #6
0
static int sock_recv_msg(lua_State *L, int sock, ringbuffer_t *rb, copy_context_t *copy_context) {
   size_t len;
   int ret = sock_recv(sock, &len, sizeof(len), copy_context);
   if (ret < 0) return LUA_HANDLE_ERROR(L, errno);
   if (ret != sizeof(len)) return LUA_HANDLE_ERROR_STR(L, "failed to recv the correct number of bytes");
   if (len > SEND_RECV_SIZE) return LUA_HANDLE_ERROR_STR(L, "message size is too large");
   ret = sock_recv(sock, ringbuffer_buf_ptr(rb), len, copy_context);
   if (ret < 0) return LUA_HANDLE_ERROR(L, errno);
   if ((size_t)ret != len) return LUA_HANDLE_ERROR_STR(L, "failed to recv the correct number of bytes");
   ringbuffer_reset_read_pos(rb);
   ringbuffer_push_write_pos(rb);
   if (ringbuffer_write(rb, NULL, ret) != (size_t)ret) {
      ringbuffer_pop_write_pos(rb);
      return LUA_HANDLE_ERROR_STR(L, "failed to write the correct number of bytes into the ringbuffer");
   }
   ret = rb_load(L, rb);
   if (ret < 0) return LUA_HANDLE_ERROR(L, ret);
   return ret;
}
Пример #7
0
int cliser_server_id(lua_State *L) {
   server_client_t *server_client = (server_client_t *)lua_touserdata(L, 1);
   if (server_client->client == NULL) return LUA_HANDLE_ERROR_STR(L, "server client is invalid, either closed or used outside of server function scope");
   if (lua_gettop(L) > 1) {
      server_client->client->id = lua_tointeger(L, 2);
      return 0;
   }
   lua_pushinteger(L, server_client->client->id);
   return 1;
}
Пример #8
0
int workqueue_write(lua_State *L) {
   context_t *context = (context_t *)lua_touserdata(L, 1);
   workqueue_t *workqueue = context->workqueue;
   if (!workqueue) return LUA_HANDLE_ERROR_STR(L, "workqueue is not open");
   if (workqueue->owner_thread == pthread_self()) {
      return workqueue_queue_write(L, 2, &workqueue->questions);
   } else {
      return workqueue_queue_write(L, 2, &workqueue->answers);
   }
}
Пример #9
0
int workqueue_read(lua_State *L) {
   context_t *context = (context_t *)lua_touserdata(L, 1);
   workqueue_t *workqueue = context->workqueue;
   if (!workqueue) return LUA_HANDLE_ERROR_STR(L, "workqueue is not open");
   int doNotBlock = luaT_optboolean(L, 2, 0);
   if (workqueue->owner_thread == pthread_self()) {
      return workqueue_queue_read(L, &workqueue->answers, doNotBlock);
   } else {
      return workqueue_queue_read(L, &workqueue->questions, doNotBlock);
   }
}
Пример #10
0
static int sock_recv_userdata(lua_State *L, int index, int sock, copy_context_t *copy_context) {
   if (!luaL_getmetafield(L, index, "_cliser_read")) return LUA_HANDLE_ERROR_STR(L, "could not find _cliser_read function in metatable");
   lua_pushvalue(L, index);
   lua_pushinteger(L, sock);
   lua_pushlightuserdata(L, copy_context);
   if (lua_type(L, index + 1) == LUA_TUSERDATA) {
      lua_pushvalue(L, index + 1);
      lua_call(L, 4, 0);
   } else {
      lua_call(L, 3, 0);
   }
   return 0;
}
Пример #11
0
int map_check_errors(lua_State *L) {
   map_t *map = (map_t *)lua_touserdata(L, 1);
   for (uint32_t i = 0; i < map->num_threads; i++) {
      if (map->threads[i].ret) {
         pthread_join(map->threads[i].thread, NULL);
         while (ringbuffer_peek(map->threads[i].rb)) {
            rb_load(L, map->threads[i].rb);
         }
         ringbuffer_destroy(map->threads[i].rb);
         map->threads[i].rb = NULL;
         return LUA_HANDLE_ERROR_STR(L, lua_tostring(L, -1));
      }
   }
   return 0;
}
Пример #12
0
int cliser_server_send(lua_State *L) {
   double t0 = _ipc_seconds();
   server_client_t *server_client = (server_client_t *)lua_touserdata(L, 1);
   if (server_client->client == NULL) return LUA_HANDLE_ERROR_STR(L, "server client is invalid, either closed or used outside of server function scope");
   int ret;
   if (lua_type(L, 2) == LUA_TUSERDATA) {
      server_client->server->copy_context.use_fastpath = server_client->client->copy_context.use_fastpath;
      ret = sock_send_userdata(L, 2, server_client->client->sock, &server_client->server->copy_context);
   } else {
      ret = sock_send_msg(L, 2, server_client->client->sock, server_client->client->send_rb, &server_client->server->copy_context);
   }
   server_client->server->copy_context.tx.total_seconds += (_ipc_seconds() - t0);
   server_client->server->copy_context.tx.num_calls++;
   return ret;
}
Пример #13
0
int workqueue_close(lua_State *L) {
   context_t *context = (context_t *)lua_touserdata(L, 1);
   workqueue_t *workqueue = context->workqueue;
   if (!workqueue) return LUA_HANDLE_ERROR_STR(L, "workqueue has already been closed");
   pthread_mutex_lock(&workqueue_mutex);
   workqueue->refcount--;
   if (workqueue->refcount == 0) {
      workqueue_remove(workqueue);
      workqueue_destroy_queue(&workqueue->questions);
      workqueue_destroy_queue(&workqueue->answers);
      pthread_mutex_destroy(&workqueue->mutex);
      free((void *)workqueue->name);
   }
   pthread_mutex_unlock(&workqueue_mutex);
   context->workqueue = NULL;
   return 0;
}
Пример #14
0
static int sock_recv_msg_peek(lua_State *L, int sock, ringbuffer_t *rb) {
   size_t len;
   int ret = recv(sock, &len, sizeof(len), MSG_PEEK | MSG_DONTWAIT);
   if (ret < 0) {
      if (errno == EAGAIN || errno == EWOULDBLOCK) return 0;
      return LUA_HANDLE_ERROR(L, errno);
   }
   if (ret != sizeof(len)) return 0;
   if (len > SEND_RECV_SIZE) return LUA_HANDLE_ERROR_STR(L, "message size is too large");
   ret = recv(sock, ringbuffer_buf_ptr(rb), len, MSG_PEEK | MSG_DONTWAIT);
   if (ret < 0) {
      if (errno == EAGAIN || errno == EWOULDBLOCK) return 0;
      return LUA_HANDLE_ERROR(L, errno);
   }
   if ((size_t)ret != len) return 0;
   return ret;
}
Пример #15
0
int cliser_server_tag(lua_State *L) {
   server_client_t *server_client = (server_client_t *)lua_touserdata(L, 1);
   if (server_client->client == NULL) return LUA_HANDLE_ERROR_STR(L, "server client is invalid, either closed or used outside of server function scope");
   const char *tag = luaL_optstring(L, 2, NULL);
   if (!tag) {
      if (server_client->client->tag) {
         lua_pushstring(L, server_client->client->tag);
         return 1;
      }
   } else {
      if (server_client->client->tag) {
         free(server_client->client->tag);
      }
      server_client->client->tag = strdup(tag);
   }
   return 0;
}
Пример #16
0
static int get_sockaddr(lua_State *L, const char *host, const char *port, struct sockaddr *addr, socklen_t *addrlen) {
   struct addrinfo hints;
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = AF_INET;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_protocol = IPPROTO_TCP;
   struct addrinfo *ai;
   int ret = getaddrinfo(host, port, &hints, &ai);
   if (ret) return LUA_HANDLE_ERROR_STR(L, gai_strerror(ret));
   if (*addrlen < ai->ai_addrlen) {
      freeaddrinfo(ai);
      return LUA_HANDLE_ERROR(L, ENOMEM);
   }
   memcpy(addr, ai->ai_addr, ai->ai_addrlen);
   *addrlen = ai->ai_addrlen;
   freeaddrinfo(ai);
   return 0;
}
Пример #17
0
static int workqueue_queue_write(lua_State *L, int index, queue_t *queue) {
   pthread_mutex_lock(&queue->mutex);
   int ret = 0;
   while (1) {
      ringbuffer_push_write_pos(queue->rb);
      ret = rb_save(L, index, queue->rb, 0);
      if (ret) {
         ringbuffer_pop_write_pos(queue->rb);
         if (ringbuffer_peek(queue->rb)) {
            pthread_cond_wait(&queue->write_avail_cond, &queue->mutex);
         } else {
            return LUA_HANDLE_ERROR_STR(L, "workqueue.write message is too big for the ring buffer.");
         }
      } else {
         break;
      }
   }
   queue->num_items++;
   pthread_cond_signal(&queue->read_avail_cond);
   pthread_mutex_unlock(&queue->mutex);
   return ret;
}
Пример #18
0
static int sock_recv_raw(lua_State *L, int sock, void *ptr, size_t len, copy_context_t *copy_context) {
   int ret = sock_recv(sock, ptr, len, copy_context);
   if (ret < 0) return LUA_HANDLE_ERROR(L, errno);
   if ((size_t)ret != len) return LUA_HANDLE_ERROR_STR(L, "failed to recv the correct number of bytes");
   return 0;
}
Пример #19
0
int cliser_server_clients(lua_State *L) {
   server_t *server = (server_t *)lua_touserdata(L, 1);
   uint32_t wait;
   const char *tag;
   int fi;
   int invert_order;
   if (lua_type(L, 2) == LUA_TFUNCTION) {
      wait = 0;
      fi = 2;
      if (lua_type(L, 3) == LUA_TSTRING) {
         tag = luaL_optstring(L, 3, NULL);
         invert_order = luaL_optinteger(L, 4, 0);
      } else {
         tag = NULL;
         invert_order = luaL_optinteger(L, 3, 0);
      }
   } else {
      wait = luaL_checkint(L, 2);
      if (lua_type(L, 3) != LUA_TFUNCTION) return LUA_HANDLE_ERROR_STR(L, "expected a callback function as argument #3");
      fi = 3;
      tag = NULL;
      invert_order = 0;
   }
   while (wait > server->num_clients) {
      struct sockaddr addr;
      socklen_t addrlen = sizeof(addr);
      int ret = accept(server->sock, &addr, &addrlen);
      if (ret <= 0) return LUA_HANDLE_ERROR(L, errno);
      int sock = ret;
      int value = 1;
      ret = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value));
      if (ret) return LUA_HANDLE_ERROR(L, errno);
      int use_fastpath = can_use_fastpath(L, sock, server->ip_address, ((struct sockaddr_in *)&addr)->sin_addr.s_addr);
      client_t *client = (client_t *)calloc(1, sizeof(client_t));
      client->sock = sock;
      client->send_rb = ringbuffer_create(SEND_RECV_SIZE);
      client->recv_rb = ringbuffer_create(SEND_RECV_SIZE);
      client->copy_context.use_fastpath = use_fastpath;
      insert_client(server, client);
   }
   client_t **clients = alloca(server->num_clients * sizeof(client_t*));
   client_t *client = server->clients;
   uint32_t i = 0;
   while (client) {
      if (!tag || (client->tag && strcmp(tag, client->tag) == 0)) {
         clients[i] = client;
         i++;
      }
      client = client->next;
   }
   if (invert_order) {
      qsort(clients, i, sizeof(client_t*), compare_clients_inverted);
   } else {
      qsort(clients, i, sizeof(client_t*), compare_clients);
   }
   for (uint32_t j = 0; j < i; j++) {
      lua_pushvalue(L, fi);
      server_client_t *server_client = (server_client_t *)lua_newuserdata(L, sizeof(server_client_t));
      server_client->server = server;
      server_client->client = clients[j];
      luaL_getmetatable(L, "ipc.server.client");
      lua_setmetatable(L, -2);
      lua_call(L, 1, 0);
      server_client->server = NULL;
      server_client->client = NULL;
   }
   lua_pushinteger(L, i);
   return 1;
}