#include #include #include #define OBJECT_QUEUE 0x1337 void queue_close(vfs_fd_t *inode) { // TODO (void)inode; } int queue_get_entries(struct queue_list *list, struct queue_entry *events, int num_events) { int rc = 0; for (int i = 0; rc < num_events; i++) { struct queue_entry *entry; int end; if (!relist_get(&list->entries, i, (void **)&entry, &end)) { if (end) { break; } continue; } if (0 == entry->listen) { continue; } vfs_fd_t *ptr = get_vfs_fd(entry->fd, list->process); if (!ptr) { continue; } int should_add = 0; if (QUEUE_WAIT_READ & entry->listen) { if (ptr->inode->_has_data) { if (ptr->inode->_has_data(ptr->inode)) { should_add = 1; } } } if (QUEUE_WAIT_WRITE & entry->listen) { if (ptr->inode->_can_write) { if (ptr->inode->_can_write(ptr->inode)) { should_add = 1; } } } if (QUEUE_WAIT_CLOSE & entry->listen) { if (ptr->inode->_is_open) { if (!ptr->inode->_is_open(ptr->inode)) { should_add = 1; } } } if (should_add) { if (events) { memcpy(events + rc, entry, sizeof(struct queue_entry)); } rc++; } } return rc; } int queue_has_data(vfs_inode_t *inode) { if (1 == queue_get_entries(inode->internal_object, NULL, 1)) { return 1; } return 0; } int queue_create(void) { struct queue_list *list = kmalloc(sizeof(struct queue_list)); assert(list); relist_init(&list->entries); list->process = current_task; vfs_inode_t *inode = vfs_create_inode( 0, 0, queue_has_data, NULL, 1 /*is_open*/, OBJECT_QUEUE, list /*internal_object*/, 0, NULL, NULL, NULL, NULL, queue_close, NULL, NULL /*get_vm_object*/, NULL, NULL, NULL /*connect*/); assert(inode); return vfs_create_fd(0, 0, 0, inode, NULL); } int queue_mod_entries(int fd, int flag, struct queue_entry *entries, int num_entries) { vfs_fd_t *fd_ptr = get_vfs_fd(fd, NULL); assert(fd_ptr); assert(OBJECT_QUEUE == fd_ptr->inode->internal_object_type); struct queue_list *list = fd_ptr->inode->internal_object; if (QUEUE_MOD_ADD == flag) { int i = 0; for (; i < num_entries; i++) { struct queue_entry *copy = kmalloc(sizeof(struct queue_entry)); if (!copy) { break; } memcpy(copy, entries + i, sizeof(struct queue_entry)); if (!relist_add(&list->entries, copy, NULL)) { kfree(copy); break; } } return i; } else if (QUEUE_MOD_CHANGE == flag) { int changes = 0; for (int i = 0; changes < num_entries; i++) { struct queue_entry *entry; int end; if (!relist_get(&list->entries, i, (void **)&entry, &end)) { if (end) { break; } continue; } for (int j = 0; j < num_entries; j++) { if (entry->fd == entries[j].fd) { entry->listen = entries[j].listen; entry->data_type = entries[j].data_type; entry->data = entries[j].data; changes++; break; } } } return changes; } else if (QUEUE_MOD_DELETE == flag) { int changes = 0; for (int i = 0; changes < num_entries; i++) { struct queue_entry *entry; int end; if (!relist_get(&list->entries, i, (void **)&entry, &end)) { if (end) { break; } continue; } for (int j = 0; j < num_entries; j++) { if (entry->fd == entries[j].fd) { assert(relist_remove(&list->entries, i)); kfree(entry); break; } } } return changes; } else { assert(0); } return 0; } int queue_wait(int fd, struct queue_entry *events, int num_events) { vfs_fd_t *fd_ptr = get_vfs_fd(fd, NULL); assert(fd_ptr); assert(OBJECT_QUEUE == fd_ptr->inode->internal_object_type); struct queue_list *list = fd_ptr->inode->internal_object; int rc = queue_get_entries(list, events, num_events); if (0 == rc) { list_add(¤t_task->read_list, fd_ptr->inode, NULL); switch_task(); list_reset(¤t_task->read_list); rc = queue_get_entries(list, events, num_events); } return rc; }