root/trunk/libffado/src/rme/rme_shm.cpp

Revision 2803, 4.7 kB (checked in by jwoithe, 3 years ago)

Cosmetic: capitalise "L" in "Linux".

"Linux" is a proper noun so it should start with a capital letter. These
changes are almost all within comments.

This patch was originally proposed by pander on the ffado-devel mailing
list. It has been expanded to cover all similar cases to maintain
consistency throughout the source tree.

Line 
1 /*
2  * Copyright (C) 2009 by Jonathan Woithe
3  *
4  * This file is part of FFADO
5  * FFADO = Free FireWire (pro-)audio drivers for Linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 /*
25  * This file implements a simple interface to a shared memory object used
26  * to share device configuration between FFADO components.  This is required
27  * because a significant amount of device information is not available for
28  * reading from the device itself.
29  *
30  * The idea is that each RME FFADO process will call rme_shm_open() to
31  * obtain a pointer to shared memory containing the structure of interest.
32  * If no process has yet created the shared object it will be created at
33  * this point; otherwise the existing object will be used.  Each new process
34  * to use the object increments a reference count.
35  *
36  * On exit, processes using this shared object will call rme_shm_close().
37  * The reference counter is decremented and if it becomes zero the shared
38  * object will be unlinked.  This way, so long as at least one RME process
39  * is active (which doesn't have to be the process which created the object
40  * initially) the device's configuration will be persistent.
41  */
42
43 #define RME_SHM_NAME  "/ffado:rme_shm-"
44 #define RME_SHM_SIZE  sizeof(rme_shm_t)
45
46 #define RME_SHM_LOCKNAME "/ffado:rme_shm_lock"
47
48 #include <unistd.h>
49 #include <errno.h>
50 #include <string>
51 #include <stdio.h>
52 #include <sys/types.h>
53 #include <sys/mman.h>
54 #include <fcntl.h>
55
56 #include "rme_shm.h"
57
58 static signed int rme_shm_lock_for_setup(void) {
59 signed lockfd;
60
61     do {
62         // The check for existance and shm creation are atomic so it's safe
63         // to use this as the basis for a global lock.
64         lockfd = shm_open(RME_SHM_LOCKNAME, O_RDWR | O_CREAT | O_EXCL, 0644);
65         if (lockfd < 0)
66             usleep(10000);
67     } while (lockfd < 0);
68
69     return lockfd;
70 }
71
72 static void rme_shm_unlock_for_setup(signed int lockfd) {
73     close(lockfd);
74     shm_unlink(RME_SHM_LOCKNAME);
75 }
76
77 void rme_shm_lock(rme_shm_t *shm_data) {
78     pthread_mutex_lock(&shm_data->lock);
79 }
80
81 void rme_shm_unlock(rme_shm_t *shm_data) {
82     pthread_mutex_unlock(&shm_data->lock);
83 }
84
85 signed int rme_shm_open(std::string id, rme_shm_t **shm_data) {
86
87     std::string shm_name;
88     signed int shmfd, lockfd;
89     rme_shm_t *data;
90     signed int created = 0;
91
92     if (shm_data == NULL) {
93         return RSO_ERROR;
94     }
95     *shm_data = NULL;
96
97     lockfd = rme_shm_lock_for_setup();
98
99     shm_name = std::string(RME_SHM_NAME);
100     shm_name.append(id);
101
102     shmfd = shm_open(shm_name.c_str(), O_RDWR, 0644);
103     if (shmfd < 0) {
104         if (errno == ENOENT) {
105             shmfd = shm_open(shm_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0644);
106             if (shmfd < 0)
107                 return RSO_ERR_SHM;
108             else {
109                 ftruncate(shmfd, RME_SHM_SIZE);
110                 created = 1;
111             }
112         } else
113             return RSO_ERR_SHM;
114     }
115
116     data = (rme_shm_t *)mmap(NULL, RME_SHM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
117     close(shmfd);
118
119     if (data == MAP_FAILED)
120         return RSO_ERR_MMAP;
121
122     if (created) {
123         pthread_mutex_init(&data->lock, NULL);
124         snprintf(data->shm_name, sizeof(data->shm_name), "%s", shm_name.c_str());
125     }
126
127     rme_shm_lock(data);
128     data->ref_count++;
129     rme_shm_unlock(data);
130
131     rme_shm_unlock_for_setup(lockfd);
132
133     *shm_data = data;
134     return created?RSO_OPEN_CREATED:RSO_OPEN_ATTACHED;
135 }
136
137 signed int rme_shm_close(rme_shm_t *shm_data) {
138
139     std::string shm_name = std::string(shm_data->shm_name);
140     signed int unlink = 0;
141     signed int lockfd;
142
143     lockfd = rme_shm_lock_for_setup();
144
145     rme_shm_lock(shm_data);
146     shm_data->ref_count--;
147     unlink = (shm_data->ref_count == 0);
148     rme_shm_unlock(shm_data);
149
150     if (unlink) {
151         // This is safe: if the reference count is zero there can't be any
152         // other process using the lock at this point.
153         pthread_mutex_destroy(&shm_data->lock);
154     }
155
156     munmap(shm_data, RME_SHM_SIZE);
157
158     if (unlink)
159         shm_unlink(shm_name.c_str());
160
161     rme_shm_unlock_for_setup(lockfd);
162
163     return unlink?RSO_CLOSE_DELETE:RSO_CLOSE;
164 }
Note: See TracBrowser for help on using the browser.