int main(int argc, char * argv[]) { setlocale(LC_ALL, ""); ab::ui::UiGameClientIpc ipc; QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); QApplication app(argc, argv); GameFieldView fieldView(ipc); std::thread network_client_thread(network_client, "localhost", 1234, std::ref(ipc)); std::thread ui_updater_thread([&]() { ab::ui::ConnectionState last_state = static_cast<ab::ui::ConnectionState>(-1); std::unique_lock<std::mutex> ipc_lock(ipc.mutex); while (true) { if (last_state != ipc.connection_state) { std::cerr << "state: " << ipc.connection_state << std::endl; last_state = ipc.connection_state; } QMetaObject::invokeMethod(&fieldView, "updateFieldView"); if (ipc.connection_state == ab::ui::ConnectionState::disconnected) { return; } ipc.cv.wait(ipc_lock); } }); fieldView.show(); app.exec(); ui_updater_thread.join(); network_client_thread.join(); return 0; }
/* * shm_lock_(check_) routines are called in the paths where the rw_mutex * is not necessarily held. */ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id); if (IS_ERR(ipcp)) return (struct shmid_kernel *)ipcp; return container_of(ipcp, struct shmid_kernel, shm_perm); }
/* * sem_lock_(check_) routines are called in the paths where the rw_mutex * is not held. */ static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id); if (IS_ERR(ipcp)) return (struct sem_array *)ipcp; return container_of(ipcp, struct sem_array, sem_perm); }
/* * msg_lock_(check_) routines are called in the paths where the rw_mutex * is not held. */ static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id); if (IS_ERR(ipcp)) return (struct msg_queue *)ipcp; return container_of(ipcp, struct msg_queue, q_perm); }
/* * ipc_finish() - * * Locks and destroys the semaphore set and message queue if called * in the daemonized queue runner. If force isn't given, it will * only do so if the archive queue is empty after locking the set * and draining the message queue. */ int ipc_finish(bool force) { if (ipc_creator) { if (!force) { /* * We are the creator of the semaphore set, so if this isn't * a force operation, we lock it first, poll the message queue * and check that we have an empty queue. */ if (ipc_lock() < 0) { fprintf(stderr, "semop() failed in ipc_finish(): %s\n", strerror(errno)); return -1; } if (ipc_poll(false) < 0) return -1; if (archive_queue_head != NULL) { if (ipc_unlock() < 0) { fprintf(stderr, "semop() failed in ipc_finish(): %s\n", strerror(errno)); return -1; } return 1; } } /* * At this point, we are either forced to stop or we have a lock * and the queue is empty. */ if (msgctl(msgid, IPC_RMID, NULL) < 0) { fprintf(stderr, "msgctl() failed in ipc_finish(): %s\n", strerror(errno)); semctl(semid, 0, IPC_RMID); return -1; } if (semctl(semid, 0, IPC_RMID) < 0) { fprintf(stderr, "semctl() failed in ipc_finish(): %s\n", strerror(errno)); return -1; } } return 0; }
/* * semexit - Called by exit() to clean up on process exit. */ void semexit(proc_t *pp) { avl_tree_t *tree; struct sem_undo *undo; void *cookie = NULL; mutex_enter(&pp->p_lock); tree = pp->p_semacct; pp->p_semacct = NULL; mutex_exit(&pp->p_lock); while (undo = avl_destroy_nodes(tree, &cookie)) { ksemid_t *sp = undo->un_sp; size_t size = SEM_UNDOSZ(sp->sem_nsems); int i; (void) ipc_lock(sem_svc, sp->sem_perm.ipc_id); if (!IPC_FREE(&sp->sem_perm)) { for (i = 0; i < sp->sem_nsems; i++) { int adj = undo->un_aoe[i]; if (adj) { struct sem *semp = &sp->sem_base[i]; int v = (int)semp->semval + adj; if (v < 0 || v > USHRT_MAX) continue; semp->semval = (ushort_t)v; if (v == 0 && semp->semzcnt) cv_broadcast(&semp->semzcnt_cv); if (adj > 0 && semp->semncnt) cv_broadcast(&semp->semncnt_cv); } } list_remove(&sp->sem_undos, undo); } ipc_rele(sem_svc, (kipc_perm_t *)sp); kmem_free(undo, size); } avl_destroy(tree); kmem_free(tree, sizeof (avl_tree_t)); }
/* * ipc_send_code() - * * Support function for ipc_send_term() and ipc_send_resume(). */ static int ipc_send_code(char *archive_dir, int code) { struct { long mtype; char mtext[1]; } msg; if (ipc_generate_keys(archive_dir) < 0) return -1; if ((semid = semget(semkey, 0, 0)) < 0) { if (!opt_quiet) fprintf(stderr, "no logshipper daemon running\n"); return 2; } if (ipc_lock() < 0) return -1; if ((msgid = msgget(msgkey, 0)) < 0) { fprintf(stderr, "msgget() failed in ipc_send_code(): %s\n", strerror(errno)); ipc_unlock(); return -1; } msg.mtype = (long)code; if (msgsnd(msgid, &msg, 0, 0) < 0) { fprintf(stderr, "msgsnd() failed in ipc_send_code(): %s\n", strerror(errno)); ipc_unlock(); return -1; } return ipc_unlock(); }
void GameFieldView::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter qp(this); qp.setRenderHint(QPainter::Antialiasing, true); std::unique_lock<std::mutex> ipc_lock(ipc.mutex); double field_size = std::min(width() - 2, height() - 2); double field_dx = 1 + (width() - 2 - field_size) / 2; double field_dy = 1 + (height() - 2 - field_size) / 2; double field_to_px_coef = field_size / ipc.current_field.radius; QRectF r = QRectF(field_dx, field_dy, field_size, field_size); QBrush fieldBrush(QColor(200, 150, 150)); qp.setBrush(fieldBrush); qp.drawEllipse(r); { std::ostringstream fmt_stream; fmt_stream << "state: "; switch (ipc.connection_state) { case ab::ui::ConnectionState::connecting: fmt_stream << "connecting"; break; case ab::ui::ConnectionState::connected: fmt_stream << "connected"; break; case ab::ui::ConnectionState::disconnected: fmt_stream << "disconnected"; break; default: break; } fmt_stream << ", tick: " << ipc.field_counter; qp.drawText(QRect(0, 0, width(), height()), QString(fmt_stream.str().c_str())); } QBrush playerBrush(QColor(120, 150, 200)); QPen velocity_pen(QColor(50, 200, 60)); velocity_pen.setWidth(5); qp.setBrush(playerBrush); for (const ab::Player& player: ipc.current_field.players) { QRectF playerRect = QRectF(field_dx + (player.center.x - player.radius) * field_to_px_coef, field_dy + (player.center.y - player.radius) * field_to_px_coef, 2 * player.radius * field_to_px_coef, 2 * player.radius * field_to_px_coef); qp.drawEllipse(playerRect); qp.save(); qp.setPen(velocity_pen); qp.drawLine(field_dx + player.center.x * field_to_px_coef, field_dy + player.center.y * field_to_px_coef, field_dx + (player.center.x + player.velocity.x) * field_to_px_coef, field_dy + (player.center.y + player.velocity.y) * field_to_px_coef); qp.restore(); { std::ostringstream fmt_stream; fmt_stream << player.id; qp.drawText(playerRect, Qt::AlignCenter, QString(fmt_stream.str().c_str())); } } QBrush coinBrush(QColor(220, 240, 150)); qp.setBrush(coinBrush); for (const ab::Coin& coin: ipc.current_field.coins) { QRectF coinRect = QRectF(field_dx + (coin.center.x - coin.radius) * field_to_px_coef, field_dy + (coin.center.y - coin.radius) * field_to_px_coef, 2 * coin.radius * field_to_px_coef, 2 * coin.radius * field_to_px_coef); qp.drawEllipse(coinRect); } }
/* * ipc_init() - * * Called to setup or connect to the semaphore set and message queue. */ int ipc_init(char *archive_dir) { struct sembuf sops[2]; if (ipc_generate_keys(archive_dir) < 0) return -1; /* * We eventually have to start over again in case * the existing daemon destroys the semaphore set * after we attached and before we can lock it. */ while (true) { /* * Create or attach to the semaphore set */ semid = semget(semkey, 3, 0700 | IPC_CREAT); if (semid < 0) { fprintf(stderr, "cannot create or attache to semaphore set\n" "semget(): %s\n", strerror(errno)); return -1; } /* * We now do two initial operations with NOWAIT: * wait for #1 =0 * inc sem #1 +1 * We never again touch semaphore #1, so this either succeeds, meaning * that we created the set and hold the current lock. Or it fails with * EAGAIN, meaning we attached to an existing set. Or it fails with * EIDRM, meaning the set was destroyed. */ sops[0].sem_num = 1; sops[0].sem_op = 0; sops[0].sem_flg = IPC_NOWAIT; sops[1].sem_num = 1; sops[1].sem_op = 1; sops[1].sem_flg = 0; if (semop(semid, sops, 2) < 0) { if (errno == EIDRM) continue; if (errno != EAGAIN) { fprintf(stderr, "semop failed in ipc_init(): %s", strerror(errno)); return -1; } /* * Grab the lock on semaphore #0 */ if (ipc_lock() < 0) { /* * Since theres a gap between attaching and locking, the * set could have been destroyed. In that case, start over. */ if (errno == EIDRM) continue; fprintf(stderr, "semop() failed in ipc_init(): %s\n", strerror(errno)); return -1; } ipc_creator = 0; } else { /* * Initial semop succeeded - we are the creator of this set. */ ipc_creator = 1; signal(SIGINT, ipc_sighandler); signal(SIGTERM, ipc_sighandler); signal(SIGPIPE, ipc_sighandler); } break; } /* * At this point we have the semaphore set and it is locked. */ msgid = msgget(msgkey, 0700 | IPC_CREAT); if (msgid < 0) { fprintf(stderr, "msgget() failed in ipc_init(): %s\n", strerror(errno)); if (ipc_creator) { if (semctl(semid, 0, IPC_RMID) < 0) fprintf(stderr, "semctl() failed in ipc_init(): %s\n", strerror(errno)); } return -1; } return ipc_creator; }
struct sem_array *sem_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id); return container_of(ipcp, struct sem_array, sem_perm); }