Preliminary stab at app scan locking; pndnotifyd creates logfile /tmp/whatever and...
authorskeezix <skeezix@flotsam-vm.(none)>
Thu, 12 Jan 2012 21:53:22 +0000 (16:53 -0500)
committerskeezix <skeezix@flotsam-vm.(none)>
Thu, 12 Jan 2012 21:53:22 +0000 (16:53 -0500)
mmenu will ignore 'old' lockfile (2 minutes or more), and for recent lockfile (<2mins) it will check every half second
for up to 20 times (10 seconds)
mmenu is configured in mmenu.conf so these settings can be fiddled with

apps/pndnotifyd.c
deployment/etc/pandora/conf/mmenu.conf
include/pnd_utility.h
lib/pnd_utility.c
minimenu/mmenu.c
minimenu/mmenu.conf

index fd1c1a1..b8ce530 100644 (file)
@@ -73,6 +73,7 @@ unsigned char g_info_p = 0; // spit out info .desktops
 
 // constants
 #define PNDNOTIFYD_LOGLEVEL "pndnotifyd.loglevel"
+#define PNDLOCKNAME "pndnotifyd-disco.lock"
 
 // decl's
 void consume_configuration ( void );
@@ -815,6 +816,13 @@ unsigned char perform_discoveries ( char *appspath, char *overridespath,
   pnd_log ( pndn_rem, "perform discovery - apps: %s, overrides: %s\n", appspath, overridespath );
   pnd_log ( pndn_rem, "                  - emit desktop: %s, icons: %s\n", emitdesktoppath, emiticonpath );
 
+  // do some 'locking'
+  pnd_log ( pndn_rem, "creating lockfile %s", PNDLOCKNAME );
+
+  if ( ! pnd_lock ( PNDLOCKNAME ) ) {
+    // problem .. well, too bad, we need to do this .. proceed!
+  }
+
   // attempt to auto-discover applications in the given path
   applist = pnd_disco_search ( appspath, overridespath );
 
@@ -907,5 +915,9 @@ unsigned char perform_discoveries ( char *appspath, char *overridespath,
     pnd_box_delete ( applist ); // does not free the disco_t contents!
   }
 
+  // close the lock
+  pnd_log ( pndn_rem, "clearing lockfile %s", PNDLOCKNAME );
+  pnd_unlock ( PNDLOCKNAME );
+
   return ( 1 );
 }
index 496dac3..69e2e57 100644 (file)
@@ -32,6 +32,9 @@ desktop_apps          1       # search the pnd standard desktop searchpath for apps
 menu_apps              1       # search the pnd standard menu searchpath for apps
 aux_searchpath         /media/*/pandora/mmenu:/usr/pandora/mmenu # if something here, also search this path; can be used for mmenu-only apps?
 auto_rescan            1       # if >0, will automaticly rescan for applications, if SD inserts/ejects
+disco_lock_max         20      # number of tries to check lock (at 1/5th sec each, 20 == 4 seconds)
+disco_lock_usec_delta  500000  # number of usec between lockfile checks; 200000 is 1/5th second
+disco_lock_maxage_s    120     # number of seconds .. if lockfile is that old or older, just ignore it entirely
 
 [utility]
 terminal               /usr/bin/Terminal       # could also be /usr/bin/xterm, or a sh-script, or whatever
index e468258..09ea621 100644 (file)
@@ -6,6 +6,8 @@
 extern "C" {
 #endif
 
+#include <time.h>
+
 // expand_tilde() will only function correctly if a user is actually logged in; perhaps you
 // want to spin until it looks like someone has in fact done so. (most devices will likely
 // have auto-login, but its not instantaneous!)
@@ -30,6 +32,17 @@ unsigned char pnd_determine_mountpoint ( char *fullpath, char *r_mountpoint, uns
 // filecopy will return >0 on success
 unsigned char pnd_filecopy ( char *sourcepath, char *targetpath );
 
+// some lame file locking utility (not using 'flock')
+// ** This is not race condition safe, so not for serious locking; this is just for casual locking, not high speed
+#define PND_LOCK_PATH "/tmp" /* default path to stick lockfiles */
+unsigned char pnd_lock ( char *lockname ); // return 0 on fail, >0 on success; lock file, not semaphore/etc
+time_t pnd_is_locked ( char *lockname );   // return 0 on unlocked, >0 is epoch time when locked
+void pnd_unlock ( char *lockname );        // assumes success
+// wait 'max' occurances of microseconds (usleep) for unlock
+// if max is 0, will not wait at all (will just check, same as pnd_is_locked())
+// return '1' for unlock (may be immediate), 0 for failed 'max' timse
+unsigned char pnd_wait_for_unlock ( char *lockname, unsigned short int max, unsigned int usec_delta );
+
 #ifdef __cplusplus
 } /* "C" */
 #endif
index 9647f20..de2a2b7 100644 (file)
@@ -9,7 +9,9 @@
 #include <sys/types.h> /* ditto */
 #include <pwd.h> /* ditto */
 #include <sys/stat.h> /* for fstat */
+#include <errno.h> /* for stat->ENOENT */
 #include <dirent.h> /* for opendir */
+#include <fcntl.h> /* for creat */
 
 #include "pnd_pxml.h"
 #include "pnd_container.h"
@@ -361,3 +363,71 @@ unsigned char pnd_filecopy ( char *sourcepath, char *targetpath ) {
 
   return ( 1 );
 }
+
+unsigned char pnd_lock ( char *lockname ) {
+
+  if ( pnd_is_locked ( lockname ) ) {
+    return ( 0 ); // already locked
+  }
+
+  char fullpath [ PATH_MAX ];
+  int fd;
+
+  snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
+
+  if ( ( fd = creat ( fullpath, 0400 ) < 0 ) ) {
+    return ( 0 ); // error, yeah, I know, no way to know why it failed..
+  }
+
+  close ( fd );
+
+  return ( 1 );
+}
+
+time_t pnd_is_locked ( char *lockname ) {
+  char fullpath [ PATH_MAX ];
+  int rv;
+  snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
+
+  struct stat statbuf;
+  rv = stat ( fullpath, &statbuf );
+
+  if ( rv == ENOENT ) {
+    return ( 0 ); // file not existk, so no lock
+  } else if ( rv < 0 ) {
+    return ( 0 ); // assume unlocked for error, so app can continue?
+  }
+
+  return ( statbuf.st_mtime );
+}
+
+void pnd_unlock ( char *lockname ) {
+  char fullpath [ PATH_MAX ];
+  snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
+
+  unlink ( fullpath );
+
+  return;
+}
+
+unsigned char pnd_wait_for_unlock ( char *lockname, unsigned short int max, unsigned int usec_delta ) {
+
+  // check right off the top
+  if ( ! pnd_is_locked ( lockname ) ) {
+    return ( 1 ); // all clear!
+  }
+
+  unsigned short int count = 0;
+  while ( count < max ) {
+
+    if ( ! pnd_is_locked ( lockname ) ) {
+      return ( 1 ); // all clear!
+    }
+
+    usleep ( usec_delta );
+
+    count++;
+  }
+
+  return ( 0 );
+}
index 78b3683..919b509 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/wait.h>
 #include <dirent.h>
 #include <signal.h> // for sigaction
+#include <time.h>
 
 #include "pnd_logger.h"
 #include "pnd_pxml.h"
@@ -61,6 +62,8 @@
 #include "mmui.h"
 #include "mmconf.h"
 
+#define PNDLOCKNAME "pndnotifyd-disco.lock" /* from pndnotifyd */
+
 pnd_box_handle g_active_apps = NULL;
 unsigned int g_active_appcount = 0;
 char g_username [ 128 ]; // since we have to wait for login (!!), store username here
@@ -597,6 +600,35 @@ void applications_scan ( void ) {
   // perform app discovery on .desktop files?
   //
   if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_dotdesktop", 0 ) ) {
+
+    // deal with locks
+    pnd_log ( pndn_debug, "Checking pndnotifyd disco lock %s\n", PNDLOCKNAME );
+
+    //   first, check if lock is 'old' -- maybe locker crashed, or if its old enough.. its just good, right?
+    time_t age = pnd_is_locked ( PNDLOCKNAME );
+
+    if ( age == 0 ) {
+      pnd_log ( pndn_debug, "Lock is all clear %s so no need to wait\n", PNDLOCKNAME );
+
+    } else if ( time ( NULL ) - age > pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_maxage_s", 120 ) ) {
+      // lock seems old, so who cares
+      pnd_log ( pndn_debug, "Lock is OLD so ignoring it: %s\n", PNDLOCKNAME );
+
+    } else {
+      // not too old, so lets wait.. we could be booting up!
+
+      int rv = pnd_wait_for_unlock ( PNDLOCKNAME,
+                                    pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_max", 20 ),
+                                    pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_usec_delta", 500000 ) );
+      if ( rv ) {
+       pnd_log ( pndn_debug, "Waited for lock and is now clear %s\n", PNDLOCKNAME );
+      } else {
+       pnd_log ( pndn_debug, "Waited for lock and timed out %s .. proceeding anyway.\n", PNDLOCKNAME );
+      }
+
+    } // locking
+
+    // where to scan..
     char *chunks[10] = {
       pnd_conf_get_as_char ( g_desktopconf, "desktop.dotdesktoppath" ),
       pnd_conf_get_as_char ( g_desktopconf, "menu.dotdesktoppath" ),
index 70cb134..fb642e4 100644 (file)
@@ -32,6 +32,9 @@ desktop_apps          1       # search the pnd standard desktop searchpath for apps
 menu_apps              1       # search the pnd standard menu searchpath for apps
 aux_searchpath         /media/*/pandora/mmenu # if something here, also search this path; can be used for mmenu-only apps?
 auto_rescan            1       # if >0, will automaticly rescan for applications, if SD inserts/ejects
+disco_lock_max         20      # number of tries to check lock (at 1/5th sec each, 20 == 4 seconds)
+disco_lock_usec_delta  500000  # number of usec between lockfile checks; 200000 is 1/5th second
+disco_lock_maxage_s    120     # number of seconds .. if lockfile is that old or older, just ignore it entirely
 
 [utility]
 terminal               /usr/bin/Terminal       # could also be /usr/bin/xterm, or a sh-script, or whatever