FORT sisäisten satunnaistapahtumien lisääminen uudistunut

Tässä postissa esitelty tapa helpottaa fort koodin lukemista ja ohjelmasi omien tapahtumien lisäämistä. Tämä lyhentää koodia runsaasti ja helpottanee sen ymmärtämistä. Jos lisäät tapahtumia omaan ohjelmaasi, tee makroista ja internal_events -muuttujasta uudet versiot ilman internal sanaa. Ennen satunnaistapahtumat lisättiin seuraavalla lohkojen alkuun ja loppuun lisättävällä koodilla: Tässä lähetetään satunnaistapahtumia, joiden source on 10 ja 11.

void hash_init(HashCtx *hash)
{
#ifdef FORT_INTERNAL_EVENTS
  unsigned long micros;
  if(fort_internal_events) {
    fort_add_random_event_time(&time_pool,
        10, fort_event_mode);
    fort_add_random_event_timer_start(&micros);
  }
#endif
  HashInit(hash);
#ifdef FORT_INTERNAL_EVENTS
  if(fort_internal_events)
    fort_add_random_event_timer_do(&init_pool,
        11, fort_event_mode, &micros);
#endif
}

Uudessa versiossa tehdään seuraavat uudet #define määritykset: FORT_INTERNAL_EVENTS_START on lohkon alkuun lisättävä makro ja FORT_INTERNAL_EVENTS_END on lohkon loppuun lisättävä makro. Nämä periaatteessa sisältävät nuo edelliset satunnaistapahtumien koodilohkot, mutta ne kirjoitetaan vain kerran makron määritykseen, ei enää uudestaan joka käyttökerralla. Nämä uudet makrot sisältävät myös pool ja pool2 määrittelyt, eli int-muuttujat joissa talletetaan seuraavan tapahtuman puskurinumero. Static tyyppisinä nämä tuntuvat toimivan niinkuin halutaan, eli että jokaisella lohkolla on omat muuttujansa, jopa sisäkkäisillä, ja että kenttien arvot säilyvät funktion ajokerrasta seuraavaan. Pool muuttujaa käytetään aikatapahtumiin ja pool2 muuttujaa käytetään kestotapahtumiin. Tosin ennen aikatapahtumille oli vain yksi pool-muuttuja, nyt niitä on oma jokaiselle FORT_INTERNAL_EVENTS lohkolle.

#ifdef FORT_INTERNAL_EVENTS
#define FORT_INTERNAL_EVENTS_START(source) \
  unsigned long micros; \
  static int pool=0, pool2=0; \
  if(fort_internal_events) { \
    fort_add_random_event_time(&pool, source, \
        fort_event_mode); \
    fort_add_random_event_timer_start(&micros); \
  }
#else
#define FORT_INTERNAL_EVENTS_START(source)
#endif

#ifdef FORT_INTERNAL_EVENTS
#define FORT_INTERNAL_EVENTS_END(source) \
  if(fort_internal_events) \
    fort_add_random_event_timer_do(&pool2, \
        source, fort_event_mode, &micros);
#else
#define FORT_INTERNAL_EVENTS_END(source)
#endif

Näiden makrojen avulla koodista tulee luettavampaa ja enää ei koodata erillisiä _pool-loppuisia muuttujia. Seuraavassa edellinen hash_init kirjoitettuna näillä uusilla makroilla: Sulkeissa kerrottu arvo on source kentän arvo. Huomaa että makrorivien lopussa ei ole puolipistettä (;).

void hash_init(HashCtx *hash)
{
  FORT_INTERNAL_EVENTS_START(10)

  HashInit(hash);

  FORT_INTERNAL_EVENTS_END(11)
}
Tässä vielä esimerkki pidemmästä rutiinista:
void fort_random_data(int len, unsigned char *buf)
{
  int c;
  unsigned long tenths;
  HashCtx hash;
  unsigned char buffer[HashLen];

  FORT_INTERNAL_EVENTS_START(22)

  tenths=gettenths();

  if( (fort_reseed_always==1) ||
      (fort_next_reseed==0) ||
      (fort_next_reseed<=tenths &&
       fort_pools[0].length >=
           FORT_MIN_POOL_SIZE) ) {

    // next tenth of a second
    fort_next_reseed = tenths + 1;                                                                                                                                                                                                                                                      
    fort_reseed_count++;

    hash_init(&hash);
    c=0;

    while(c < 32 &&
        (fort_reseed_count % (1<<c))==0) {

      FORT_INTERNAL_EVENTS_START(23)

#ifdef RESSU
      if(fort_fill_pool_when_reseeding==1 &&
         fort_pools[c].length <
              FORT_MIN_POOL_SIZE) {
        unsigned char tmp32[32];
        int len=FORT_MIN_POOL_SIZE -
            fort_pools[c].length;
        int n;

        while(len>0) {

          FORT_INTERNAL_EVENTS_START(24)

          n=(len<sizeof(tmp32)) ? len :
              sizeof(tmp32);
          ressu_genbuffer(n, tmp32);

          int pooltemp=c;
          fort_add_random_event(&pooltemp, 29,
              fort_event_mode, n, tmp32);
          len-=n;

          FORT_INTERNAL_EVENTS_END(25)
        } // while(len>0)
      } // if(fort_fill...
#endif
      hash_final(buffer, &fort_pools[c].pool);
      hash_update(&hash, buffer, sizeof(buffer));
      fort_pools[c].length = 0;
      HashInit(&fort_pools[c].pool);
      // save earlier pool to new one
      hash_update(&fort_pools[c].pool,
          buffer, sizeof(buffer));                                                                                                                                                                                                                   
      c++;

      FORT_INTERNAL_EVENTS_END(26)
    } // while(c < 32...
    hash_update(&hash, (unsigned char *)&cvar,
        sizeof(cvar));
    hash_final(buffer, &hash);
    fort_reseed(sizeof(buffer), buffer);
    // Forget hash context
    memset(&hash, 0, sizeof(hash));
    /* Forget reseed key */
    memset(buffer, 0, sizeof(buffer));
    inccvar();
  } // if( (fort_reseed...
  fort_pseudo_random_data(len, buf);

  FORT_INTERNAL_EVENTS_END(27)
}