Exemple #1
0
static FileMonitor *
gam_kqueue_file_monitor_new (SubMonitor *smon,
			     const char *filename,
			     FileMonitorFlags *flags)
{
  FileMonitor *fmon;
  Monitor *mon;

  fmon = g_new0(FileMonitor, 1);

  mon = MONITOR(fmon);
  mon->handle_kevent = gam_kqueue_file_monitor_handle_kevent;
  mon->pathname = g_build_filename(MONITOR(smon)->pathname, filename, NULL);
  mon->fd = -1;

  fmon->smon = smon;
  fmon->filename = strrchr(mon->pathname, G_DIR_SEPARATOR);
  fmon->filename = fmon->filename ? fmon->filename + 1 : mon->pathname;

  gam_kqueue_hash_table_add(fmon->smon->fmons, fmon);

  if (gam_kqueue_monitor_enable_kqueue(mon))
    *flags = 0;
  else
    {
      gam_kqueue_file_monitor_set_unsupported(fmon);
      *flags = (mon->sb.mode & S_IFDIR) != 0 ? MONITOR_ISDIR : MONITOR_ISNOTDIR;
    }

  return fmon;
}
Exemple #2
0
/**
 * Adds a subscription to be monitored.
 *
 * @param sub a #GamSubscription to be polled
 * @returns TRUE if adding the subscription succeeded, FALSE otherwise
 */
gboolean
gam_kqueue_add_subscription (GamSubscription *sub)
{
  const char *path;
  GHashTable *hash;
  SubMonitor *smon;

  gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);

  path = gam_subscription_get_path(sub);
  hash = gam_subscription_is_dir(sub) ? dir_hash : file_hash;
  smon = g_hash_table_lookup(hash, path);

  if (smon)
    {
      smon->subs = g_list_append(smon->subs, sub);
      return TRUE;
    }
  
  smon = gam_kqueue_sub_monitor_new(sub);
  smon->subs = g_list_append(smon->subs, sub);

  g_hash_table_insert(hash, MONITOR(smon)->pathname, smon);
  gam_kqueue_sub_monitor_enable_notification(smon, 0);

  return TRUE;
}
Exemple #3
0
static void
gam_kqueue_unsupported_fmon_poll_foreach_cb (FileMonitor *fmon,
					     gpointer unused,
					     gpointer user_data)
{
  Monitor *mon = MONITOR(fmon);
  MiniStat sb;
  GaminEventType event;

  if (++mon->poll_count == CFG_UNSUPPORTED_FMON_KQUEUE_RETRY_FREQUENCY)
    {
      mon->poll_count = 0;
      if (gam_kqueue_monitor_enable_kqueue(mon))
	gam_kqueue_hash_table_remove(fmon->smon->unsupported_fmons, fmon);
    }

  gam_kqueue_mini_lstat(mon->pathname, &sb);

  if (! sb.exists && mon->sb.exists)
    event = GAMIN_EVENT_DELETED;
  else if (gam_kqueue_differs(&sb, &mon->sb))
    event = GAMIN_EVENT_CHANGED;
  else
    return;

  memcpy(&mon->sb, &sb, sizeof(sb));
  gam_kqueue_file_monitor_emit_event(fmon, event, (sb.mode & S_IFDIR) != 0 ? MONITOR_ISDIR : MONITOR_ISNOTDIR);
}
Exemple #4
0
static void
gam_kqueue_unsupported_smon_poll (SubMonitor *smon)
{
  Monitor *mon = MONITOR(smon);
  MiniStat sb;
  GaminEventType event;

  if (++mon->poll_count == CFG_UNSUPPORTED_SMON_KQUEUE_RETRY_FREQUENCY)
    {
      mon->poll_count = 0;
      if (gam_kqueue_monitor_enable_kqueue(mon))
	gam_kqueue_poller_remove_sub_monitor(&missing_smon_poller, smon);
    }
  
  gam_kqueue_mini_lstat(mon->pathname, &sb);
  
  if (! sb.exists && mon->sb.exists)
    event = GAMIN_EVENT_DELETED;
  else if (gam_kqueue_differs(&sb, &mon->sb))
    event = GAMIN_EVENT_CHANGED;
  else
    return;
	
  memcpy(&mon->sb, &sb, sizeof(sb));
  gam_kqueue_sub_monitor_emit_event(smon, event, (sb.mode & S_IFDIR) != 0 ? MONITOR_ISDIR : MONITOR_ISNOTDIR);
}
Exemple #5
0
static void
gam_kqueue_sub_monitor_emit_event (SubMonitor *smon,
				   GaminEventType event,
				   SubMonitorFlags flags)
{
  Monitor *mon = MONITOR(smon);
  gboolean isdir;

  isdir = gam_kqueue_isdir(mon->pathname, flags);

  switch (event)
    {
    case GAMIN_EVENT_CHANGED:
      if (smon->isdir)
	{
	  gam_kqueue_sub_monitor_handle_directory_change(smon, isdir);
	  return;
	}
      break;

    case GAMIN_EVENT_DELETED:
    case GAMIN_EVENT_MOVED:
      gam_kqueue_sub_monitor_set_missing(smon);
      break;
    }

  gam_server_emit_event(mon->pathname, isdir, event, smon->subs, 1);
}
Exemple #6
0
int sc_main(int ac, char *av[])
{
  sc_clock clock("Clock", CLOCK_PERIOD, SC_NS, DUTY_CYCLE, 0, SC_NS);
  sc_clock tb_clock("TBClock", TB_CLOCK_PERIOD, SC_NS, DUTY_CYCLE, 0, SC_NS);
  sc_clock mon_clock("MonClock", CLOCK_PERIOD, SC_NS, DUTY_CYCLE, 75, SC_NS);
 
  sc_signal<bool> reset_sig;

  sc_signal<int> i1;
  sc_signal<int> i2;
  sc_signal<int> i3;
  sc_signal<int> i4;
  sc_signal<int> i5;
  
  sc_signal<bool> cont1;
  sc_signal<bool> cont2;
  sc_signal<bool> cont3;
  
  sc_signal<int> o1;
  sc_signal<int> o2;
  sc_signal<int> o3;
  sc_signal<int> o4;
  sc_signal<int> o5;

  test TEST ("TEST", clock, reset_sig, i1, i2, i3, i4, i5,
	 cont1, cont2, cont3, o1, o2, o3, o4, o5);
  tb TB ("TB", tb_clock, reset_sig, i1, i2, i3, i4, i5,
	 cont1, cont2, cont3, o1, o2, o3, o4, o5);
  monitor MONITOR ("MONITOR", mon_clock, reset_sig, i1, i2, i3, i4, i5,
	 cont1, cont2, cont3, o1, o2, o3, o4, o5);

  // Simulation Run Control
  sc_start ();
  return 0;
}
Exemple #7
0
static void
gam_kqueue_sub_monitor_set_missing (SubMonitor *smon)
{
  Monitor *mon = MONITOR(smon);

  if (mon->fd >= 0)
    {
      close(mon->fd);
      mon->fd = -1;

      open_files--;
    }

  /*
   * A removed directory will normally not contain files, but we must
   * not assume it (we might receive events out of order, etc). We
   * therefore check if files are remaining, and if yes, clear them.
   */
  if (g_hash_table_size(smon->fmons->main) > 0)
    {
      gam_kqueue_sub_monitor_clear_fmons(smon);
      gam_kqueue_sub_monitor_init_fmons(smon);
    }

  gam_kqueue_poller_remove_sub_monitor(&unsupported_smon_poller, smon);
  gam_kqueue_poller_add_sub_monitor(&missing_smon_poller, smon);
}
Exemple #8
0
static void
gam_kqueue_file_monitor_set_unsupported (FileMonitor *fmon)
{
  Monitor *mon = MONITOR(fmon);

  gam_kqueue_monitor_set_unsupported(mon);
  gam_kqueue_hash_table_add(fmon->smon->unsupported_fmons, fmon);
}
Exemple #9
0
static void
gam_kqueue_sub_monitor_set_unsupported (SubMonitor *smon)
{
  Monitor *mon = MONITOR(smon);

  gam_kqueue_monitor_set_unsupported(mon);
  gam_kqueue_poller_add_sub_monitor(&unsupported_smon_poller, smon);
}
Exemple #10
0
XsiStatus pluginNotify(void *instance, int type, unsigned arg1, unsigned arg2) {
    switch (type) {
    case START_MONITORING:
        MONITOR(instance)->setMonitoring(true);
        break;

    case STOP_MONITORING:
        MONITOR(instance)->setMonitoring(false);
        break;

    case REPORT_STATUS:
        MONITOR(instance)->reportStatus();
        break;

    default:
        break;
    }
    return XSI_STATUS_OK;
}
Exemple #11
0
static void
gam_kqueue_sub_monitor_free (SubMonitor *smon)
{
  gam_kqueue_poller_remove_sub_monitor(&missing_smon_poller, smon);
  gam_kqueue_poller_remove_sub_monitor(&unsupported_smon_poller, smon);
  /* unsupported_dirs_poller is handled by _clear_fmons() below */
  
  gam_kqueue_sub_monitor_clear_fmons(smon);
  gam_kqueue_monitor_free(MONITOR(smon));
}
Exemple #12
0
static void
gam_kqueue_missing_smon_poll (SubMonitor *smon)
{
  struct stat sb;

  if (lstat(MONITOR(smon)->pathname, &sb) >= 0)
    {
      gam_kqueue_poller_remove_sub_monitor(&missing_smon_poller, smon);
      gam_kqueue_sub_monitor_enable_notification(smon, SUB_MONITOR_WAS_MISSING | ((sb.st_mode & S_IFDIR) != 0 ? MONITOR_ISDIR : MONITOR_ISNOTDIR));
    }
}
Exemple #13
0
static gboolean
gam_kqueue_kevent_cb (GIOChannel *source,
		      GIOCondition condition,
		      gpointer user_data)
{
  int nevents;
  struct kevent ev[1];
  struct timespec timeout = { 0, 0 };
  int i;

  nevents = kevent(kq, NULL, 0, ev, G_N_ELEMENTS(ev), &timeout);
  if (nevents < 0)
    {
      GAM_DEBUG(DEBUG_INFO, "kevent() failure: %s\n", g_strerror(errno));
      return TRUE;		/* keep source */
    }

  for (i = 0; i < nevents; i++)
    MONITOR(ev[i].udata)->handle_kevent(MONITOR(ev[i].udata), &ev[i]);
  
  return TRUE;			/* keep source */
}
Exemple #14
0
static void
gam_kqueue_sub_monitor_handle_directory_change (SubMonitor *smon,
						gboolean isdir)
{
  Monitor *mon = MONITOR(smon);
  GHashTable *filenames;

  filenames = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);

  if (isdir)			/* do not follow symbolic links */
    {
      GDir *dir;
      GError *err = NULL;

      dir = g_dir_open(mon->pathname, 0, &err);
      if (dir)
	{
	  const char *filename;
	  
	  while ((filename = g_dir_read_name(dir)))
	    {
	      g_hash_table_insert(filenames, g_strdup(filename), GINT_TO_POINTER(TRUE));

	      /* handle file creation */
	      if (! g_hash_table_lookup(smon->fmons->main, filename))
		{
		  FileMonitor *fmon;
		  FileMonitorFlags fmon_flags;
		  
		  fmon = gam_kqueue_file_monitor_new(smon, filename, &fmon_flags);
		  gam_kqueue_file_monitor_emit_event(fmon, GAMIN_EVENT_CREATED, fmon_flags);
		}
	    }
	  
	  g_dir_close(dir);
	}
      else
	{
	  GAM_DEBUG(DEBUG_INFO, "unable to open directory %s: %s\n", mon->pathname, err->message);
	  g_error_free(err);
	}
    }

  /*
   * Handle deleted files (they are also handled at the FileMonitor
   * level, but we must use whichever event comes first).
   */
  gam_kqueue_hash_table_foreach(smon->fmons, (GHFunc) gam_kqueue_sub_monitor_handle_directory_change_removal_cb, filenames);
  g_hash_table_destroy(filenames);
}
Exemple #15
0
dsk_err_t tele_seeksec(TELE_DSK_DRIVER *self, const DSK_GEOMETRY *geom,
		dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected,
		dsk_phead_t head_expected, dsk_psect_t sector, 
		size_t *request_len, size_t *sseclen)
{
	dsk_err_t err;
	int s;
	long pos;

	err = tele_seektrack(self, cylinder, head);

	for (s = 0; s < self->tele_trackhead.sectors; s++)
	{
		pos = ftell(self->tele_fp);
		err = tele_readsechead(self);	
		if (err) return err;
		MONITOR(("tele_seeksec: c%d h%d s%d at 0x%08lx (%d/%d)\n",
				self->tele_sechead.cylinder_id, 
				self->tele_sechead.head_id, 
				self->tele_sechead.sector_id, pos,
				s, self->tele_trackhead.sectors));
		if (self->tele_sechead.sector_id   == sector   &&
		    self->tele_sechead.cylinder_id == cylinder &&
		    self->tele_sechead.head_id     == head)
		{
			*sseclen = self->tele_sechead.sector_len;
/* Sector shorter than expected. Report a data error, and set
 * request_len to the actual size. */
			if (*sseclen < *request_len)
			{
				*request_len = *sseclen;
				err = DSK_ERR_DATAERR;
			}
/* Sector longer than expected. Report a data error but don't change 
 * request_len */
		        else if ((*sseclen) > (*request_len))
		        {
				err = DSK_ERR_DATAERR;
			}
			return err;
		}
		/* Skip over that sector and on to the next */
		err = tele_readsec(self, NULL);
	}
	return DSK_ERR_NOADDR;
}
Exemple #16
0
static SubMonitor *
gam_kqueue_sub_monitor_new (GamSubscription *sub)
{
  SubMonitor *smon;
  Monitor *mon;

  smon = g_new0(SubMonitor, 1);

  mon = MONITOR(smon);
  mon->handle_kevent = gam_kqueue_sub_monitor_handle_kevent;
  mon->pathname = g_strdup(gam_subscription_get_path(sub));
  mon->fd = -1;

  smon->isdir = gam_subscription_is_dir(sub);
  gam_kqueue_sub_monitor_init_fmons(smon);

  return smon;
}
Exemple #17
0
/**
 * Removes a subscription which was being monitored.
 *
 * @param sub a #GamSubscription to remove
 * @returns TRUE if removing the subscription succeeded, FALSE otherwise
 */
gboolean
gam_kqueue_remove_subscription (GamSubscription *sub)
{
  GHashTable *hash;
  SubMonitor *smon;

  hash = gam_subscription_is_dir(sub) ? dir_hash : file_hash;
  smon = g_hash_table_lookup(hash, gam_subscription_get_path(sub));

  if (! smon)
    return FALSE;

  smon->subs = g_list_remove_all(smon->subs, sub);
  if (! smon->subs)
    {
      g_hash_table_remove(hash, MONITOR(smon)->pathname);
      gam_kqueue_sub_monitor_free(smon);
    }

  gam_subscription_cancel(sub);

  return TRUE;
}
Exemple #18
0
static void
gam_kqueue_file_monitor_free (FileMonitor *fmon)
{
  gam_kqueue_monitor_free(MONITOR(fmon));
}
Exemple #19
0
static void
gam_kqueue_sub_monitor_enable_notification (SubMonitor *smon,
					    SubMonitorFlags flags)
{
  Monitor *mon = MONITOR(smon);
  gboolean exists;

  /* we first send CREATED or EXISTS/DELETED+ENDEXISTS events */

  if ((flags & SUB_MONITOR_WAS_MISSING) != 0)
    exists = TRUE;
  else
    {
      struct stat sb;

      exists = lstat(mon->pathname, &sb) >= 0;
      flags |= (exists && (sb.st_mode & S_IFDIR) != 0) ? MONITOR_ISDIR : MONITOR_ISNOTDIR;
    }

  if (exists)
    {
      GaminEventType gevent;

      gevent = (flags & SUB_MONITOR_WAS_MISSING) != 0 ? GAMIN_EVENT_CREATED : GAMIN_EVENT_EXISTS;
      gam_kqueue_sub_monitor_emit_event(smon, gevent, flags);

      if (smon->isdir && (flags & MONITOR_ISDIR) != 0)
	{
	  GDir *dir;
	  GError *err = NULL;
	  
	  dir = g_dir_open(mon->pathname, 0, &err);
	  if (dir)
	    {
	      const char *filename;
	      
	      while ((filename = g_dir_read_name(dir)))
		{
		  FileMonitor *fmon;
		  FileMonitorFlags fmon_flags;
		  
		  fmon = gam_kqueue_file_monitor_new(smon, filename, &fmon_flags);
		  gam_kqueue_file_monitor_emit_event(fmon, gevent, fmon_flags);
		}
	      
	      g_dir_close(dir);
	    }
	  else
	    {
	      GAM_DEBUG(DEBUG_INFO, "unable to open directory %s: %s\n", mon->pathname, err->message);
	      g_error_free(err);
	    }
	}

      if ((flags & SUB_MONITOR_WAS_MISSING) == 0)
	gam_kqueue_sub_monitor_emit_event(smon, GAMIN_EVENT_ENDEXISTS, flags);
    }
  else
    {
      gam_kqueue_sub_monitor_emit_event(smon, GAMIN_EVENT_DELETED, flags);
      gam_kqueue_sub_monitor_emit_event(smon, GAMIN_EVENT_ENDEXISTS, flags);

      return;
    }
    
  /* then we enable kqueue notification, falling back to poll if necessary */

  if (! gam_kqueue_monitor_enable_kqueue(mon))
    gam_kqueue_sub_monitor_set_unsupported(smon);
}
Exemple #20
0
XsiStatus pluginClock(void *instance) {
    MONITOR(instance)->clock();
    return XSI_STATUS_OK;
}
Exemple #21
0
XsiStatus pluginTerminate(void *instance) {
    delete MONITOR(instance);
    return XSI_STATUS_OK;
}
Exemple #22
0
/* We cache previously-encountered track addresses in self->tele_track_addr
 * to avoid doing a linear search every time a track is needed. */
static dsk_err_t tele_seektrack(TELE_DSK_DRIVER *self, dsk_pcyl_t cylinder,
		dsk_phead_t head)
{
	long startpos;
	int c, h, s;
	dsk_err_t err;

	h = head;
	c = cylinder;
	startpos = 0;
	MONITOR(("tele_seektrack: cylinder=%d head=%d\n", cylinder, head));

	do
	{
		MONITOR(("tele_seektrack: Trying c%d h%d\n", c, h));
		if (c < 100 && h < 2 && self->tele_track_addr[c][h] != 0)
		{
			MONITOR(("tele_seektrack: starting at c%d h%d\n", c, h));
			startpos = self->tele_track_addr[c][h];
		}
		if (h == 0)
		{
			h = 1;
			--c;
		}
		else
		{
			--h;
		}
	}
	while (startpos == 0 && c >= 0);

	if (startpos == 0)
	{
#ifndef WIN16
		fprintf(stderr, "drv_tele internal error: Cannot find cylinder 0 head 0\n");
#endif
		return DSK_ERR_CTRLR;
	}

	if (fseek(self->tele_fp, startpos, SEEK_SET))
		return DSK_ERR_SYSERR;

	do
	{
		tele_byte buf[4];
		startpos = ftell(self->tele_fp);
		err = tele_fread(self, buf, 4);
		if (err) 
		{
			return DSK_ERR_NOADDR;
		}
		self->tele_trackhead.sectors  = buf[0];
		self->tele_trackhead.cylinder = buf[1];
		self->tele_trackhead.head     = buf[2];
		self->tele_trackhead.crc      = buf[3];
		c = self->tele_trackhead.cylinder;
		h = self->tele_trackhead.head;
		MONITOR(("tele_seektrack: c%d h%d at 0x%08lx\n", c, h, startpos));
		if (c < 100 && h < 2 && self->tele_track_addr[c][h] == 0)
		{
			self->tele_track_addr[c][h] = startpos;
		}
		if ((dsk_pcyl_t)c == cylinder && (dsk_phead_t)h == head)
		{
			return DSK_ERR_OK;
		}
		for (s = 0; s < self->tele_trackhead.sectors; s++)
		{
			err = tele_readsechead(self);	
			if (err) return err;
			err = tele_readsec(self, NULL);
			if (err) return err;
		}

	}
	while(1);
/* Should never happen, but need to shut Pacific C up */
	return DSK_ERR_UNKNOWN;
}
Exemple #23
0
/* Read the sector described by tele_sechead */
static dsk_err_t tele_readsec(TELE_DSK_DRIVER *self, unsigned char *buf)
{
	int n, w, wleft, plen, ptype;
	dsk_err_t err;
	size_t len = self->tele_sechead.sector_len;
	tele_byte pattern[257];

	if (self->tele_sechead.syndrome & 0x30)	/* Nothing there */
	{
		if (buf) memset(buf, 0xF6, len);
		return DSK_ERR_OK;
	}
	switch(self->tele_sechead.encoding)
	{
		case 0:	/* Uncompressed */
			MONITOR(("tele_readsec @ 0x%08lx: Type 0 len %d\n",
				 ftell(self->tele_fp), len));
			return tele_fread(self, buf, len);
		case 1:	/* One pattern */
			MONITOR(("tele_readsec @ 0x%08lx: Type 1 len 4\n",
				 ftell(self->tele_fp)));
			err = tele_fread(self, pattern, 4);
			if (err) return err;

			if (buf) for (n = 0; n < (int)len; n+= 2)
			{
				buf[n]   = pattern[2];
				buf[n+1] = pattern[3];
			}
			return DSK_ERR_OK;
		case 2:	/* More than one pattern */
			w = 0;
			MONITOR(("tele_readsec @ 0x%08lx: Type 2 \n",
				 ftell(self->tele_fp)));
			while ((size_t)w < len)
			{
				wleft = len - w;
				err = tele_fread(self, pattern, 2);
				if (err) return err;
				ptype = pattern[0];
				plen = pattern[1];
			MONITOR(("tele_readsec @ 0x%08lx: Type 2 ptype=%d plen=%d\n",
				 ftell(self->tele_fp), ptype, plen));
				if (ptype == 0)
				{
					err = tele_fread(self, pattern, plen);
					if (err) return err;	
					if (plen > wleft) plen = wleft;
					if (buf) memcpy(buf + w, pattern, plen);
					w += plen;
					continue;
				}
				err = tele_fread(self, pattern, (1 << ptype));
				for (n = 0; n < plen; n++)
				{
					if (buf)
					{
/* Ensure the amount of data written does not exceed len */
						if ((1 << ptype) > wleft)
							memcpy(buf + w,
							  pattern,wleft);	
						else	memcpy(buf + w,
							  pattern, 1 << ptype);
					}
					w += (1 << ptype);	
					wleft -= (1 << ptype);
				}
			}	
			return DSK_ERR_OK;
		default:	
#ifndef WIN16
			fprintf(stderr, "Teledisk: Unsupported sector compression method %d!\n", self->tele_sechead.encoding);
#endif
			break;
	}
	return DSK_ERR_NOTIMPL;
}
Exemple #24
0
static void
gam_kqueue_file_monitor_emit_event (FileMonitor *fmon,
				    GaminEventType event,
				    FileMonitorFlags flags)
{
  Monitor *mon = MONITOR(fmon);
  struct stat sb;
  gboolean isdir;
  gboolean stat_done;
  gboolean stat_succeeded;
  
  if ((flags & MONITOR_ISDIR) == 0 && (flags & MONITOR_ISNOTDIR) == 0)
    {
      stat_done = TRUE;
      stat_succeeded = lstat(mon->pathname, &sb) >= 0;
      isdir = stat_succeeded && (sb.st_mode & S_IFDIR) != 0;
    }
  else
    {
      stat_done = FALSE;
      isdir = (flags & MONITOR_ISDIR) != 0;
    }
  
  gam_server_emit_event(mon->pathname, isdir, event, fmon->smon->subs, 1);

  switch (event)
    {
    case GAMIN_EVENT_DELETED:
    case GAMIN_EVENT_MOVED:
      if (mon->fd < 0)
	gam_kqueue_hash_table_remove(fmon->smon->unsupported_fmons, fmon);

      if ((flags & FILE_MONITOR_POSSIBLY_RECREATED) != 0)
	{
	  if (! stat_done)
	    stat_succeeded = lstat(mon->pathname, &sb) >= 0;

	  if (stat_succeeded)
	    {
	      FileMonitor *new_fmon;
	      FileMonitorFlags new_fmon_flags;
	      
	      /*
	       * The file exists again. It means that kqueue has
	       * aggregated a removal+creation into a single event. We
	       * must therefore create a new fmon and emit a
	       * GAMIN_EVENT_CREATED event, because
	       * gam_kqueue_sub_monitor_handle_directory_change() did
	       * not detect the removal+creation.
	       */

	      new_fmon = gam_kqueue_file_monitor_new(fmon->smon, fmon->filename, &new_fmon_flags);
	      gam_kqueue_file_monitor_emit_event(new_fmon, GAMIN_EVENT_CREATED, new_fmon_flags);

	      break;		/* do not remove the fmon we've just created */
	    }
	}
	
      gam_kqueue_hash_table_remove(fmon->smon->fmons, fmon);
      break;
    }
}