Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1606540166, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", "f":3, "items": [ {"schema":"libjg2-1", "cid":"04607e82836f1e4eabaf9f545e3b0dc0", "oid":{ "oid": "41240965cf0359128c7c51cd35d6bd6d0bc95bb0", "alias": [ "refs/heads/main","refs/heads/master"]},"blobname": "minimal-examples/ws-server/minimal-ws-server-threads/protocol_lws_minimal.c", "blob": "/*\n * ws protocol handler plugin for \u0022lws-minimal\u0022 demonstrating multithread\n *\n * Written in 2010-2019 by Andy Green \u003candy@warmcat.com\u003e\n *\n * This file is made available under the Creative Commons CC0 1.0\n * Universal Public Domain Dedication.\n */\n\n#if !defined (LWS_PLUGIN_STATIC)\n#define LWS_DLL\n#define LWS_INTERNAL\n#include \u003clibwebsockets.h\u003e\n#endif\n\n#include \u003cstring.h\u003e\n\n/* one of these created for each message in the ringbuffer */\n\nstruct msg {\n\tvoid *payload; /* is malloc'd */\n\tsize_t len;\n};\n\n/*\n * One of these is created for each client connecting to us.\n *\n * It is ONLY read or written from the lws service thread context.\n */\n\nstruct per_session_data__minimal {\n\tstruct per_session_data__minimal *pss_list;\n\tstruct lws *wsi;\n\tuint32_t tail;\n};\n\n/* one of these is created for each vhost our protocol is used with */\n\nstruct per_vhost_data__minimal {\n\tstruct lws_context *context;\n\tstruct lws_vhost *vhost;\n\tconst struct lws_protocols *protocol;\n\n\tstruct per_session_data__minimal *pss_list; /* linked-list of live pss*/\n\tpthread_t pthread_spam[2];\n\n\tpthread_mutex_t lock_ring; /* serialize access to the ring buffer */\n\tstruct lws_ring *ring; /* {lock_ring} ringbuffer holding unsent content */\n\n\tconst char *config;\n\tchar finished;\n};\n\n#if defined(WIN32)\nstatic void usleep(unsigned long l) { Sleep(l / 1000); }\n#endif\n\n/*\n * This runs under both lws service and \u0022spam threads\u0022 contexts.\n * Access is serialized by vhd-\u003elock_ring.\n */\n\nstatic void\n__minimal_destroy_message(void *_msg)\n{\n\tstruct msg *msg \u003d _msg;\n\n\tfree(msg-\u003epayload);\n\tmsg-\u003epayload \u003d NULL;\n\tmsg-\u003elen \u003d 0;\n}\n\n/*\n * This runs under the \u0022spam thread\u0022 thread context only.\n *\n * We spawn two threads that generate messages with this.\n *\n */\n\nstatic void *\nthread_spam(void *d)\n{\n\tstruct per_vhost_data__minimal *vhd \u003d\n\t\t\t(struct per_vhost_data__minimal *)d;\n\tstruct msg amsg;\n\tint len \u003d 128, index \u003d 1, n, whoami \u003d 0;\n\n\tfor (n \u003d 0; n \u003c (int)LWS_ARRAY_SIZE(vhd-\u003epthread_spam); n++)\n\t\tif (pthread_equal(pthread_self(), vhd-\u003epthread_spam[n]))\n\t\t\twhoami \u003d n + 1;\n\n\tdo {\n\t\t/* don't generate output if nobody connected */\n\t\tif (!vhd-\u003epss_list)\n\t\t\tgoto wait;\n\n\t\tpthread_mutex_lock(\u0026vhd-\u003elock_ring); /* --------- ring lock { */\n\n\t\t/* only create if space in ringbuffer */\n\t\tn \u003d (int)lws_ring_get_count_free_elements(vhd-\u003ering);\n\t\tif (!n) {\n\t\t\tlwsl_user(\u0022dropping!\u005cn\u0022);\n\t\t\tgoto wait_unlock;\n\t\t}\n\n\t\tamsg.payload \u003d malloc(LWS_PRE + len);\n\t\tif (!amsg.payload) {\n\t\t\tlwsl_user(\u0022OOM: dropping\u005cn\u0022);\n\t\t\tgoto wait_unlock;\n\t\t}\n\t\tn \u003d lws_snprintf((char *)amsg.payload + LWS_PRE, len,\n\t\t\t \u0022%s: tid: %d, msg: %d\u0022, vhd-\u003econfig,\n\t\t\t whoami, index++);\n\t\tamsg.len \u003d n;\n\t\tn \u003d lws_ring_insert(vhd-\u003ering, \u0026amsg, 1);\n\t\tif (n !\u003d 1) {\n\t\t\t__minimal_destroy_message(\u0026amsg);\n\t\t\tlwsl_user(\u0022dropping!\u005cn\u0022);\n\t\t} else\n\t\t\t/*\n\t\t\t * This will cause a LWS_CALLBACK_EVENT_WAIT_CANCELLED\n\t\t\t * in the lws service thread context.\n\t\t\t */\n\t\t\tlws_cancel_service(vhd-\u003econtext);\n\nwait_unlock:\n\t\tpthread_mutex_unlock(\u0026vhd-\u003elock_ring); /* } ring lock ------- */\n\nwait:\n\t\tusleep(100000);\n\n\t} while (!vhd-\u003efinished);\n\n\tlwsl_notice(\u0022thread_spam %d exiting\u005cn\u0022, whoami);\n\n\tpthread_exit(NULL);\n\n\treturn NULL;\n}\n\n/* this runs under the lws service thread context only */\n\nstatic int\ncallback_minimal(struct lws *wsi, enum lws_callback_reasons reason,\n\t\t\tvoid *user, void *in, size_t len)\n{\n\tstruct per_session_data__minimal *pss \u003d\n\t\t\t(struct per_session_data__minimal *)user;\n\tstruct per_vhost_data__minimal *vhd \u003d\n\t\t\t(struct per_vhost_data__minimal *)\n\t\t\tlws_protocol_vh_priv_get(lws_get_vhost(wsi),\n\t\t\t\t\tlws_get_protocol(wsi));\n\tconst struct lws_protocol_vhost_options *pvo;\n\tconst struct msg *pmsg;\n\tvoid *retval;\n\tint n, m, r \u003d 0;\n\n\tswitch (reason) {\n\tcase LWS_CALLBACK_PROTOCOL_INIT:\n\t\t/* create our per-vhost struct */\n\t\tvhd \u003d lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),\n\t\t\t\tlws_get_protocol(wsi),\n\t\t\t\tsizeof(struct per_vhost_data__minimal));\n\t\tif (!vhd)\n\t\t\treturn 1;\n\n\t\tpthread_mutex_init(\u0026vhd-\u003elock_ring, NULL);\n\n\t\t/* recover the pointer to the globals struct */\n\t\tpvo \u003d lws_pvo_search(\n\t\t\t(const struct lws_protocol_vhost_options *)in,\n\t\t\t\u0022config\u0022);\n\t\tif (!pvo || !pvo-\u003evalue) {\n\t\t\tlwsl_err(\u0022%s: Can't find \u005c\u0022config\u005c\u0022 pvo\u005cn\u0022, __func__);\n\t\t\treturn 1;\n\t\t}\n\t\tvhd-\u003econfig \u003d pvo-\u003evalue;\n\n\t\tvhd-\u003econtext \u003d lws_get_context(wsi);\n\t\tvhd-\u003eprotocol \u003d lws_get_protocol(wsi);\n\t\tvhd-\u003evhost \u003d lws_get_vhost(wsi);\n\n\t\tvhd-\u003ering \u003d lws_ring_create(sizeof(struct msg), 8,\n\t\t\t\t\t __minimal_destroy_message);\n\t\tif (!vhd-\u003ering) {\n\t\t\tlwsl_err(\u0022%s: failed to create ring\u005cn\u0022, __func__);\n\t\t\treturn 1;\n\t\t}\n\n\t\t/* start the content-creating threads */\n\n\t\tfor (n \u003d 0; n \u003c (int)LWS_ARRAY_SIZE(vhd-\u003epthread_spam); n++)\n\t\t\tif (pthread_create(\u0026vhd-\u003epthread_spam[n], NULL,\n\t\t\t\t\t thread_spam, vhd)) {\n\t\t\t\tlwsl_err(\u0022thread creation failed\u005cn\u0022);\n\t\t\t\tr \u003d 1;\n\t\t\t\tgoto init_fail;\n\t\t\t}\n\t\tbreak;\n\n\tcase LWS_CALLBACK_PROTOCOL_DESTROY:\ninit_fail:\n\t\tvhd-\u003efinished \u003d 1;\n\t\tfor (n \u003d 0; n \u003c (int)LWS_ARRAY_SIZE(vhd-\u003epthread_spam); n++)\n\t\t\tif (vhd-\u003epthread_spam[n])\n\t\t\t\tpthread_join(vhd-\u003epthread_spam[n], \u0026retval);\n\n\t\tif (vhd-\u003ering)\n\t\t\tlws_ring_destroy(vhd-\u003ering);\n\n\t\tpthread_mutex_destroy(\u0026vhd-\u003elock_ring);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_ESTABLISHED:\n\t\t/* add ourselves to the list of live pss held in the vhd */\n\t\tlws_ll_fwd_insert(pss, pss_list, vhd-\u003epss_list);\n\t\tpss-\u003etail \u003d lws_ring_get_oldest_tail(vhd-\u003ering);\n\t\tpss-\u003ewsi \u003d wsi;\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLOSED:\n\t\t/* remove our closing pss from the list of live pss */\n\t\tlws_ll_fwd_remove(struct per_session_data__minimal, pss_list,\n\t\t\t\t pss, vhd-\u003epss_list);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_SERVER_WRITEABLE:\n\t\tpthread_mutex_lock(\u0026vhd-\u003elock_ring); /* --------- ring lock { */\n\n\t\tpmsg \u003d lws_ring_get_element(vhd-\u003ering, \u0026pss-\u003etail);\n\t\tif (!pmsg) {\n\t\t\tpthread_mutex_unlock(\u0026vhd-\u003elock_ring); /* } ring lock ------- */\n\t\t\tbreak;\n\t\t}\n\n\t\t/* notice we allowed for LWS_PRE in the payload already */\n\t\tm \u003d lws_write(wsi, ((unsigned char *)pmsg-\u003epayload) + LWS_PRE,\n\t\t\t pmsg-\u003elen, LWS_WRITE_TEXT);\n\t\tif (m \u003c (int)pmsg-\u003elen) {\n\t\t\tpthread_mutex_unlock(\u0026vhd-\u003elock_ring); /* } ring lock ------- */\n\t\t\tlwsl_err(\u0022ERROR %d writing to ws socket\u005cn\u0022, m);\n\t\t\treturn -1;\n\t\t}\n\n\t\tlws_ring_consume_and_update_oldest_tail(\n\t\t\tvhd-\u003ering,\t/* lws_ring object */\n\t\t\tstruct per_session_data__minimal, /* type of objects with tails */\n\t\t\t\u0026pss-\u003etail,\t/* tail of guy doing the consuming */\n\t\t\t1,\t\t/* number of payload objects being consumed */\n\t\t\tvhd-\u003epss_list,\t/* head of list of objects with tails */\n\t\t\ttail,\t\t/* member name of tail in objects with tails */\n\t\t\tpss_list\t/* member name of next object in objects with tails */\n\t\t);\n\n\t\t/* more to do? */\n\t\tif (lws_ring_get_element(vhd-\u003ering, \u0026pss-\u003etail))\n\t\t\t/* come back as soon as we can write more */\n\t\t\tlws_callback_on_writable(pss-\u003ewsi);\n\n\t\tpthread_mutex_unlock(\u0026vhd-\u003elock_ring); /* } ring lock ------- */\n\t\tbreak;\n\n\tcase LWS_CALLBACK_RECEIVE:\n\t\tbreak;\n\n\tcase LWS_CALLBACK_EVENT_WAIT_CANCELLED:\n\t\tif (!vhd)\n\t\t\tbreak;\n\t\t/*\n\t\t * When the \u0022spam\u0022 threads add a message to the ringbuffer,\n\t\t * they create this event in the lws service thread context\n\t\t * using lws_cancel_service().\n\t\t *\n\t\t * We respond by scheduling a writable callback for all\n\t\t * connected clients.\n\t\t */\n\t\tlws_start_foreach_llp(struct per_session_data__minimal **,\n\t\t\t\t ppss, vhd-\u003epss_list) {\n\t\t\tlws_callback_on_writable((*ppss)-\u003ewsi);\n\t\t} lws_end_foreach_llp(ppss, pss_list);\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn r;\n}\n\n#define LWS_PLUGIN_PROTOCOL_MINIMAL \u005c\n\t{ \u005c\n\t\t\u0022lws-minimal\u0022, \u005c\n\t\tcallback_minimal, \u005c\n\t\tsizeof(struct per_session_data__minimal), \u005c\n\t\t128, \u005c\n\t\t0, NULL, 0 \u005c\n\t}\n","s":{"c":1606540166,"u": 352}} ],"g": 1579,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 1, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}