forked from Minki/linux
Merge branch 'akpm' (Fixes from Andrew)
Merge misc fixes from Andrew Morton: "Five fixes" * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (5 patches) h8300: add missing L1_CACHE_SHIFT mm: bugfix: set current->reclaim_state to NULL while returning from kswapd() fanotify: fix missing break revert "epoll: support for disabling items, and a self-test app" checkpatch: improve network block comment style checking
This commit is contained in:
commit
ce6d841e9c
@ -2,7 +2,8 @@
|
|||||||
#define __ARCH_H8300_CACHE_H
|
#define __ARCH_H8300_CACHE_H
|
||||||
|
|
||||||
/* bytes per L1 cache line */
|
/* bytes per L1 cache line */
|
||||||
#define L1_CACHE_BYTES 4
|
#define L1_CACHE_SHIFT 2
|
||||||
|
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
|
||||||
|
|
||||||
/* m68k-elf-gcc 2.95.2 doesn't like these */
|
/* m68k-elf-gcc 2.95.2 doesn't like these */
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ static inline struct epitem *ep_item_from_epqueue(poll_table *p)
|
|||||||
/* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
|
/* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
|
||||||
static inline int ep_op_has_event(int op)
|
static inline int ep_op_has_event(int op)
|
||||||
{
|
{
|
||||||
return op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD;
|
return op != EPOLL_CTL_DEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the poll safe wake up structure */
|
/* Initialize the poll safe wake up structure */
|
||||||
@ -676,34 +676,6 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Disables a "struct epitem" in the eventpoll set. Returns -EBUSY if the item
|
|
||||||
* had no event flags set, indicating that another thread may be currently
|
|
||||||
* handling that item's events (in the case that EPOLLONESHOT was being
|
|
||||||
* used). Otherwise a zero result indicates that the item has been disabled
|
|
||||||
* from receiving events. A disabled item may be re-enabled via
|
|
||||||
* EPOLL_CTL_MOD. Must be called with "mtx" held.
|
|
||||||
*/
|
|
||||||
static int ep_disable(struct eventpoll *ep, struct epitem *epi)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&ep->lock, flags);
|
|
||||||
if (epi->event.events & ~EP_PRIVATE_BITS) {
|
|
||||||
if (ep_is_linked(&epi->rdllink))
|
|
||||||
list_del_init(&epi->rdllink);
|
|
||||||
/* Ensure ep_poll_callback will not add epi back onto ready
|
|
||||||
list: */
|
|
||||||
epi->event.events &= EP_PRIVATE_BITS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = -EBUSY;
|
|
||||||
spin_unlock_irqrestore(&ep->lock, flags);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ep_free(struct eventpoll *ep)
|
static void ep_free(struct eventpoll *ep)
|
||||||
{
|
{
|
||||||
struct rb_node *rbp;
|
struct rb_node *rbp;
|
||||||
@ -1048,6 +1020,8 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
|
|||||||
rb_insert_color(&epi->rbn, &ep->rbr);
|
rb_insert_color(&epi->rbn, &ep->rbr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define PATH_ARR_SIZE 5
|
#define PATH_ARR_SIZE 5
|
||||||
/*
|
/*
|
||||||
* These are the number paths of length 1 to 5, that we are allowing to emanate
|
* These are the number paths of length 1 to 5, that we are allowing to emanate
|
||||||
@ -1813,12 +1787,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
|||||||
} else
|
} else
|
||||||
error = -ENOENT;
|
error = -ENOENT;
|
||||||
break;
|
break;
|
||||||
case EPOLL_CTL_DISABLE:
|
|
||||||
if (epi)
|
|
||||||
error = ep_disable(ep, epi);
|
|
||||||
else
|
|
||||||
error = -ENOENT;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
mutex_unlock(&ep->mtx);
|
mutex_unlock(&ep->mtx);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
|
|||||||
if ((old->path.mnt == new->path.mnt) &&
|
if ((old->path.mnt == new->path.mnt) &&
|
||||||
(old->path.dentry == new->path.dentry))
|
(old->path.dentry == new->path.dentry))
|
||||||
return true;
|
return true;
|
||||||
|
break;
|
||||||
case (FSNOTIFY_EVENT_NONE):
|
case (FSNOTIFY_EVENT_NONE):
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#define EPOLL_CTL_ADD 1
|
#define EPOLL_CTL_ADD 1
|
||||||
#define EPOLL_CTL_DEL 2
|
#define EPOLL_CTL_DEL 2
|
||||||
#define EPOLL_CTL_MOD 3
|
#define EPOLL_CTL_MOD 3
|
||||||
#define EPOLL_CTL_DISABLE 4
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Request the handling of system wakeup events so as to prevent system suspends
|
* Request the handling of system wakeup events so as to prevent system suspends
|
||||||
|
@ -3017,6 +3017,8 @@ static int kswapd(void *p)
|
|||||||
&balanced_classzone_idx);
|
&balanced_classzone_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current->reclaim_state = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1890,8 +1890,10 @@ sub process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($realfile =~ m@^(drivers/net/|net/)@ &&
|
if ($realfile =~ m@^(drivers/net/|net/)@ &&
|
||||||
$rawline !~ m@^\+[ \t]*(\/\*|\*\/)@ &&
|
$rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */
|
||||||
$rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) {
|
$rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/
|
||||||
|
$rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/
|
||||||
|
$rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */
|
||||||
WARN("NETWORKING_BLOCK_COMMENT_STYLE",
|
WARN("NETWORKING_BLOCK_COMMENT_STYLE",
|
||||||
"networking block comments put the trailing */ on a separate line\n" . $herecurr);
|
"networking block comments put the trailing */ on a separate line\n" . $herecurr);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug epoll
|
TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug
|
||||||
|
|
||||||
all:
|
all:
|
||||||
for TARGET in $(TARGETS); do \
|
for TARGET in $(TARGETS); do \
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
# Makefile for epoll selftests
|
|
||||||
|
|
||||||
all: test_epoll
|
|
||||||
%: %.c
|
|
||||||
gcc -pthread -g -o $@ $^
|
|
||||||
|
|
||||||
run_tests: all
|
|
||||||
./test_epoll
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) test_epoll
|
|
@ -1,344 +0,0 @@
|
|||||||
/*
|
|
||||||
* tools/testing/selftests/epoll/test_epoll.c
|
|
||||||
*
|
|
||||||
* Copyright 2012 Adobe Systems Incorporated
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Paton J. Lewis <palewis@adobe.com>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/epoll.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A pointer to an epoll_item_private structure will be stored in the epoll
|
|
||||||
* item's event structure so that we can get access to the epoll_item_private
|
|
||||||
* data after calling epoll_wait:
|
|
||||||
*/
|
|
||||||
struct epoll_item_private {
|
|
||||||
int index; /* Position of this struct within the epoll_items array. */
|
|
||||||
int fd;
|
|
||||||
uint32_t events;
|
|
||||||
pthread_mutex_t mutex; /* Guards the following variables... */
|
|
||||||
int stop;
|
|
||||||
int status; /* Stores any error encountered while handling item. */
|
|
||||||
/* The following variable allows us to test whether we have encountered
|
|
||||||
a problem while attempting to cancel and delete the associated
|
|
||||||
event. When the test program exits, 'deleted' should be exactly
|
|
||||||
one. If it is greater than one, then the failed test reflects a real
|
|
||||||
world situation where we would have tried to access the epoll item's
|
|
||||||
private data after deleting it: */
|
|
||||||
int deleted;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct epoll_item_private *epoll_items;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete the specified item from the epoll set. In a real-world secneario this
|
|
||||||
* is where we would free the associated data structure, but in this testing
|
|
||||||
* environment we retain the structure so that we can test for double-deletion:
|
|
||||||
*/
|
|
||||||
void delete_item(int index)
|
|
||||||
{
|
|
||||||
__sync_fetch_and_add(&epoll_items[index].deleted, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A pointer to a read_thread_data structure will be passed as the argument to
|
|
||||||
* each read thread:
|
|
||||||
*/
|
|
||||||
struct read_thread_data {
|
|
||||||
int stop;
|
|
||||||
int status; /* Indicates any error encountered by the read thread. */
|
|
||||||
int epoll_set;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The function executed by the read threads:
|
|
||||||
*/
|
|
||||||
void *read_thread_function(void *function_data)
|
|
||||||
{
|
|
||||||
struct read_thread_data *thread_data =
|
|
||||||
(struct read_thread_data *)function_data;
|
|
||||||
struct epoll_event event_data;
|
|
||||||
struct epoll_item_private *item_data;
|
|
||||||
char socket_data;
|
|
||||||
|
|
||||||
/* Handle events until we encounter an error or this thread's 'stop'
|
|
||||||
condition is set: */
|
|
||||||
while (1) {
|
|
||||||
int result = epoll_wait(thread_data->epoll_set,
|
|
||||||
&event_data,
|
|
||||||
1, /* Number of desired events */
|
|
||||||
1000); /* Timeout in ms */
|
|
||||||
if (result < 0) {
|
|
||||||
/* Breakpoints signal all threads. Ignore that while
|
|
||||||
debugging: */
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
thread_data->status = errno;
|
|
||||||
return 0;
|
|
||||||
} else if (thread_data->stop)
|
|
||||||
return 0;
|
|
||||||
else if (result == 0) /* Timeout */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* We need the mutex here because checking for the stop
|
|
||||||
condition and re-enabling the epoll item need to be done
|
|
||||||
together as one atomic operation when EPOLL_CTL_DISABLE is
|
|
||||||
available: */
|
|
||||||
item_data = (struct epoll_item_private *)event_data.data.ptr;
|
|
||||||
pthread_mutex_lock(&item_data->mutex);
|
|
||||||
|
|
||||||
/* Remove the item from the epoll set if we want to stop
|
|
||||||
handling that event: */
|
|
||||||
if (item_data->stop)
|
|
||||||
delete_item(item_data->index);
|
|
||||||
else {
|
|
||||||
/* Clear the data that was written to the other end of
|
|
||||||
our non-blocking socket: */
|
|
||||||
do {
|
|
||||||
if (read(item_data->fd, &socket_data, 1) < 1) {
|
|
||||||
if ((errno == EAGAIN) ||
|
|
||||||
(errno == EWOULDBLOCK))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
goto error_unlock;
|
|
||||||
}
|
|
||||||
} while (item_data->events & EPOLLET);
|
|
||||||
|
|
||||||
/* The item was one-shot, so re-enable it: */
|
|
||||||
event_data.events = item_data->events;
|
|
||||||
if (epoll_ctl(thread_data->epoll_set,
|
|
||||||
EPOLL_CTL_MOD,
|
|
||||||
item_data->fd,
|
|
||||||
&event_data) < 0)
|
|
||||||
goto error_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&item_data->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
error_unlock:
|
|
||||||
thread_data->status = item_data->status = errno;
|
|
||||||
pthread_mutex_unlock(&item_data->mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A pointer to a write_thread_data structure will be passed as the argument to
|
|
||||||
* the write thread:
|
|
||||||
*/
|
|
||||||
struct write_thread_data {
|
|
||||||
int stop;
|
|
||||||
int status; /* Indicates any error encountered by the write thread. */
|
|
||||||
int n_fds;
|
|
||||||
int *fds;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The function executed by the write thread. It writes a single byte to each
|
|
||||||
* socket in turn until the stop condition for this thread is set. If writing to
|
|
||||||
* a socket would block (i.e. errno was EAGAIN), we leave that socket alone for
|
|
||||||
* the moment and just move on to the next socket in the list. We don't care
|
|
||||||
* about the order in which we deliver events to the epoll set. In fact we don't
|
|
||||||
* care about the data we're writing to the pipes at all; we just want to
|
|
||||||
* trigger epoll events:
|
|
||||||
*/
|
|
||||||
void *write_thread_function(void *function_data)
|
|
||||||
{
|
|
||||||
const char data = 'X';
|
|
||||||
int index;
|
|
||||||
struct write_thread_data *thread_data =
|
|
||||||
(struct write_thread_data *)function_data;
|
|
||||||
while (!thread_data->stop)
|
|
||||||
for (index = 0;
|
|
||||||
!thread_data->stop && (index < thread_data->n_fds);
|
|
||||||
++index)
|
|
||||||
if ((write(thread_data->fds[index], &data, 1) < 1) &&
|
|
||||||
(errno != EAGAIN) &&
|
|
||||||
(errno != EWOULDBLOCK)) {
|
|
||||||
thread_data->status = errno;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Arguments are currently ignored:
|
|
||||||
*/
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
const int n_read_threads = 100;
|
|
||||||
const int n_epoll_items = 500;
|
|
||||||
int index;
|
|
||||||
int epoll_set = epoll_create1(0);
|
|
||||||
struct write_thread_data write_thread_data = {
|
|
||||||
0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int))
|
|
||||||
};
|
|
||||||
struct read_thread_data *read_thread_data =
|
|
||||||
malloc(n_read_threads * sizeof(struct read_thread_data));
|
|
||||||
pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t));
|
|
||||||
pthread_t write_thread;
|
|
||||||
|
|
||||||
printf("-----------------\n");
|
|
||||||
printf("Runing test_epoll\n");
|
|
||||||
printf("-----------------\n");
|
|
||||||
|
|
||||||
epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private));
|
|
||||||
|
|
||||||
if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 ||
|
|
||||||
read_thread_data == 0 || read_threads == 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (sysconf(_SC_NPROCESSORS_ONLN) < 2) {
|
|
||||||
printf("Error: please run this test on a multi-core system.\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the socket pairs and epoll items: */
|
|
||||||
for (index = 0; index < n_epoll_items; ++index) {
|
|
||||||
int socket_pair[2];
|
|
||||||
struct epoll_event event_data;
|
|
||||||
if (socketpair(AF_UNIX,
|
|
||||||
SOCK_STREAM | SOCK_NONBLOCK,
|
|
||||||
0,
|
|
||||||
socket_pair) < 0)
|
|
||||||
goto error;
|
|
||||||
write_thread_data.fds[index] = socket_pair[0];
|
|
||||||
epoll_items[index].index = index;
|
|
||||||
epoll_items[index].fd = socket_pair[1];
|
|
||||||
if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0)
|
|
||||||
goto error;
|
|
||||||
/* We always use EPOLLONESHOT because this test is currently
|
|
||||||
structured to demonstrate the need for EPOLL_CTL_DISABLE,
|
|
||||||
which only produces useful information in the EPOLLONESHOT
|
|
||||||
case (without EPOLLONESHOT, calling epoll_ctl with
|
|
||||||
EPOLL_CTL_DISABLE will never return EBUSY). If support for
|
|
||||||
testing events without EPOLLONESHOT is desired, it should
|
|
||||||
probably be implemented in a separate unit test. */
|
|
||||||
epoll_items[index].events = EPOLLIN | EPOLLONESHOT;
|
|
||||||
if (index < n_epoll_items / 2)
|
|
||||||
epoll_items[index].events |= EPOLLET;
|
|
||||||
epoll_items[index].stop = 0;
|
|
||||||
epoll_items[index].status = 0;
|
|
||||||
epoll_items[index].deleted = 0;
|
|
||||||
event_data.events = epoll_items[index].events;
|
|
||||||
event_data.data.ptr = &epoll_items[index];
|
|
||||||
if (epoll_ctl(epoll_set,
|
|
||||||
EPOLL_CTL_ADD,
|
|
||||||
epoll_items[index].fd,
|
|
||||||
&event_data) < 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create and start the read threads: */
|
|
||||||
for (index = 0; index < n_read_threads; ++index) {
|
|
||||||
read_thread_data[index].stop = 0;
|
|
||||||
read_thread_data[index].status = 0;
|
|
||||||
read_thread_data[index].epoll_set = epoll_set;
|
|
||||||
if (pthread_create(&read_threads[index],
|
|
||||||
NULL,
|
|
||||||
read_thread_function,
|
|
||||||
&read_thread_data[index]) != 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pthread_create(&write_thread,
|
|
||||||
NULL,
|
|
||||||
write_thread_function,
|
|
||||||
&write_thread_data) != 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Cancel all event pollers: */
|
|
||||||
#ifdef EPOLL_CTL_DISABLE
|
|
||||||
for (index = 0; index < n_epoll_items; ++index) {
|
|
||||||
pthread_mutex_lock(&epoll_items[index].mutex);
|
|
||||||
++epoll_items[index].stop;
|
|
||||||
if (epoll_ctl(epoll_set,
|
|
||||||
EPOLL_CTL_DISABLE,
|
|
||||||
epoll_items[index].fd,
|
|
||||||
NULL) == 0)
|
|
||||||
delete_item(index);
|
|
||||||
else if (errno != EBUSY) {
|
|
||||||
pthread_mutex_unlock(&epoll_items[index].mutex);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
/* EBUSY means events were being handled; allow the other thread
|
|
||||||
to delete the item. */
|
|
||||||
pthread_mutex_unlock(&epoll_items[index].mutex);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (index = 0; index < n_epoll_items; ++index) {
|
|
||||||
pthread_mutex_lock(&epoll_items[index].mutex);
|
|
||||||
++epoll_items[index].stop;
|
|
||||||
pthread_mutex_unlock(&epoll_items[index].mutex);
|
|
||||||
/* Wait in case a thread running read_thread_function is
|
|
||||||
currently executing code between epoll_wait and
|
|
||||||
pthread_mutex_lock with this item. Note that a longer delay
|
|
||||||
would make double-deletion less likely (at the expense of
|
|
||||||
performance), but there is no guarantee that any delay would
|
|
||||||
ever be sufficient. Note also that we delete all event
|
|
||||||
pollers at once for testing purposes, but in a real-world
|
|
||||||
environment we are likely to want to be able to cancel event
|
|
||||||
pollers at arbitrary times. Therefore we can't improve this
|
|
||||||
situation by just splitting this loop into two loops
|
|
||||||
(i.e. signal 'stop' for all items, sleep, and then delete all
|
|
||||||
items). We also can't fix the problem via EPOLL_CTL_DEL
|
|
||||||
because that command can't prevent the case where some other
|
|
||||||
thread is executing read_thread_function within the region
|
|
||||||
mentioned above: */
|
|
||||||
usleep(1);
|
|
||||||
pthread_mutex_lock(&epoll_items[index].mutex);
|
|
||||||
if (!epoll_items[index].deleted)
|
|
||||||
delete_item(index);
|
|
||||||
pthread_mutex_unlock(&epoll_items[index].mutex);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Shut down the read threads: */
|
|
||||||
for (index = 0; index < n_read_threads; ++index)
|
|
||||||
__sync_fetch_and_add(&read_thread_data[index].stop, 1);
|
|
||||||
for (index = 0; index < n_read_threads; ++index) {
|
|
||||||
if (pthread_join(read_threads[index], NULL) != 0)
|
|
||||||
goto error;
|
|
||||||
if (read_thread_data[index].status)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shut down the write thread: */
|
|
||||||
__sync_fetch_and_add(&write_thread_data.stop, 1);
|
|
||||||
if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Check for final error conditions: */
|
|
||||||
for (index = 0; index < n_epoll_items; ++index) {
|
|
||||||
if (epoll_items[index].status != 0)
|
|
||||||
goto error;
|
|
||||||
if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
for (index = 0; index < n_epoll_items; ++index)
|
|
||||||
if (epoll_items[index].deleted != 1) {
|
|
||||||
printf("Error: item data deleted %1d times.\n",
|
|
||||||
epoll_items[index].deleted);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("[PASS]\n");
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
printf("[FAIL]\n");
|
|
||||||
return errno;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user