xwords/xwords4/linux/gsrcwrap.c
Eric House 55e36e10a7 new script to run many games per device
I need it to be much closer to Android....
2023-11-27 21:32:43 -08:00

188 lines
5.8 KiB
C

/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 2020 by Eric House (xwords@eehouse.org). All rights reserved.
*
* 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.
*/
#include <glib.h>
#include <time.h>
#include <stdbool.h>
#include "gsrcwrap.h"
#include "xptypes.h"
#include "comtypes.h"
#define TAG __FILE__ ": "
typedef struct _WrapperState {
union {
GSourceFunc srcProc;
GIOFunc ioProc;
} proc;
void* data;
const char* caller;
const char* procName;
struct timespec spec;
} WrapperState;
static GSList* s_idleProcs = NULL;
static pthread_mutex_t s_idleProcsMutex = PTHREAD_MUTEX_INITIALIZER;
static void
printElapsedFor( struct timespec* first, struct timespec* second,
const char* proc, const char* action )
{
XP_USE( proc );
XP_USE( action );
time_t secs = second->tv_sec - first->tv_sec;
long nsecs = second->tv_nsec - first->tv_nsec;
while ( nsecs < 0 ) {
++secs;
nsecs += 1000000000;
}
/* float firstSecs = (float)first->tv_sec + (((float)first->tv_nsec)/1000000000.0f); */
/* float secondSecs = (float)second->tv_sec + (((float)second->tv_nsec)/1000000000.0f); */
/* XP_LOGF( TAG "elapsed %s %s(): %ld.%ld", action, proc, secs, nsecs ); */
}
static gint
idle_wrapper( gpointer data )
{
WrapperState* state = (WrapperState*)data;
/* XP_LOGF( TAG "%s(): CALLED for %s", __func__, state->procName ); */
struct timespec callTime;
clock_gettime(CLOCK_REALTIME, &callTime);
printElapsedFor( &state->spec, &callTime, state->procName, "scheduling" );
gint result = (*state->proc.srcProc)(state->data);
struct timespec returnTime;
clock_gettime( CLOCK_REALTIME, &returnTime );
printElapsedFor( &callTime, &returnTime, state->procName, "running" );
#ifdef DEBUG
const char* procName = state->procName;
XP_USE( procName );
#endif
if ( 0 == result ) { /* won't be getting called again */
pthread_mutex_lock( &s_idleProcsMutex );
s_idleProcs = g_slist_remove( s_idleProcs, state );
pthread_mutex_unlock( &s_idleProcsMutex );
g_free( state );
}
/* XP_LOGF( TAG "%s(): DONE for %s; now have %d", __func__, procName, */
/* g_slist_length(s_idleProcs) ); */
return result;
}
guint
_wrapIdle( GSourceFunc function, gpointer data,
const char* procName, const char* caller )
{
/* XP_LOGF( TAG "%s(): installing proc %s from caller %s", __func__, */
/* procName, caller ); */
WrapperState* state = g_malloc0( sizeof(*state) );
pthread_mutex_lock( &s_idleProcsMutex );
s_idleProcs = g_slist_append( s_idleProcs, state );
pthread_mutex_unlock( &s_idleProcsMutex );
state->proc.srcProc = function;
state->data = data;
state->caller = caller;
state->procName = procName;
clock_gettime(CLOCK_REALTIME, &state->spec);
guint res = g_idle_add( idle_wrapper, state );
/* XP_LOGF( TAG "%s(): added idle for %s; now have %d", __func__, */
/* procName, g_slist_length(s_idleProcs) ); */
return res;
}
#define TRY_ONE(FLAG) \
if ((condition & FLAG) == FLAG) { \
offset += snprintf( &buf[offset], len - offset, #FLAG " " ); \
}
static void
formatFlags( char* buf, size_t len, GIOCondition condition )
{
int offset = 0;
TRY_ONE(G_IO_IN);
TRY_ONE(G_IO_HUP);
TRY_ONE(G_IO_ERR);
TRY_ONE(G_IO_PRI);
}
static gboolean
watch_wrapper( GIOChannel* source, GIOCondition condition, gpointer data )
{
WrapperState* state = (WrapperState*)data;
char buf[128] = {0};
formatFlags( buf, VSIZE(buf), condition );
/* XP_LOGF( TAG "%s(%s): CALLED; flags: %s", __func__, state->procName, buf ); */
struct timespec callTime;
clock_gettime(CLOCK_REALTIME, &callTime);
bool keep = (*state->proc.ioProc)(source, condition, state->data);
struct timespec returnTime;
clock_gettime( CLOCK_REALTIME, &returnTime );
printElapsedFor( &callTime, &returnTime, state->procName, "running" );
/* XP_LOGF( TAG "%s(%s): DONE", __func__, state->procName ); */
if ( 0 == keep ) { /* won't be getting called again */
// g_source_destroy( source );
g_free( state );
}
return keep;
}
guint
_wrapWatch( gpointer data, int socket, GIOFunc ioProc,
const char* procName, const char* caller )
{
/* XP_LOGF( TAG "%s(): installing proc %s from caller %s", __func__, */
/* procName, caller ); */
WrapperState* state = g_malloc0( sizeof(*state) );
state->proc.ioProc = ioProc;
state->data = data;
state->caller = caller;
state->procName = procName;
GIOChannel* channel = g_io_channel_unix_new( socket );
guint watch = g_io_add_watch( channel,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
watch_wrapper, state );
g_io_channel_unref( channel ); /* only main loop holds it now */
/* XP_LOGF( TAG "%s(): added watch for %s", __func__, procName ); */
return watch;
}
void
gsw_logIdles()
{
XP_LOGF( TAG "%s(): %d idles pending", __func__, g_slist_length(s_idleProcs) );
}