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; }
/** * 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; }
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); }
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); }
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); }
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; }
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); }
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); }
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); }
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; }
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)); }
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)); } }
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 */ }
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); }
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; }
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; }
/** * 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; }
static void gam_kqueue_file_monitor_free (FileMonitor *fmon) { gam_kqueue_monitor_free(MONITOR(fmon)); }
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); }
XsiStatus pluginClock(void *instance) { MONITOR(instance)->clock(); return XSI_STATUS_OK; }
XsiStatus pluginTerminate(void *instance) { delete MONITOR(instance); return XSI_STATUS_OK; }
/* 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; }
/* 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; }
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; } }