+ struct callback_data cbd = {.handler = f};
+ int ret;
+ void *query_sma;
+
+ assert(query->data && query->size);
+ ret = shm_new(query->size);
+ if (ret < 0)
+ return ret;
+ cbd.query_shmid = ret;
+ cbd.query_size = query->size;
+ ret = shm_attach(cbd.query_shmid, ATTACH_RW, &query_sma);
+ if (ret < 0)
+ goto out;
+ memcpy(query_sma, query->data, query->size);
+ ret = shm_detach(query_sma);
+ if (ret < 0)
+ goto out;
+ /* prevent other children from interacting */
+ mutex_lock(child_mutex);
+ /* prevent parent from messing with shm_callback_data. */
+ mutex_lock(callback_mutex);
+ /* all three mutexes are locked, set parameters for callback */
+ *shm_callback_data = cbd;
+ /* unblock parent */
+ mutex_unlock(callback_mutex);
+ kill(getppid(), SIGUSR1); /* wake up parent */
+ /*
+ * At this time only the parent can run. It will execute our callback
+ * and unlock the result_mutex when ready to indicate that the child
+ * may use the result. So let's sleep on this mutex.
+ */
+ mutex_lock(result_mutex);
+ /* No need to aquire the callback mutex again */
+ ret = shm_callback_data->sma_ret;
+ if (ret < 0) /* sma problem, callback might not have been executed */
+ goto unlock_child_mutex;
+ if (shm_callback_data->result_shmid >= 0) { /* parent provided a result */
+ void *sma;
+ ret = shm_attach(shm_callback_data->result_shmid, ATTACH_RO,
+ &sma);
+ if (ret >= 0) {
+ if (result) { /* copy result */
+ result->size = shm_callback_data->result_size;
+ result->data = para_malloc(result->size);
+ memcpy(result->data, sma, result->size);
+ ret = shm_detach(sma);
+ if (ret < 0)
+ PARA_ERROR_LOG("can not detach result\n");
+ } else
+ PARA_WARNING_LOG("no result pointer\n");
+ } else
+ PARA_ERROR_LOG("attach result failed: %d\n", ret);
+ if (shm_destroy(shm_callback_data->result_shmid) < 0)
+ PARA_ERROR_LOG("destroy result failed\n");
+ } else { /* no result from callback */
+ if (result) {
+ PARA_WARNING_LOG("callback has no result\n");
+ result->data = NULL;
+ result->size = 0;
+ }
+ }
+ ret = shm_callback_data->callback_ret;
+unlock_child_mutex:
+ /* give other children a chance */
+ mutex_unlock(child_mutex);
+out:
+ if (shm_destroy(cbd.query_shmid) < 0)
+ PARA_ERROR_LOG("%s\n", "shm destroy error");
+ PARA_DEBUG_LOG("callback_ret: %d\n", ret);
+ return ret;