summaryrefslogtreecommitdiff
path: root/plugins/!NotAdopted/VypressChat/msgloop.c
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2013-04-02 13:54:21 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2013-04-02 13:54:21 +0000
commitff5a775b94465b30897964630af600fe5915fc51 (patch)
treef79e36c79faf7095ca6f02f6b7fea0f6e81bf085 /plugins/!NotAdopted/VypressChat/msgloop.c
parent8d3307adf7ba64b75fb4de363f873c97286b0e9b (diff)
VypressChat added (not adopted)
git-svn-id: http://svn.miranda-ng.org/main/trunk@4285 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/!NotAdopted/VypressChat/msgloop.c')
-rw-r--r--plugins/!NotAdopted/VypressChat/msgloop.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/plugins/!NotAdopted/VypressChat/msgloop.c b/plugins/!NotAdopted/VypressChat/msgloop.c
new file mode 100644
index 0000000000..6815394c07
--- /dev/null
+++ b/plugins/!NotAdopted/VypressChat/msgloop.c
@@ -0,0 +1,248 @@
+/*
+ * Miranda-IM Vypress Chat/quickChat plugins
+ * Copyright (C) Saulius Menkevicius
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: msgloop.c,v 1.13 2005/03/08 17:42:25 bobas Exp $
+ */
+
+#include "main.h"
+#include "msgloop.h"
+#include "pthread.h"
+
+/* constants and struct defs
+ */
+
+/* max packet output rate is 2 packets per sec */
+#define PACKET_OUTPUT_RATE 500
+
+struct msgloop_message_list_entry {
+ struct msgloop_message_list_entry * prev, * next;
+ vqp_msg_t msg;
+};
+
+/* static data
+ */
+static PAPCFUNC s_lpfnMsgHandleApc;
+static HANDLE s_hMainThread, s_hLoopThread;
+static BOOL s_fStopLoop = TRUE,
+ s_fLoopStarted;
+static HANDLE s_hStopWaitEvent;
+
+static UINT_PTR s_outputTimer;
+static struct msgloop_message_list_entry
+ * s_outputListHead, * s_outputListTail;
+static BOOL s_outputSentThisTick = FALSE, s_outputSentThisTickInTimer;
+
+/* static routines
+ */
+
+static void CALLBACK msgloop_apc_stop(ULONG_PTR unused)
+{
+ s_fStopLoop = TRUE;
+}
+
+static void CALLBACK msgloop_apc_send_msg(ULONG_PTR vqmsg)
+{
+ vqp_link_send((vqp_msg_t)vqmsg);
+ vqp_msg_free((vqp_msg_t)vqmsg);
+}
+
+static void msgloop_loop(void * vqlink)
+{
+ WSAEVENT hReadEvent;
+ SOCKET rx_socket = vqp_link_rx_socket((vqp_link_t) vqlink);
+
+ s_fLoopStarted = TRUE;
+
+ hReadEvent = WSACreateEvent();
+ WSAEventSelect(rx_socket, hReadEvent, FD_READ);
+
+ while(!Miranda_Terminated() && !s_fStopLoop) {
+ DWORD nEvent = WSAWaitForMultipleEvents(
+ 1, &hReadEvent, FALSE, WSA_INFINITE, TRUE);
+
+ if(nEvent==WSA_WAIT_EVENT_0) {
+ vqp_msg_t msg;
+
+ WSAResetEvent(hReadEvent);
+
+ if(!vqp_link_recv((vqp_link_t) vqlink, &msg)) {
+ QueueUserAPC(
+ s_lpfnMsgHandleApc,
+ s_hMainThread, (ULONG_PTR)msg);
+ }
+ }
+ }
+
+ WSACloseEvent(hReadEvent);
+
+ /* wait for pending user APC */
+ while(SleepEx(10, TRUE) == WAIT_IO_COMPLETION) /* nothing */;
+
+ /* signal that we've finished */
+ SetEvent(s_hStopWaitEvent);
+}
+
+static void CALLBACK msgloop_message_output_timer_cb(
+ HWND hwnd, UINT nmsg, UINT_PTR idevent, DWORD dwtime)
+{
+ if(s_outputListTail && (!s_outputSentThisTick
+ || (s_outputSentThisTick && s_outputSentThisTickInTimer)))
+ {
+ struct msgloop_message_list_entry * entry = s_outputListTail;
+ QueueUserAPC(msgloop_apc_send_msg, s_hLoopThread, (ULONG_PTR)entry->msg);
+
+ s_outputListTail = entry->next;
+ if(s_outputListTail) {
+ s_outputListTail->prev = NULL;
+ } else {
+ s_outputListHead = NULL;
+ }
+
+ free(entry);
+
+ s_outputSentThisTick = TRUE;
+ s_outputSentThisTickInTimer = TRUE;
+ } else {
+ s_outputSentThisTick = FALSE;
+ }
+}
+
+/* exported routines
+ */
+
+/* msgloop_start:
+ * starts msg loop
+ */
+void msgloop_start(vqp_link_t vqlink, PAPCFUNC lpfMsgHandlerApc)
+{
+ ASSERT_RETURNIFFAIL(s_fStopLoop);
+
+ s_lpfnMsgHandleApc = lpfMsgHandlerApc;
+ DuplicateHandle(
+ GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &s_hMainThread,
+ THREAD_SET_CONTEXT, FALSE, 0);
+
+ s_fStopLoop = FALSE;
+ s_fLoopStarted = FALSE; /* this will be set in msgloop_loop() */
+ s_hLoopThread = (HANDLE)pthread_create(msgloop_loop, (void*)vqlink);
+
+ /* start scheduler timer:
+ * this will make packets to be send no faster than specific rate
+ */
+ s_outputTimer = SetTimer(NULL, 0, PACKET_OUTPUT_RATE, msgloop_message_output_timer_cb);
+ s_outputSentThisTick = FALSE;
+}
+
+/* msgloop_stop:
+ * msgloop_stop should be called from miranda's gui thread
+ * to stop the qcs_msg loop.
+ */
+void msgloop_stop()
+{
+ struct msgloop_message_list_entry * entry;
+
+ ASSERT_RETURNIFFAIL(!s_fStopLoop);
+
+ /* stop packet scheduler timer
+ */
+ KillTimer(NULL, s_outputTimer);
+ s_outputTimer = 0;
+
+ /* signal the thread to stop */
+ s_hStopWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ QueueUserAPC(msgloop_apc_stop, s_hLoopThread, (ULONG_PTR)NULL);
+
+ /* wait for the thread to stop
+ * and handle all the queued APCs
+ */
+ while(WaitForSingleObjectEx(s_hStopWaitEvent, 10, TRUE) == WAIT_IO_COMPLETION)
+ /* do nothing */ ;
+
+ CloseHandle(s_hStopWaitEvent);
+ CloseHandle(s_hMainThread);
+
+ /* do cleanup */
+ s_fLoopStarted = FALSE;
+
+ /* send all the queued packets that didn't get sent
+ * by packet scheduler in msgloop_packet_output_timer_c()
+ */
+ entry = s_outputListTail;
+ while(entry) {
+ struct msgloop_message_list_entry * next = entry->next;
+ vqp_link_send(entry->msg);
+ vqp_msg_free(entry->msg);
+ free(entry);
+
+ entry = next;
+ }
+ s_outputListTail = NULL;
+ s_outputListHead = NULL;
+}
+
+/* msgloop_send:
+ * msgloop_send should be used to send a message from miranda's
+ * gui thread to send a message with qcs_msg loop.
+ */
+void msgloop_send(vqp_msg_t msg, int never_wait)
+{
+ ASSERT_RETURNIFFAIL(VALIDPTR(msg));
+
+ /* send this message */
+ if(s_fLoopStarted && s_outputTimer) {
+ /* check if we've sent a packet this tick,
+ * and if we did, we'll have to wait for the next tick
+ */
+ if(s_outputSentThisTick && !never_wait) {
+ /* add msg to message queue for scheduler timer
+ */
+ struct msgloop_message_list_entry * entry;
+ entry = malloc(sizeof(struct msgloop_message_list_entry));
+ entry->msg = msg;
+ entry->next = NULL;
+ entry->prev = s_outputListHead;
+ if(entry->prev) {
+ entry->prev->next = entry;
+ } else {
+ s_outputListTail = entry;
+ }
+ s_outputListHead = entry;
+ } else {
+ QueueUserAPC(msgloop_apc_send_msg, s_hLoopThread, (ULONG_PTR)msg);
+ s_outputSentThisTick = TRUE;
+ }
+ } else {
+ if(s_outputSentThisTick && !never_wait) {
+ Sleep(PACKET_OUTPUT_RATE);
+ }
+ vqp_link_send(msg);
+ vqp_msg_free(msg);
+ s_outputSentThisTick = TRUE;
+ s_outputSentThisTickInTimer = FALSE;
+ }
+}
+
+/* msgloop_send_to:
+ * sends message to the specified address only
+ */
+void msgloop_send_to(vqp_msg_t msg, int never_wait, vqp_addr_t addr) {
+ vqp_msg_set_dst_addr(msg, addr);
+ msgloop_send(msg, never_wait);
+}
+