static void * thread_spam(void *d) { struct per_vhost_data__minimal *vhd = (struct per_vhost_data__minimal *)d; struct msg amsg; int len = 128, index = 1, n; do { /* don't generate output if client not connected */ if (!vhd->established) goto wait; pthread_mutex_lock(&vhd->lock_ring); /* --------- ring lock { */ /* only create if space in ringbuffer */ n = (int)lws_ring_get_count_free_elements(vhd->ring); if (!n) { lwsl_user("dropping!\n"); goto wait_unlock; } amsg.payload = malloc(LWS_PRE + len); if (!amsg.payload) { lwsl_user("OOM: dropping\n"); goto wait_unlock; } n = lws_snprintf((char *)amsg.payload + LWS_PRE, len, "tid: %p, msg: %d", (void *)pthread_self(), index++); amsg.len = n; n = lws_ring_insert(vhd->ring, &amsg, 1); if (n != 1) { __minimal_destroy_message(&amsg); lwsl_user("dropping!\n"); } else /* * This will cause a LWS_CALLBACK_EVENT_WAIT_CANCELLED * in the lws service thread context. */ lws_cancel_service(vhd->context); wait_unlock: pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */ wait: usleep(100000); } while (!vhd->finished); lwsl_notice("thread_spam %p exiting\n", (void *)pthread_self()); pthread_exit(NULL); return NULL; }
LWS_VISIBLE LWS_EXTERN void lws_ring_dump(struct lws_ring *ring, uint32_t *tail) { if (tail == NULL) tail = &ring->oldest_tail; lwsl_notice("ring %p: buflen %u, elem_len %u, head %u, oldest_tail %u\n" " free_elems: %u; for tail %u, waiting elements: %u\n", ring, ring->buflen, ring->element_len, ring->head, ring->oldest_tail, (int)lws_ring_get_count_free_elements(ring), *tail, (int)lws_ring_get_count_waiting_elements(ring, tail)); }
LWS_VISIBLE LWS_EXTERN size_t lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count) { const uint8_t *osrc = src; int m, n; /* n is how many bytes the whole fifo can take */ n = (int)(lws_ring_get_count_free_elements(ring) * ring->element_len); /* restrict n to how much we want to insert */ if ((uint32_t)n > max_count * ring->element_len) n = (int)(max_count * ring->element_len); /* * n is legal to insert, but as an optimization we can cut the * insert into one or two memcpys, depending on if it wraps */ if (ring->head + n > ring->buflen) { /* * He does wrap. The first memcpy should take us up to * the end of the buffer */ m = ring->buflen - ring->head; memcpy(((uint8_t *)ring->buf) + ring->head, src, m); /* we know it will wrap exactly back to zero */ ring->head = 0; /* adapt the second memcpy for what we already did */ src = ((uint8_t *)src) + m; n -= m; } memcpy(((uint8_t *)ring->buf) + ring->head, src, n); ring->head = (ring->head + n) % ring->buflen; return (((uint8_t *)src + n) - osrc) / ring->element_len; }
LWS_VISIBLE LWS_EXTERN int lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start, size_t *bytes) { int n; /* n is how many bytes the whole fifo can take */ n = (int)(lws_ring_get_count_free_elements(ring) * ring->element_len); if (!n) return 1; if (ring->head + n > ring->buflen) { *start = (void *)(((uint8_t *)ring->buf) + ring->head); *bytes = ring->buflen - ring->head; return 0; } *start = (void *)(((uint8_t *)ring->buf) + ring->head); *bytes = n; return 0; }
static int callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__minimal *pss = (struct per_session_data__minimal *)user; struct per_vhost_data__minimal *vhd = (struct per_vhost_data__minimal *) lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); const struct msg *pmsg; struct msg amsg; char buf[32]; int n, m; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__minimal)); vhd->context = lws_get_context(wsi); vhd->protocol = lws_get_protocol(wsi); vhd->vhost = lws_get_vhost(wsi); vhd->ring = lws_ring_create(sizeof(struct msg), 8, __minimal_destroy_message); if (!vhd->ring) return 1; break; case LWS_CALLBACK_PROTOCOL_DESTROY: lws_ring_destroy(vhd->ring); break; case LWS_CALLBACK_ESTABLISHED: pss->tail = lws_ring_get_oldest_tail(vhd->ring); pss->wsi = wsi; if (lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_GET_URI) > 0) pss->publishing = !strcmp(buf, "/publisher"); if (!pss->publishing) /* add subscribers to the list of live pss held in the vhd */ lws_ll_fwd_insert(pss, pss_list, vhd->pss_list); break; case LWS_CALLBACK_CLOSED: /* remove our closing pss from the list of live pss */ lws_ll_fwd_remove(struct per_session_data__minimal, pss_list, pss, vhd->pss_list); break; case LWS_CALLBACK_SERVER_WRITEABLE: if (pss->publishing) break; pmsg = lws_ring_get_element(vhd->ring, &pss->tail); if (!pmsg) break; /* notice we allowed for LWS_PRE in the payload already */ m = lws_write(wsi, ((unsigned char *)pmsg->payload) + LWS_PRE, pmsg->len, LWS_WRITE_TEXT); if (m < (int)pmsg->len) { lwsl_err("ERROR %d writing to ws socket\n", m); return -1; } lws_ring_consume_and_update_oldest_tail( vhd->ring, /* lws_ring object */ struct per_session_data__minimal, /* type of objects with tails */ &pss->tail, /* tail of guy doing the consuming */ 1, /* number of payload objects being consumed */ vhd->pss_list, /* head of list of objects with tails */ tail, /* member name of tail in objects with tails */ pss_list /* member name of next object in objects with tails */ ); /* more to do? */ if (lws_ring_get_element(vhd->ring, &pss->tail)) /* come back as soon as we can write more */ lws_callback_on_writable(pss->wsi); break; case LWS_CALLBACK_RECEIVE: if (!pss->publishing) break; /* * For test, our policy is ignore publishing when there are * no subscribers connected. */ if (!vhd->pss_list) break; n = (int)lws_ring_get_count_free_elements(vhd->ring); if (!n) { lwsl_user("dropping!\n"); break; } amsg.len = len; /* notice we over-allocate by LWS_PRE */ amsg.payload = malloc(LWS_PRE + len); if (!amsg.payload) { lwsl_user("OOM: dropping\n"); break; } memcpy((char *)amsg.payload + LWS_PRE, in, len); if (!lws_ring_insert(vhd->ring, &amsg, 1)) { __minimal_destroy_message(&amsg); lwsl_user("dropping 2!\n"); break; } /* * let every subscriber know we want to write something * on them as soon as they are ready */ lws_start_foreach_llp(struct per_session_data__minimal **, ppss, vhd->pss_list) { if (!(*ppss)->publishing) lws_callback_on_writable((*ppss)->wsi); } lws_end_foreach_llp(ppss, pss_list); break; default: break; } return 0; }