MXS-1582 Close listener sockets on exit

If the listener socket refers to a Unix domain socket, the socket file
will be deleted as well.
This commit is contained in:
Johan Wikman 2017-12-28 15:31:32 +02:00
parent 6f3a580168
commit 140620a366
3 changed files with 114 additions and 48 deletions

View File

@ -182,6 +182,7 @@ typedef struct dcb
struct dcb *tail; /**< Last DCB in owning thread's list */
} thread;
uint32_t n_close; /** How many times dcb_close has been called. */
char *path; /** If a Unix socket, the path it was bound to. */
skygw_chk_t dcb_chk_tail;
} DCB;

View File

@ -234,6 +234,7 @@ dcb_final_free(DCB *dcb)
if (SESSION_STATE_DUMMY != local_session->state)
{
bool is_client_dcb = (DCB_ROLE_CLIENT_HANDLER == dcb->dcb_role ||
DCB_ROLE_SERVICE_LISTENER == dcb->dcb_role ||
DCB_ROLE_INTERNAL == dcb->dcb_role);
session_put_ref(local_session);
@ -331,6 +332,11 @@ dcb_free_all_memory(DCB *dcb)
SSL_free(dcb->ssl);
}
if (dcb->path)
{
MXS_FREE(dcb->path);
}
// Ensure that id is immediately the wrong one.
dcb->poll.thread.id = 0xdeadbeef;
MXS_FREE(dcb);
@ -1100,10 +1106,17 @@ void dcb_close(DCB *dcb)
{
dcb->n_close = 1;
Worker* worker = Worker::get(dcb->poll.thread.id);
ss_dassert(worker);
if (dcb->dcb_role == DCB_ROLE_SERVICE_LISTENER)
{
dcb_final_close(dcb);
}
else
{
Worker* worker = Worker::get(dcb->poll.thread.id);
ss_dassert(worker);
worker->register_zombie(dcb);
worker->register_zombie(dcb);
}
}
else
{
@ -1220,6 +1233,14 @@ void dcb_final_close(DCB* dcb)
MXS_DEBUG("Closed socket %d on dcb %p.", dcb->fd, dcb);
}
if (dcb->path)
{
if (unlink(dcb->path) != 0)
{
MXS_ERROR("Could not unlink %s: %s", dcb->path, mxs_strerror(errno));
}
}
}
dcb->state = DCB_STATE_DISCONNECTED;
@ -2560,6 +2581,11 @@ int dcb_listen(DCB *listener, const char *config, const char *protocol_name)
if (strchr(host, '/'))
{
listener_socket = dcb_listen_create_socket_unix(host);
if (listener_socket != -1)
{
listener->path = MXS_STRDUP_A(host);
}
}
else if (port > 0)
{
@ -2776,41 +2802,44 @@ void dcb_add_to_list(DCB *dcb)
*/
static void dcb_remove_from_list(DCB *dcb)
{
if (dcb == this_unit.all_dcbs[dcb->poll.thread.id])
if (dcb->dcb_role != DCB_ROLE_SERVICE_LISTENER)
{
DCB *tail = this_unit.all_dcbs[dcb->poll.thread.id]->thread.tail;
this_unit.all_dcbs[dcb->poll.thread.id] = this_unit.all_dcbs[dcb->poll.thread.id]->thread.next;
if (this_unit.all_dcbs[dcb->poll.thread.id])
if (dcb == this_unit.all_dcbs[dcb->poll.thread.id])
{
this_unit.all_dcbs[dcb->poll.thread.id]->thread.tail = tail;
}
}
else
{
DCB *current = this_unit.all_dcbs[dcb->poll.thread.id]->thread.next;
DCB *prev = this_unit.all_dcbs[dcb->poll.thread.id];
DCB *tail = this_unit.all_dcbs[dcb->poll.thread.id]->thread.tail;
this_unit.all_dcbs[dcb->poll.thread.id] = this_unit.all_dcbs[dcb->poll.thread.id]->thread.next;
while (current)
{
if (current == dcb)
if (this_unit.all_dcbs[dcb->poll.thread.id])
{
if (current == this_unit.all_dcbs[dcb->poll.thread.id]->thread.tail)
{
this_unit.all_dcbs[dcb->poll.thread.id]->thread.tail = prev;
}
prev->thread.next = current->thread.next;
break;
this_unit.all_dcbs[dcb->poll.thread.id]->thread.tail = tail;
}
prev = current;
current = current->thread.next;
}
}
else
{
DCB *current = this_unit.all_dcbs[dcb->poll.thread.id]->thread.next;
DCB *prev = this_unit.all_dcbs[dcb->poll.thread.id];
/** Reset the next and tail pointers so that if this DCB is added to the list
* again, it will be in a clean state. */
dcb->thread.next = NULL;
dcb->thread.tail = NULL;
while (current)
{
if (current == dcb)
{
if (current == this_unit.all_dcbs[dcb->poll.thread.id]->thread.tail)
{
this_unit.all_dcbs[dcb->poll.thread.id]->thread.tail = prev;
}
prev->thread.next = current->thread.next;
break;
}
prev = current;
current = current->thread.next;
}
}
/** Reset the next and tail pointers so that if this DCB is added to the list
* again, it will be in a clean state. */
dcb->thread.next = NULL;
dcb->thread.tail = NULL;
}
}
/**

View File

@ -1843,6 +1843,57 @@ void service_shutdown()
spinlock_release(&service_spin);
}
/**
* Destroy a listener
*
* @param sl The listener to destroy.
*
* @return The next listener or NULL if there is not one.
*/
static SERV_LISTENER* service_destroy_listener(SERV_LISTENER* sl)
{
SERV_LISTENER* next = sl->next;
dcb_close(sl->listener);
// TODO: What else should be closed and freed here?
return next;
}
/**
* Destroy one service instance
*
* @param svc The service to destroy.
*/
static void service_destroy_instance(SERVICE* svc)
{
SERV_LISTENER* sl = svc->ports;
while (sl)
{
sl = service_destroy_listener(sl);
}
/* Call destroyInstance hook for routers */
if (svc->router->destroyInstance && svc->router_instance)
{
svc->router->destroyInstance(svc->router_instance);
}
if (svc->n_filters)
{
MXS_FILTER_DEF **filters = svc->filters;
for (int i = 0; i < svc->n_filters; i++)
{
if (filters[i]->obj->destroyInstance && filters[i]->filter)
{
/* Call destroyInstance hook for filters */
filters[i]->obj->destroyInstance(filters[i]->filter);
}
}
}
}
void service_destroy_instances(void)
{
spinlock_acquire(&service_spin);
@ -1850,23 +1901,8 @@ void service_destroy_instances(void)
while (svc != NULL)
{
ss_dassert(svc->svc_do_shutdown);
/* Call destroyInstance hook for routers */
if (svc->router->destroyInstance && svc->router_instance)
{
svc->router->destroyInstance(svc->router_instance);
}
if (svc->n_filters)
{
MXS_FILTER_DEF **filters = svc->filters;
for (int i = 0; i < svc->n_filters; i++)
{
if (filters[i]->obj->destroyInstance && filters[i]->filter)
{
/* Call destroyInstance hook for filters */
filters[i]->obj->destroyInstance(filters[i]->filter);
}
}
}
service_destroy_instance(svc);
svc = svc->next;
}
spinlock_release(&service_spin);