1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! Provides the Cuda API with its context functionality.
//!
//! A Coaster device can be understood as a synonym to Cuda's context.

use super::ffi::*;
use super::{Error, API};
use crate::frameworks::cuda::Device;
use std::ptr;

impl API {
    /// Creates a Cuda context.
    ///
    /// An Cuda context can only be created with one device. Contexts are used by the Cuda
    /// runtime for managing objects such as command-queues, memory, program and kernel objects
    /// and for executing kernels on one or more devices specified in the context.
    /// An Cuda context is a synonym to a Coaster device.
    pub fn create_context(device: Device) -> Result<CUcontext, Error> {
        unsafe { API::ffi_create_context(device.id_c()) }
    }

    /// Removes a created Cuda context from the device.
    ///
    /// Should be called when freeing a Cuda::Context to not trash up the Cuda device.
    pub fn destroy_context(context: CUcontext) -> Result<(), Error> {
        unsafe { API::ffi_destroy_context(context) }
    }

    /// Synchronize the CUDA context associated with the current CPU thread.
    ///
    /// Should be called when you want to make sure that previous asynchronous operations
    /// have been executed.
    pub fn synchronize_context() -> Result<(), Error> {
        unsafe { API::ffi_synchronize_context() }
    }

    unsafe fn ffi_create_context(dev: CUdevice) -> Result<CUcontext, Error> {
        let mut context: CUcontext = ptr::null_mut();
        match cuCtxCreate_v2(&mut context, CU_CTX_SCHED_BLOCKING_SYNC, dev) {
            CUresult::CUDA_SUCCESS => Ok(context),
            CUresult::CUDA_ERROR_DEINITIALIZED => {
                Err(Error::Deinitialized("CUDA got deinitialized."))
            }
            CUresult::CUDA_ERROR_NOT_INITIALIZED => {
                Err(Error::NotInitialized("CUDA is not initialized."))
            }
            CUresult::CUDA_ERROR_INVALID_CONTEXT => {
                Err(Error::InvalidContext("No valid context available."))
            }
            CUresult::CUDA_ERROR_INVALID_DEVICE => {
                Err(Error::InvalidValue("Invalid value for `device` provided."))
            }
            CUresult::CUDA_ERROR_INVALID_VALUE => {
                Err(Error::InvalidValue("Invalid value provided."))
            }
            CUresult::CUDA_ERROR_OUT_OF_MEMORY => {
                Err(Error::OutOfMemory("Device is out of memory."))
            }
            status @ CUresult::CUDA_ERROR_UNKNOWN => Err(Error::Unknown(
                "An unknown Error occured. Check the CUDA DRIVER API manual for more details.",
                status as i32 as u64,
            )),
            status => Err(Error::Unknown(
                "Unable to create Cuda context.",
                status as i32 as u64,
            )),
        }
    }

    unsafe fn ffi_destroy_context(ctx: CUcontext) -> Result<(), Error> {
        match cuCtxDestroy_v2(ctx) {
            CUresult::CUDA_SUCCESS => Ok(()),
            CUresult::CUDA_ERROR_DEINITIALIZED => {
                Err(Error::Deinitialized("CUDA got deinitialized."))
            }
            CUresult::CUDA_ERROR_NOT_INITIALIZED => {
                Err(Error::NotInitialized("CUDA is not initialized."))
            }
            CUresult::CUDA_ERROR_INVALID_CONTEXT => {
                Err(Error::InvalidContext("No valid context available."))
            }
            CUresult::CUDA_ERROR_INVALID_VALUE => {
                Err(Error::InvalidValue("Invalid value provided."))
            }
            status => Err(Error::Unknown(
                "Unable to destroy Cuda context.",
                status as i32 as u64,
            )),
        }
    }

    unsafe fn ffi_synchronize_context() -> Result<(), Error> {
        match cuCtxSynchronize() {
            CUresult::CUDA_SUCCESS => Ok(()),
            CUresult::CUDA_ERROR_DEINITIALIZED => {
                Err(Error::Deinitialized("CUDA got deinitialized."))
            }
            CUresult::CUDA_ERROR_NOT_INITIALIZED => {
                Err(Error::NotInitialized("CUDA is not initialized."))
            }
            CUresult::CUDA_ERROR_INVALID_CONTEXT => {
                Err(Error::InvalidContext("No valid context available."))
            }
            CUresult::CUDA_ERROR_INVALID_VALUE => {
                Err(Error::InvalidValue("Invalid value provided."))
            }
            status => Err(Error::Unknown(
                "Unable to synchronize CUDA context.",
                status as i32 as u64,
            )),
        }
    }
}