mirror of
https://github.com/troglobit/libuev.git
synced 2026-10-23 11:24:34 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de89b6647d | ||
|
|
7eee63e5eb | ||
|
|
c780b82929 | ||
|
|
cccaabfad5 | ||
|
|
6d33c56d0f | ||
|
|
6ae98d135c | ||
|
|
d3e5900f73 | ||
|
|
2ff15101ae | ||
|
|
04d9e1c80a | ||
|
|
0674fb8db4 | ||
|
|
c4ac2eae5d | ||
|
|
951f959549 | ||
|
|
a2900279f6 | ||
|
|
f9c9f24afb | ||
|
|
ab05f71bbc | ||
|
|
856546f4c7 | ||
|
|
748ebc998c | ||
|
|
0e97bfdc5a | ||
|
|
cebe66e8a4 | ||
|
|
dd651ae791 | ||
|
|
a528405258 | ||
|
|
70f04c10e1 | ||
|
|
e3dca8255d | ||
|
|
dbf8c0dae2 | ||
|
|
f75b1d5080 |
No files matched your search
@@ -69,7 +69,7 @@ int uev_io_set (uev_t *w, int fd, int events);
|
||||
int uev_io_start (uev_t *w);
|
||||
int uev_io_stop (uev_t *w);
|
||||
|
||||
/* Timer watcher: schedule a relative timer, timeout and period in milliseconds */
|
||||
/* Timer watcher: schedule a relative timer, timeout (must be non-zero) and period in milliseconds */
|
||||
int uev_timer_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeout, int period);
|
||||
int uev_timer_set (uev_t *w, int timeout, int period); /* Change timeout or period */
|
||||
int uev_timer_start (uev_t *w); /* Restart a stopped timer */
|
||||
@@ -312,7 +312,7 @@ int main(void)
|
||||
uev_t watcher;
|
||||
uev_ctx_t ctx;
|
||||
|
||||
fd = open("/dev/input/js1", O_RDONLY, O_NONBLOCK);
|
||||
fd = open("/dev/input/js0", O_RDONLY, O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
errx(errno, "Cannot find a joystick attached.");
|
||||
|
||||
|
||||
+44
-1
@@ -4,6 +4,46 @@ Change Log
|
||||
All notable changes to the project are documented in this file.
|
||||
|
||||
|
||||
[v2.1.3][] - 2018-09-06
|
||||
-----------------------
|
||||
|
||||
### Changes
|
||||
- Update joystick example, use first device, `/dev/input/js0`
|
||||
- Minor refactor of `uev_exit()`, use `_SAFE` macros to traverse
|
||||
list of watchers instead of `while()`
|
||||
- New API test to verify that `uev_exit()` terminates properly
|
||||
- Make `uev_signal_stop()` idempotent
|
||||
|
||||
### Fixes
|
||||
- Let `uev_timer_stop()` call `close()` on the timerfd directly, do not
|
||||
call `uev_timer_set()` since that may cause lockups or hangs
|
||||
|
||||
|
||||
[v2.1.2][] - 2018-02-27
|
||||
-----------------------
|
||||
|
||||
### Changes
|
||||
- Minor refactor of event loop after fixing the nasty use-after-free bug
|
||||
in v2.1.1. Code can now be collapsed and noticeably simplified
|
||||
|
||||
### Fixes
|
||||
- Issue #17: Check if `AM_PROG_AR` macro exists before calling it, fixes
|
||||
problem building libuEv on systems with older autoconf + automake.
|
||||
Patch by Markus Svilans
|
||||
- Fix minor issue with unit tests, return result of test not event loop
|
||||
|
||||
|
||||
[v2.1.1][] - 2018-01-28
|
||||
-----------------------
|
||||
|
||||
### Fixes
|
||||
- Fix use after free in main event loop if watcher deletes itself in
|
||||
the callback. I.e., the callback must be the last action for the
|
||||
watcher in the event loop.
|
||||
- Doc timer example fix by @tisyang
|
||||
- Doc timer updates, non-zero timeout required
|
||||
|
||||
|
||||
[v2.1.0][] - 2017-11-14
|
||||
-----------------------
|
||||
|
||||
@@ -326,7 +366,10 @@ v0.0.1 - 2012-03-17
|
||||
Lua users mailing list.
|
||||
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/libuev/compare/v2.1.0...HEAD
|
||||
[UNRELEASED]: https://github.com/troglobit/libuev/compare/v2.1.3...HEAD
|
||||
[v2.1.3]: https://github.com/troglobit/libuev/compare/v2.1.2...v2.1.3
|
||||
[v2.1.2]: https://github.com/troglobit/libuev/compare/v2.1.1...v2.1.2
|
||||
[v2.1.1]: https://github.com/troglobit/libuev/compare/v2.1.0...v2.1.1
|
||||
[v2.1.0]: https://github.com/troglobit/libuev/compare/v2.0.0...v2.1.0
|
||||
[v2.0.0]: https://github.com/troglobit/libuev/compare/v1.6.0...v2.0.0
|
||||
[v1.6.0]: https://github.com/troglobit/libuev/compare/v1.5.2...v1.6.0
|
||||
|
||||
@@ -59,7 +59,7 @@ int main(void)
|
||||
|
||||
uev_init(&ctx);
|
||||
/* Set up a timer watcher to call cb() every other second */
|
||||
uev_timer_init(&ctx, &timer, cb, NULL, 0, 2 * 1000);
|
||||
uev_timer_init(&ctx, &timer, cb, NULL, 2 * 1000, 2 * 1000);
|
||||
|
||||
return uev_run(&ctx, 0);
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
AC_INIT(libuev, 2.1.0, https://github.com/troglobit/libuev/issues)
|
||||
AC_INIT(libuev, 2.1.3, https://github.com/troglobit/libuev/issues)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
@@ -8,7 +8,7 @@ AC_CONFIG_FILES([Makefile src/libuev.pc src/Makefile examples/Makefile tests/Mak
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_PROG_CC
|
||||
AM_PROG_AR
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
LT_INIT
|
||||
|
||||
# Optional features
|
||||
|
||||
Vendored
+41
@@ -1,3 +1,44 @@
|
||||
libuev (2.1.3) unstable; urgency=medium
|
||||
|
||||
* Minor bugfix release
|
||||
- Updated joystick example, use first joystick, /dev/input/js0
|
||||
- Use LIST_FOREACH_SAFE() instead of while() in uev_exit()
|
||||
- New API test for uev_exit()
|
||||
- Don't call uev_timer_set() when stopping a timer, may cause lockups
|
||||
- Return OK immediately if a signal watcher is already stopped
|
||||
* Packaging fixes: libuev.so symlink goes in -dev package
|
||||
-- Joachim Nilsson <troglobit@gmail.com> Thu, 06 Sep 2018 22:01:24 +0200
|
||||
|
||||
libuev (2.1.2) unstable; urgency=medium
|
||||
|
||||
* Minor bugfix release
|
||||
- Fix #17: build problem on systems with too old autoconf + automake
|
||||
- Fix unit tests, return result of test not result of event loop
|
||||
- Refactor/simplify/collapse main event loop code after fixes in v2.1.1
|
||||
* Fix minor packaging issues
|
||||
|
||||
-- Joachim Nilsson <troglobit@gmail.com> Tue, 27 Feb 2018 00:05:32 +0100
|
||||
|
||||
libuev (2.1.1) unstable; urgency=medium
|
||||
|
||||
* Minor bugfix release
|
||||
* Use native version numbering for package
|
||||
|
||||
-- Joachim Nilsson <troglobit@gmail.com> Sun, 28 Jan 2018 13:38:00 +0100
|
||||
|
||||
libuev (2.1.0-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release. Further improvements to failure modes, some
|
||||
fixes to regressions introduced in v2.0.
|
||||
|
||||
- Unconditionally stop I/O watchers on UEV_HUP and UEV_ERR conditions.
|
||||
- Attempt to restart failing signal watchers before dropping to error.
|
||||
- Properly de-register signal and cron/timer watchers on error.
|
||||
- Fix possible double close() on cron/timer watchers.
|
||||
- Documentation updates, improved examples, and unit tests.
|
||||
|
||||
-- Joachim Nilsson <troglobit@gmail.com> Tue, 14 Nov 2017 17:40:43 +0100
|
||||
|
||||
libuev (2.0.0-1) unstable; urgency=medium
|
||||
|
||||
* Major new upstream version, possibly incompatible changes to both
|
||||
|
||||
Vendored
+3
-5
@@ -1,6 +1,4 @@
|
||||
usr/include/uev/uev.h
|
||||
usr/include/uev/private.h
|
||||
usr/include/uev/queue.h
|
||||
usr/lib/*/lib*.a
|
||||
usr/lib/*/lib*.so
|
||||
usr/include/uev/*.h
|
||||
usr/lib/*/libuev.a
|
||||
usr/lib/*/libuev.so
|
||||
usr/lib/*/pkgconfig/lib*.pc
|
||||
+1
-1
@@ -78,7 +78,7 @@ int main(void)
|
||||
uev_t js1_watcher;
|
||||
uev_ctx_t ctx;
|
||||
|
||||
fd = open("/dev/input/js1", O_RDONLY, O_NONBLOCK);
|
||||
fd = open("/dev/input/js0", O_RDONLY, O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
errx(errno, "Cannot find a joystick attached.");
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ lib_LTLIBRARIES = libuev.la
|
||||
libuev_la_SOURCES = uev.c io.c timer.c signal.c cron.c
|
||||
libuev_la_CPPFLAGS = -D_GNU_SOURCE -D_TIME_BITS=64
|
||||
libuev_la_CFLAGS = -W -Wall -Wextra
|
||||
libuev_la_LDFLAGS = $(AM_LDFLAGS) -version-info 2:0:0
|
||||
libuev_la_LDFLAGS = $(AM_LDFLAGS) -version-info 2:2:0
|
||||
|
||||
noinst_PROGRAMS = bench
|
||||
bench_CPPFLAGS = -D_GNU_SOURCE
|
||||
|
||||
@@ -60,7 +60,6 @@ int uev_io_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int e
|
||||
*/
|
||||
int uev_io_set(uev_t *w, int fd, int events)
|
||||
{
|
||||
|
||||
if ((events & UEV_ONESHOT) && _uev_watcher_active(w))
|
||||
return _uev_watcher_rearm(w);
|
||||
|
||||
|
||||
@@ -140,6 +140,9 @@ int uev_signal_start(uev_t *w)
|
||||
*/
|
||||
int uev_signal_stop(uev_t *w)
|
||||
{
|
||||
if (!_uev_watcher_active(w))
|
||||
return 0;
|
||||
|
||||
if (_uev_watcher_stop(w))
|
||||
return -1;
|
||||
|
||||
|
||||
+5
-6
@@ -93,9 +93,13 @@ int uev_timer_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeou
|
||||
/**
|
||||
* Reset a timer
|
||||
* @param w Watcher to reset
|
||||
* @param timeout Timeout in milliseconds before @param cb is called
|
||||
* @param timeout Timeout in milliseconds before @param cb is called, zero disarms timer
|
||||
* @param period For periodic timers this is the period time that @param timeout is reset to
|
||||
*
|
||||
* Note, the @param timeout value must be non-zero. Setting it to zero
|
||||
* will disarm the timer. This is the underlying Linux function @func
|
||||
* timerfd_settimer() which has this behavior.
|
||||
*
|
||||
* @return POSIX OK(0) or non-zero with @param errno set on error.
|
||||
*/
|
||||
int uev_timer_set(uev_t *w, int timeout, int period)
|
||||
@@ -166,17 +170,12 @@ int uev_timer_start(uev_t *w)
|
||||
*/
|
||||
int uev_timer_stop(uev_t *w)
|
||||
{
|
||||
/* Check if already stopped in uev_run() after cb() or _init() */
|
||||
if (!_uev_watcher_active(w))
|
||||
return 0;
|
||||
|
||||
/* Stop kernel timer */
|
||||
uev_timer_set(w, 0, 0);
|
||||
|
||||
if (_uev_watcher_stop(w))
|
||||
return -1;
|
||||
|
||||
/* Close timerfd, will have to be reopened again on reset */
|
||||
close(w->fd);
|
||||
w->fd = -1;
|
||||
|
||||
|
||||
@@ -203,14 +203,14 @@ int uev_init(uev_ctx_t *ctx)
|
||||
*/
|
||||
int uev_exit(uev_ctx_t *ctx)
|
||||
{
|
||||
uev_t *w, *next;
|
||||
|
||||
if (!ctx) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (!LIST_EMPTY(&ctx->watchers)) {
|
||||
uev_t *w = LIST_FIRST(&ctx->watchers);
|
||||
|
||||
LIST_FOREACH_SAFE(w, &ctx->watchers, link, next) {
|
||||
/* Remove from internal list */
|
||||
LIST_REMOVE(w, link);
|
||||
|
||||
@@ -233,6 +233,7 @@ int uev_exit(uev_ctx_t *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
LIST_INIT(&ctx->watchers);
|
||||
ctx->running = 0;
|
||||
close(ctx->fd);
|
||||
ctx->fd = -1;
|
||||
@@ -347,6 +348,8 @@ int uev_run(uev_ctx_t *ctx, int flags)
|
||||
|
||||
if (!w->u.t.period)
|
||||
w->u.t.timeout = 0;
|
||||
if (!w->u.t.timeout)
|
||||
uev_timer_stop(w);
|
||||
break;
|
||||
|
||||
case UEV_CRON_TYPE:
|
||||
@@ -362,20 +365,17 @@ int uev_run(uev_ctx_t *ctx, int flags)
|
||||
w->u.c.when = 0;
|
||||
else
|
||||
w->u.c.when += w->u.c.interval;
|
||||
if (!w->u.c.when)
|
||||
uev_timer_stop(w);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: Must be last action for watcher, the
|
||||
* callback may delete itself.
|
||||
*/
|
||||
if (w->cb)
|
||||
w->cb(w, w->arg, events & UEV_EVENT_MASK);
|
||||
|
||||
if (UEV_CRON_TYPE == w->type) {
|
||||
if (!w->u.c.when)
|
||||
uev_timer_stop(w);
|
||||
}
|
||||
if (UEV_TIMER_TYPE == w->type) {
|
||||
if (!w->u.t.timeout)
|
||||
uev_timer_stop(w);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & UEV_ONCE)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
*.trs
|
||||
*.log
|
||||
active
|
||||
api
|
||||
complete
|
||||
cronrun
|
||||
signal
|
||||
|
||||
@@ -3,6 +3,7 @@ CLEANFILES = *~ *.trs *.log
|
||||
|
||||
TESTS =
|
||||
TESTS += active
|
||||
TESTS += api
|
||||
TESTS += complete
|
||||
TESTS += cronrun
|
||||
TESTS += signal
|
||||
|
||||
@@ -30,6 +30,9 @@ static void cb(uev_t *w, void *UNUSED(arg), int events)
|
||||
fail_unless(!uev_timer_active(&timer2));
|
||||
fail_unless(!uev_cron_active(&cron2));
|
||||
|
||||
/* Restart timer and see if we fail in uev_exit() */
|
||||
uev_timer_start(&timer2);
|
||||
|
||||
uev_exit(w->ctx);
|
||||
}
|
||||
|
||||
@@ -52,3 +55,10 @@ int main(void)
|
||||
|
||||
return uev_run(&ctx, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#include "check.h"
|
||||
|
||||
uev_t timer, file;
|
||||
int counter = 10;
|
||||
|
||||
static void cb(uev_t *w, void *UNUSED(arg), int events)
|
||||
{
|
||||
if (UEV_ERROR == events)
|
||||
fprintf(stderr, "timer watcher failed, ignoring ...\n");
|
||||
|
||||
if (counter--)
|
||||
return;
|
||||
|
||||
uev_exit(w->ctx);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uev_ctx_t ctx;
|
||||
FILE *fp;
|
||||
|
||||
uev_init(&ctx);
|
||||
uev_timer_init(&ctx, &timer, cb, NULL, 100, 100);
|
||||
|
||||
fp = fopen("/dev/one", "r");
|
||||
if (fp)
|
||||
uev_io_init(&ctx, &file, cb, NULL, fileno(fp), UEV_READ);
|
||||
|
||||
uev_run(&ctx, 0);
|
||||
|
||||
uev_exit(&ctx); /* Should not hang event loop, troglobit/uftpd#16 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
+4
-4
@@ -82,7 +82,7 @@ static void pipe_read_cb(uev_t *w, void UNUSED(*arg), int events)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Kick watchdog */
|
||||
/* Kick watchdog */
|
||||
if (watchdog)
|
||||
uev_timer_set(watchdog, 1000, 0);
|
||||
|
||||
@@ -112,9 +112,9 @@ static void pipe_write_cb(uev_t *w, void *arg, int UNUSED(events))
|
||||
|
||||
/* Here we *must* use out, not w->fd, since we're a timer callback */
|
||||
if (write(out, msg, my->counter) < 0) {
|
||||
perror("\nFailed writing to pipe");
|
||||
return;
|
||||
}
|
||||
perror("\nFailed writing to pipe");
|
||||
return;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "WRITE %.*s %d\n", my->counter, msg, my->counter);
|
||||
fprintf(stderr, "%d ", my->counter);
|
||||
|
||||
+10
-3
@@ -28,6 +28,7 @@
|
||||
#define TIMEOUT 2
|
||||
#define INTERVAL 2
|
||||
|
||||
int result = -1;
|
||||
struct timeval tv;
|
||||
|
||||
static void cron_job(uev_t *w, void *UNUSED(arg), int events)
|
||||
@@ -45,12 +46,15 @@ static void cron_job(uev_t *w, void *UNUSED(arg), int events)
|
||||
printf("Cron job HELO %s", ctime(&now.tv_sec));
|
||||
fail_unless(now.tv_sec == tv.tv_sec);
|
||||
|
||||
if (!laps--)
|
||||
if (!laps--) {
|
||||
result = 0;
|
||||
uev_exit(w->ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int rc;
|
||||
uev_t cron_watcher;
|
||||
uev_ctx_t ctx;
|
||||
time_t when, interval;
|
||||
@@ -62,11 +66,14 @@ int main(void)
|
||||
|
||||
printf("Start of test %s", ctime(&tv.tv_sec));
|
||||
printf("Expected cron %s", ctime(&when));
|
||||
|
||||
|
||||
interval = INTERVAL;
|
||||
uev_cron_init(&ctx, &cron_watcher, cron_job, NULL, when, interval);
|
||||
|
||||
return uev_run(&ctx, 0);
|
||||
rc = uev_run(&ctx, 0);
|
||||
fail_unless(result == 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-13
@@ -63,7 +63,7 @@ static int callback(arg_t *arg, int event, void *foo)
|
||||
printf("child: segfaulting failed!\n");
|
||||
#endif
|
||||
|
||||
return 42;
|
||||
return 42;
|
||||
}
|
||||
|
||||
static void sigsegv_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
@@ -74,27 +74,27 @@ static void sigsegv_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
|
||||
static void sigchld_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
pid_t pid = waitpid(-1, NULL, WNOHANG);
|
||||
pid_t pid = waitpid(-1, NULL, WNOHANG);
|
||||
|
||||
if (-1 != pid)
|
||||
warnx("PID %d exited, bye.", pid);
|
||||
if (-1 != pid)
|
||||
warnx("PID %d exited, bye.", pid);
|
||||
}
|
||||
|
||||
static void work_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
|
||||
{
|
||||
int status = 0;
|
||||
pid_t pid;
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (-1 == pid)
|
||||
err(1, "fork");
|
||||
pid = fork();
|
||||
if (-1 == pid)
|
||||
err(1, "fork");
|
||||
if (!pid) {
|
||||
status = callback(arg, 6137, NULL);
|
||||
exit(status);
|
||||
}
|
||||
exit(status);
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) == -1)
|
||||
err(1, "waitpid");
|
||||
if (waitpid(pid, &status, 0) == -1)
|
||||
err(1, "waitpid");
|
||||
|
||||
if (WIFEXITED(status))
|
||||
printf("Child exited normally => %d\n", WEXITSTATUS(status));
|
||||
@@ -108,7 +108,7 @@ static void work_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
|
||||
|
||||
static void exit_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
printf("Process deadline reached, exiting!\n");
|
||||
printf("Process deadline reached, exiting!\n");
|
||||
uev_exit(w->ctx);
|
||||
}
|
||||
|
||||
|
||||
+15
-1
@@ -3,6 +3,8 @@
|
||||
#include <sys/time.h>
|
||||
|
||||
#define TIMEOUT 2 /* 2 sec */
|
||||
|
||||
int result = -1;
|
||||
struct timeval start;
|
||||
|
||||
static void cb(uev_t *w, void *UNUSED(arg), int events)
|
||||
@@ -15,11 +17,13 @@ static void cb(uev_t *w, void *UNUSED(arg), int events)
|
||||
gettimeofday(&now, NULL);
|
||||
fail_unless(now.tv_sec == start.tv_sec + TIMEOUT);
|
||||
|
||||
result = 0;
|
||||
uev_exit(w->ctx);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int rc;
|
||||
uev_t w;
|
||||
uev_ctx_t ctx;
|
||||
|
||||
@@ -27,5 +31,15 @@ int main(void)
|
||||
uev_timer_init(&ctx, &w, cb, NULL, TIMEOUT * 1000, 0);
|
||||
gettimeofday(&start, NULL);
|
||||
|
||||
return uev_run(&ctx, 0);
|
||||
rc = uev_run(&ctx, 0);
|
||||
fail_unless(result == 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
Reference in new issue
Block a user