diff --git a/lib/hio-cmn.h b/lib/hio-cmn.h index c003aa6..5dbadba 100644 --- a/lib/hio-cmn.h +++ b/lib/hio-cmn.h @@ -963,6 +963,14 @@ struct hio_cmgr_t #endif #endif +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) + #define HCL_ATOMIC_LOAD(dst) __atomic_load_n(dst, __ATOMIC_RELAXED) + #define HCL_ATOMIC_CMP_XCHG(dst,expected,desired) \ + __atomic_compare_exchange_n(dst, expected, desired, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED) +#else + #error NOT SUPPORTED +#endif + #if defined(HIO_HAVE_BUILTIN_EXPECT) # define HIO_LIKELY(x) (__builtin_expect(!!(x),1)) # define HIO_UNLIKELY(x) (__builtin_expect(!!(x),0)) diff --git a/lib/http-cgi.c b/lib/http-cgi.c index 03ba07d..4014339 100644 --- a/lib/http-cgi.c +++ b/lib/http-cgi.c @@ -48,6 +48,8 @@ #define CGI_OVER_WRITE_TO_PEER (1 << 3) #define CGI_OVER_ALL (CGI_OVER_READ_FROM_CLIENT | CGI_OVER_READ_FROM_PEER | CGI_OVER_WRITE_TO_CLIENT | CGI_OVER_WRITE_TO_PEER) +/* ----------------------------------------------------------------------- */ + struct cgi_t { HIO_SVC_HTTS_TASK_HEADER; @@ -75,9 +77,45 @@ struct cgi_peer_xtn_t }; typedef struct cgi_peer_xtn_t cgi_peer_xtn_t; +/* ----------------------------------------------------------------------- */ + static void unbind_task_from_client (cgi_t* cgi, int rcdown); static void unbind_task_from_peer (cgi_t* cgi, int rcdown); +/* ----------------------------------------------------------------------- */ + +static int inc_ntask_cgis (hio_svc_htts_t* htts) +{ + int ok; + do + { + hio_oow_t ntask_cgis; + ntask_cgis = HCL_ATOMIC_LOAD(&htts->stat.ntask_cgis); + if (ntask_cgis >= htts->option.task_cgi_max) + { + hio_seterrbfmt (htts->hio, HIO_ENOCAPA, "too many cgi tasks"); + return -1; + } + ok = HCL_ATOMIC_CMP_XCHG(&htts->stat.ntask_cgis, &ntask_cgis, ntask_cgis + 1); + } + while (!ok); + return 0; +} + +static void dec_ntask_cgis (hio_svc_htts_t* htts) +{ + int ok; + do + { + hio_oow_t ntask_cgis; + ntask_cgis = HCL_ATOMIC_LOAD(&htts->stat.ntask_cgis); + ok = HCL_ATOMIC_CMP_XCHG(&htts->stat.ntask_cgis, &ntask_cgis, ntask_cgis - 1); + } + while (!ok); +} + +/* ----------------------------------------------------------------------- */ + static void cgi_halt_participating_devices (cgi_t* cgi) { HIO_DEBUG5 (cgi->htts->hio, "HTTS(%p) - cgi(t=%p,c=%p(%d),p=%p) Halting participating devices\n", cgi->htts, cgi, cgi->task_csck, (cgi->task_csck? cgi->task_csck->hnd: -1), cgi->peer); @@ -192,7 +230,8 @@ static void cgi_on_kill (hio_svc_htts_task_t* task) } if (cgi->task_next) HIO_SVC_HTTS_TASKL_UNLINK_TASK (cgi); /* detach from the htts service only if it's attached */ - cgi->htts->stat.ntask_cgis--; + dec_ntask_cgis (cgi->htts); + HIO_DEBUG5 (hio, "HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - killed the task\n", cgi->htts, cgi, cgi->task_client, (cgi->task_csck? cgi->task_csck->hnd: -1), cgi->peer); } @@ -939,16 +978,14 @@ int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r HIO_ASSERT (hio, hio_htre_getcontentlen(req) == 0); HIO_ASSERT (hio, cli->sck == csck); - if (htts->stat.ntask_cgis >= htts->option.task_cgi_max) - { - hio_seterrbfmt (hio, HIO_ENOCAPA, "too many cgi tasks"); - return -1; - } - + if (inc_ntask_cgis(htts) <= -1) return -1; cgi = (cgi_t*)hio_svc_htts_task_make(htts, HIO_SIZEOF(*cgi), cgi_on_kill, req, csck); - if (HIO_UNLIKELY(!cgi)) goto oops; + if (HIO_UNLIKELY(!cgi)) + { + dec_ntask_cgis (htts); + goto oops; + } HIO_SVC_HTTS_TASK_RCUP((hio_svc_htts_task_t*)cgi); - htts->stat.ntask_cgis++; cgi->on_kill = on_kill; cgi->options = options; diff --git a/lib/http-svr.c b/lib/http-svr.c index 8924dbf..e1ce832 100644 --- a/lib/http-svr.c +++ b/lib/http-svr.c @@ -38,6 +38,38 @@ static int client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t len, static int client_on_write (hio_dev_sck_t* sck, hio_iolen_t wrlen, void* wrctx, const hio_skad_t* dstaddr); static void client_on_disconnect (hio_dev_sck_t* sck); +/* ------------------------------------------------------------------------ */ + +static int inc_ntasks (hio_svc_htts_t* htts) +{ + int ok; + do + { + hio_oow_t ntasks; + ntasks = HCL_ATOMIC_LOAD(&htts->stat.ntasks); + if (ntasks >= htts->option.task_cgi_max) + { + hio_seterrbfmt (htts->hio, HIO_ENOCAPA, "too many tasks"); + return -1; + } + ok = HCL_ATOMIC_CMP_XCHG(&htts->stat.ntasks, &ntasks, ntasks + 1); + } + while (!ok); + return 0; +} + +static void dec_ntasks (hio_svc_htts_t* htts) +{ + int ok; + do + { + hio_oow_t ntasks; + ntasks = HCL_ATOMIC_LOAD(&htts->stat.ntasks); + ok = HCL_ATOMIC_CMP_XCHG(&htts->stat.ntasks, &ntasks, ntasks - 1); + } + while (!ok); +} + /* ------------------------------------------------------------------------ */ static int client_htrd_peek_request (hio_htrd_t* htrd, hio_htre_t* req) { @@ -805,10 +837,13 @@ hio_svc_htts_task_t* hio_svc_htts_task_make (hio_svc_htts_t* htts, hio_oow_t tas qpath_len = hio_htre_getqpathlen(req); qmth_len = hio_htre_getqmethodlen(req); + if (inc_ntasks(htts) <= -1) return HIO_NULL; + task = hio_callocmem(hio, task_size + qmth_len + 1 + qpath_len + 1); if (HIO_UNLIKELY(!task)) { HIO_DEBUG1 (hio, "HTTS(%p) - failed to allocate task\n", htts); + dec_ntasks (htts); return HIO_NULL; } @@ -837,7 +872,6 @@ hio_svc_htts_task_t* hio_svc_htts_task_make (hio_svc_htts_t* htts, hio_oow_t tas HIO_ASSERT (hio, csck->on_write == client_on_write); HIO_ASSERT (hio, csck->on_disconnect == client_on_disconnect); - htts->stat.ntasks++; HIO_DEBUG2 (hio, "HTTS(%p) - allocated task %p\n", htts, task); return task; } @@ -852,7 +886,7 @@ void hio_svc_htts_task_kill (hio_svc_htts_task_t* task) if (task->task_on_kill) task->task_on_kill (task); hio_freemem (hio, task); - htts->stat.ntasks--; + dec_ntasks (htts); HIO_DEBUG2 (hio, "HTTS(%p) - destroyed task %p\n", htts, task); } diff --git a/lib/thr.c b/lib/thr.c index 9cc4159..728052a 100644 --- a/lib/thr.c +++ b/lib/thr.c @@ -323,7 +323,7 @@ static int dev_thr_kill_master (hio_dev_t* dev, int force) hio_freemem (hio, ti); #else /* schedule a resource destroyer */ - hio_addcfmb (hio, ti, ready_to_free_thr_info, HIO_NULL); + hio_addcfmb (hio, (hio_cfmb_t*)ti, ready_to_free_thr_info, HIO_NULL); #endif }